Search code examples
c++cffmpegvideo-processing

How to seek in FFmpeg C/C++


Does anyone know how to implement seeking by seconds (or milliseconds) in FFmpeg. I currently have a loop running through the frames of a video using av_read_frame() and I want to determine what time this frame should be at in seconds. If it gets to a certain point then I want to seek to a later point in the video. By the way it is not a video player, just processing the frames. Ive heard I should be able to get the dts or pts from the packet but its always returning 0.


Solution

  • NOTE: This is out of date, it should still work but there is now av_seek_frame() to do it officially.

    I didn't write this but here is some code from a sample I have

    bool seekMs(int tsms)
    {
       //printf("**** SEEK TO ms %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",tsms,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk);
    
       // Convert time into frame number
       DesiredFrameNumber = ffmpeg::av_rescale(tsms,pFormatCtx->streams[videoStream]->time_base.den,pFormatCtx->streams[videoStream]->time_base.num);
       DesiredFrameNumber/=1000;
    
       return seekFrame(DesiredFrameNumber);
    }
    
    bool seekFrame(ffmpeg::int64_t frame)
    {
    
       //printf("**** seekFrame to %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",(int)frame,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk);
    
       // Seek if:
       // - we don't know where we are (Ok=false)
       // - we know where we are but:
       //    - the desired frame is after the last decoded frame (this could be optimized: if the distance is small, calling decodeSeekFrame may be faster than seeking from the last key frame)
       //    - the desired frame is smaller or equal than the previous to the last decoded frame. Equal because if frame==LastLastFrameNumber we don't want the LastFrame, but the one before->we need to seek there
       if( (LastFrameOk==false) || ((LastFrameOk==true) && (frame<=LastLastFrameNumber || frame>LastFrameNumber) ) )
       {
          //printf("\t avformat_seek_file\n");
          if(ffmpeg::avformat_seek_file(pFormatCtx,videoStream,0,frame,frame,AVSEEK_FLAG_FRAME)<0)
             return false;
    
          avcodec_flush_buffers(pCodecCtx);
    
          DesiredFrameNumber = frame;
          LastFrameOk=false;
       }
       //printf("\t decodeSeekFrame\n");
    
       return decodeSeekFrame(frame);
    
       return true;
    }