FFmpeg-avcodec_receive_frame在接收帧之前不会接收所有帧并丢失帧

时间:2019-03-22 02:51:20

标签: ffmpeg

vcodec_receive_frame函数没有收到其余的帧。我测试了视频总共有132帧,并且只收到了125帧在视频结尾处丢失了7帧。如何找回丢失的镜框?

但是发生了一些奇怪的事情。如您所见,我的MyDecode::receiveFrame()函数的输出。首先执行块if (ret != 0){}中的代码,但是丢失的帧位于视频的末尾。那么他们怎么会首先出来呢?造成这种情况的原因是什么?

MyDecode.cpp

AVFrame* MyDecode::receiveFrame()
{
    mux.lock();
    if (!codecCtx) {
        mux.unlock();
        return 0;
    }
    AVFrame* frame = av_frame_alloc();
    int ret = avcodec_receive_frame(codecCtx, frame);
    mux.unlock();
    if (ret != 0)
    {
        static int lost_frames = 1;
        std::cout << "Lost frames: " << lost_frames << std::endl;
        lost_frames += 1;
        av_frame_free(&frame);
        return nullptr;
    }
    std::cout << "Received frames: " << received_frame_num << std::endl;
    received_frame_num += 1;
    return frame;
}

bool MyDecode::sendPacket(AVPacket* packet)
{
    if (!packet || !packet->data || packet->size == 0)
        return false;
    mux.lock();
    if (!codecCtx) {
        mux.unlock();
        return false;
    }
    int ret = avcodec_send_packet(codecCtx, packet);
    mux.unlock();
    av_packet_free(&packet);
    if (ret != 0) {
        return false;
    }
    return true;
}

控制台输出

Total frames: 132
Lost frames: 1
Lost frames: 2
Lost frames: 3
Lost frames: 4
Lost frames: 5
Lost frames: 6
Lost frames: 7
Received frames: 1
Received frames: 2
Received frames: 3
................
Received frames: 125

更新:

MyDemux.cpp

AVPacket* MyDemux::readFrame()
{
    mux.lock();
    if (!formatCtx) {
        std::cout << "formaetCtx is null" << std::endl;
        mux.unlock();
        return nullptr;
    }
    AVPacket* packet = av_packet_alloc();
    if (!packet) {
        std::cout << "packet is null" << std::endl;
        mux.unlock();
        return nullptr;
    }

    int ret = av_read_frame(formatCtx, packet);
    if (ret != 0) {
        while (true) {
            av_read_frame(formatCtx, nullptr);
        }
        mux.unlock();
        av_packet_free(&packet);
        av_packet_unref(packet);
        return nullptr;
    }
    media_type = packet->stream_index;
    mux.unlock();
    return packet;
}

main.cpp

while (true) {
            AVPacket* pkt = demux.readFrame();
            if (demux.get_media_type() == 0) {
                AVFrame* frame = video_decode.receiveFrame();
                videoWidget->paintFrame(frame);
            }
            else if (demux.get_media_type() == 1) {
            }
            if (!pkt) {
                std::cout << "to break" << std::endl;
                break;
            }
        }

1 个答案:

答案 0 :(得分:4)

您必须发送NULL pkts到解码器以耗尽所有未决帧。

来自avcodec.h

  

流结束情况。这些需要“冲洗”(又称排水)   编解码器,因为编解码器可能会缓冲多个帧或数据包   内部出于性能考虑或出于必要(考虑B帧)。
  处理方法如下:
    -将无效值发送到avcodec_send_packet()(解码),而不是有效输入       或avcodec_send_frame()(编码)函数。这将进入排水       模式。
    -调用avcodec_receive_frame()(解码)或avcodec_receive_packet()       (编码)循环进行,直到返回AVERROR_EOF。该功能将       除非您忘记进入排水模式,否则不会返回AVERROR(EAGAIN)。     -在重新恢复解码之前,必须使用以下命令重置编解码器:       avcodec_flush_buffers()。