FFmpeg - Lost in the hell of av_seek_frame()

650 Views Asked by At

I'm writing a video player which uses FFmpeg. I need to implement a seek functionality.

So I implemented a seek function (see code below) which I tested against a video with a duration of 2,8s:

static void seek_to(AVFormatContext* fmt, int64_t pos)
{
    AVStream* stream = fmt->streams[0];
    int64_t   seek_pos = pos;
    int       seek_flags;

    if (fmt->duration == AV_NOPTS_VALUE)
        seek_flags = AVSEEK_FLAG_FRAME;
    else
        seek_flags = AVSEEK_FLAG_BACKWARD;

    AVRational time_base = { 1, AV_TIME_BASE };

    int64_t seek_target = seek_flags == AVSEEK_FLAG_BACKWARD ?
            av_rescale_q(seek_pos, time_base, stream->time_base) : seek_pos;

    int ret = av_seek_frame(fmt, 0, seek_target, seek_flags);

    if (ret < 0)
    {
        // log the error...
    }

    ...

    // perform some tasks like flushing the decoder(s) by calling the mp_decode_flush() function
}

I certify that the pos value is well passed in microseconds (it's the format expected by AV_TIME_BASE and matching with the duration exposed in format context - I strongly checked it), and contains a valid number between 0 and the video duration time.

As a result, the seek roughly works, however it is very choppy and ugly. It's like the video contained only 3 possible position (0, 1/3 and 2/3 of the total length) and there is no way to have a smooth and precise seek position.

I suspect a conversion issue somewhere (as if the final value was in seconds instead of microseconds), but I cannot figure out what I'm doing wrong.

My assumptions are:

  • I have effectively a conversion issue, but I strongly tested all my values and I can certify that they are passed in the expected ranges and well converted in the correct time bases. So the issue would be on the FFmpeg side
  • The FFmpeg library is not planned to work well with so small values, it needs at least a huger video to works well
  • I'm doing something wrong, and perhaps my approach isn't the good one to seek in my videos

Is one of my above assumptions correct, or there is something else which may break my seek function? Has someone already faced a such issue and how he resolved it?

1

There are 1 best solutions below

0
micha137 On

What codec is your video encoded in (ffprobe will tell you)? You can only seek to key frames. If you want any non-key frame you have to start decoding from the last key frame before that and throw away frames until you got the frame you wanted.

Another issue with av_seek_frame is that it depends on the demuxer wheter it expects timestamps as DTS or PTS.