Search code examples
c++ffmpegframe-rate

Video too fast FFmpeg


I am having an issue again with ffmpeg, I'm a newbie with ffmpeg, and I can't find a good tutorial up to date...

This time, when I play a video with ffmpeg, it plays too fast, ffmpeg is ignoring the FPS, I don't want to handle that with a thread sleep, because the videos have differents FPS's.

I created a thread, there you can find the loop:

AVPacket framepacket;

while(av_read_frame(formatContext,&framepacket)>= 0){
    pausecontrol.lock();

    // Is it a video or audio frame¿?
    if(framepacket.stream_index==gotVideoCodec){
        int framereaded;
        // Video? Ok
        avcodec_decode_video2(videoCodecContext,videoFrame,&framereaded,&framepacket);
        // Yeah, did we get it?
        if(framereaded && doit){
            AVRational millisecondbase = {1,1000};
            int f_number = framepacket.dts;
            int f_time = av_rescale_q(framepacket.dts,formatContext->streams[gotVideoCodec]->time_base,millisecondbase);
            currentTime=f_time;
            currentFrameNumber=f_number;

            int stWidth = videoCodecContext->width;
            int stHeight = videoCodecContext->height;
            SwsContext *ctx = sws_getContext(stWidth, stHeight, videoCodecContext->pix_fmt, stWidth,
            stHeight, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
            if(ctx!=0){
            sws_scale(ctx,videoFrame->data,videoFrame->linesize,0,videoCodecContext->height,videoFrameRGB->data,videoFrameRGB->linesize);
            QImage framecapsule=QImage(stWidth,stHeight,QImage::Format_RGB888);

            for(int y=0;y<stHeight;y++){
                memcpy(framecapsule.scanLine(y),videoFrameRGB->data[0]+y*videoFrameRGB->linesize[0],stWidth*3);
            }
            emit newFrameReady(framecapsule);
            sws_freeContext(ctx);
            }

        }
    }
    if(framepacket.stream_index==gotAudioCodec){
        // Audio? Ok
    }
    pausecontrol.unlock();
    av_free_packet(&framepacket);
}

Any Idea?


Solution

  • The simplest solution is to use a delay based on the FPS value

    firstFrame = true;
    for(;;)
    {
      //  decoding, color conversion, etc.
    
      if (!firstFrame)
      {
        const double frameDuration = 1000.0 / frameRate;
        duration_t actualDelay = get_local_time() - lastTime;
        if (frameDuration > actualDelay)
          sleep(frameDuration - actualDelay); 
      }
      else
        firstFrame = false;
    
      emit newFrameReady(framecapsule);
    
      lastTime = get_local_time();
    }
    

    get_local_time() and duration_t is abstract.

    A more accurate method is to use a time stamp for each frame, but the idea is the same