#ffmpeg #decoding
#ffmpeg #декодирование
Вопрос:
Я использую виджет QOpenGL для рисования фреймов. Тем не менее, я изо всех сил пытаюсь получить кадры с помощью avcodec_receive_frame
. Оно завершилось в пределах блока else if (ret == AVERROR(EAGAIN))
и вернуло -11. Я понятия не имею, из-за чего это произошло. Также я проверил, что кодеки были в порядке, поэтому я предполагаю, что проблема была вызвана не кодеками.
MyDemux.cpp
AVPacket* MyDemux::allocatePacket()
{
AVPacket* packet = av_packet_alloc();
return packet;
}
AVFrame* MyDemux::allocateFrame()
{
AVFrame* frame = av_frame_alloc();
return frame;
}
int MyDemux::readFrame(AVPacket* packet)
{
mux.lock();
if (!formatCtx) {
std::cout << "formaetCtx is null" << std::endl;
mux.unlock();
return -1;
}
int ret = av_read_frame(formatCtx, packet);
if (ret == AVERROR_EOF) {
return -2;
}
if (ret != 0) {
mux.unlock();
av_packet_free(amp;packet);
return -1;
}
media_type = packet->stream_index;
mux.unlock();
return 0;
}
MyDecode.cpp
void MyDecode::decode(AVFrame* frame, AVPacket* packet)
{
int ret;
ret = avcodec_send_packet(codecCtx, packet); // this returned 0
while (ret == 0) {
ret = avcodec_receive_frame(codecCtx, frame); // this returned -11
if (ret == AVERROR(EINVAL)) {
std::cout << "codec issue" << std::endl;
av_frame_free(amp;frame);
return;
}
else if (ret == AVERROR(EAGAIN)) { // program ends here
std::cout << "output is not available this state" << std::endl;
av_frame_free(amp;frame);
return;
}
else if (ret == AVERROR(EINVAL)) {
std::cout << "no more frames" << std::endl;
av_frame_free(amp;frame);
return;
}
}
}
main.cpp
class MyThread : public QThread
{
public:
MyDemux demux;
MyDecode video_decode;
myDecode audio_decode;
MyVideoWidget* videoWidget;
AVPacket* packet;
AVFrame* frame;
void initThread()
{
char* url = "demo.mp4";
demux.openFile(url);
video_decode.openCodec(demux.copy_video_codec_par());
audio_decode.openCodec(demux.copy_audio_codec_par());
packet = demux.allocatePacket();
frame = demux.allocateFrame();
}
void run()
{
while (demux.readFrame(packet) != -2) {
if (demux.get_media_type() == 0) {
video_decode.decode(frame, packet);
videoWidget->paintFrame(frame);
}
else if (demux.get_media_type() == 1) {
}
}
video_decode.decode(frame, nullptr);
demux.clear();
demux.close();
}
};
Ответ №1:
Когда вы вызываете avcodec_receive_frame
и получаете EAGAIN
ошибку, это означает, что ваш декодер не получает достаточно данных для декодирования (например, вы отправляете B-кадр в видео). Поэтому каждый раз, когда вы получаете эту ошибку, вы должны игнорировать ее и переходить к следующему avcodec_send_packet
Ответ №2:
Существует задержка между отправкой и приемом кадра. Когда receive вернет EAGAIN, вы должны вызвать send со следующим закодированным кадром, затем снова вызвать receive.
Комментарии:
1. Извините, я не совсем уверен, что вы имеете в виду. Пакет avcodec_send_packet предшествует avcodec_receive_frame. А также они реализованы в цикле while в основном методе
2. Вы должны продолжать вызывать avcodec_send_frame с новыми данными, пока avcode_receive_frame не вернет допустимый кадр.