Alvein
Alvein

Reputation: 207

Slightly different number of total frames between my program (using libav) and ffprobe

For learning purposes, I made a routine that decodes each frame for each stream inside a given container.

I noticed that for some videos, the amount of frames returned by my code differs the one calculated by the tool ffprobe (which comes with ffmpeg).

I'm using ffprobe like this:

ffprobe <media file> -v error -select_streams v:0 -count_frames -show_entries stream=nb_read_frames

Replacing "v:0" with "a:0" for audio, etc.

And this is my source code:

void showFrames(char *szFilename) {
    int               iError;
    char              szError[AV_ERROR_MAX_STRING_SIZE];
    AVFormatContext   *fcFormatCtx;
    AVCodec           *cdCodec;
    AVCodecParameters *cdpCodecParams;
    AVCodecContext    *ccCodecCtx;
    AVPacket          *pkPacket;
    AVFrame           *frFrame;
    fcFormatCtx=avformat_alloc_context();
    iError=avformat_open_input(&fcFormatCtx,szFilename,NULL,NULL);
    if(0>iError) {
        av_strerror(iError,szError,sizeof(szError));
        fprintf(stderr,"avformat_open_input() failed: %s\n",szError);
        return;
    }
    iError=avformat_find_stream_info(fcFormatCtx,NULL);
    if(0>iError) {
        av_strerror(iError,szError,sizeof(szError));
        fprintf(stderr,"avformat_find_stream_info() failed: %s\n",szError);
        avformat_close_input(&fcFormatCtx);
        return;
    }
    for(uint uiSt=0;uiSt<fcFormatCtx->nb_streams;uiSt++) {
        cdpCodecParams=fcFormatCtx->streams[uiSt]->codecpar;
        cdCodec=avcodec_find_decoder(cdpCodecParams->codec_id);
        if(NULL==cdCodec) {
            fprintf(stderr,"no codec found for stream %u\n",uiSt);
            continue;
        }
        fprintf(stderr,"stream %u\n",uiSt);
        if(AVMEDIA_TYPE_VIDEO==cdpCodecParams->codec_type)
            fprintf(stderr,"video codec id=%d name='%s'\n",
                    cdCodec->id,cdCodec->long_name);
        else if(AVMEDIA_TYPE_AUDIO==cdpCodecParams->codec_type)
            fprintf(stderr,"audio codec id=%d name='%s'\n",
                    cdCodec->id,cdCodec->long_name);
        else {
            fprintf(stderr,"unsupported codec id=%d name='%s'\n",
                    cdCodec->id,cdCodec->long_name);
            continue;
        }
        ccCodecCtx=avcodec_alloc_context3(cdCodec);
        avcodec_parameters_to_context(ccCodecCtx,cdpCodecParams);
        iError=avcodec_open2(ccCodecCtx,cdCodec,NULL);
        if(0>iError) {
            av_strerror(iError,szError,sizeof(szError));
            fprintf(stderr,"avcodec_open2() failed: %s\n",szError);
            avcodec_free_context(&ccCodecCtx);
            continue;
        }
        pkPacket=av_packet_alloc();
        frFrame=av_frame_alloc();
        av_seek_frame(fcFormatCtx,uiSt,0,AVSEEK_FLAG_FRAME);
        while(0==av_read_frame(fcFormatCtx,pkPacket)) {
            if(uiSt==pkPacket->stream_index) {
                iError=avcodec_send_packet(ccCodecCtx,pkPacket);
                if(0>iError) {
                    av_strerror(iError,szError,sizeof(szError));
                    fprintf(stderr,"avcodec_send_packet() failed: %s\n",szError);
                    break;
                }
                while(true) {
                    iError=avcodec_receive_frame(ccCodecCtx,frFrame);
                    if(0>iError)
                        break;
                    fprintf(stderr,"stream %u, frame %d\n",
                            uiSt,ccCodecCtx->frame_number);
                    av_frame_unref(frFrame);
                }
                if(AVERROR(EAGAIN)!=iError&&AVERROR_EOF!=iError) {
                    av_strerror(iError,szError,sizeof(szError));
                    fprintf(stderr,"avcodec_receive_frame() failed: %s\n",szError);
                    break;
                }
            }
            av_packet_unref(pkPacket);
        }
        av_packet_free(&pkPacket);
        av_frame_free(&frFrame);
        avcodec_free_context(&ccCodecCtx);
    }
    avformat_close_input(&fcFormatCtx);
}

It's pretty much self contained but you may ignore all the initializations and go directly to the while after the call to av_seek_frame(). This is where the actual frames are being read.

BTW, I'm using av_seek_frame() because this program goes stream by stream, separating the frames, so I need to rewind with every stream found.

Anyway, I've tested the previous code with the following files:

#1. sample-10s.mp4 from https://samplelib.com/sample-mp4.html ...

My program: 301 video frames; 440 audio frames

ffprobe: 303 video frames; 440 audio frames

#2. production ID_3997798.mp4 from https://www.pexels.com/video/hands-hand-table-colorful-3997798/ ...

My program: 736 video frames; no audio frames

ffprobe: 738 video frames; no audio frames

I found more videos with this difference, but it ONLY happens in the video streams.

Is there something I am forgetting? There seem to be always 2 frames behind what ffprobe shows.

Thank you.

Upvotes: 3

Views: 258

Answers (0)

Related Questions