4
votes

I use ffmpeg's MPEG4 decoder. The decoder has CODEC_CAP_DELAY capability among others. It means the decoder will give me decoded frames with latency of 1 frame.

I have a set of MPEG4 (I- & P- )frames from AVI file and feed ffmpeg decoder with these frames. For the very first I-frame decoder gives me nothing, but decodes the frames successfully. I can force the decoder to get the decoded frame with the second call of avcodec_decode_video2 and providing nulls (flush it), but if I do so for each frame I get artifacts for the first group of pictures (e.g. second decoded P-frame is of gray color).

If I do not force ffmpeg decoder to give me decoded frame right now, then it works flawlessly and without artifacts.

Question: But is it possible to get decoded frame without giving the decoder next frame and without artifacts?

Small example of how decoding is implemented for each frame:

        // decode
        int got_frame = 0;
        int err = 0;
        int tries = 5;
        do
        {
            err = avcodec_decode_video2(m_CodecContext, m_Frame, &got_frame, &m_Packet);
            /* some codecs, such as MPEG, transmit the I and P frame with a
            latency of one frame. You must do the following to have a
            chance to get the last frame of the video */
            m_Packet.data = NULL;
            m_Packet.size = 0;
            --tries;
        }
        while (err >= 0 && got_frame == 0 && tries > 0);

But as I said that gave me artifacts for the first gop.

2

2 Answers

6
votes

Use the "-flags +low_delay" option (or in code, set AVCodecContext.flags |= CODEC_FLAG_LOW_DELAY).

0
votes

I tested several options and "-flags low_delay" and "-probesize 32" is more important than others. bellow code worked for me.

AVDictionary* avDic = nullptr;
av_dict_set(&avDic, "flags", "low_delay", 0);
av_dict_set(&avDic, "probesize", "32", 0);

const int errorCode = avformat_open_input(&pFormatCtx, mUrl.c_str(), nullptr, &avDic);