FFmpeg — avcodec_receive_frame возвращает ошибку AVERROR (EAGAIN)

#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 не вернет допустимый кадр.