wangt13
wangt13

Reputation: 1265

How to accurately/precisely seek to a timestamp in media with ffmpeg API?

I am writing a simple audio player with ffmpeg ver.4.4.4, and I want to seek to specific timestamp of the audio media (a MP3 file).

Here is my code. I am using avformat_seek_file() with flags of AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD, and when I set seek_pos to 10 second when it is playing frames of 3rd second, it seemed NOT jump to the 10th second, it only played the audios after 3rd second!

Then I added the code skipping/discarding the packets whose pts is before the seek position. This time, it loops in the if (curr_s < seek_ts), not going to 10th seconds.

It seemed NO keyframe at 10th second.

void decode_func(...)
{
    while (1) {
        if (av_read_frame(pfmtctx, packet) < 0) {
            avcodec_flush_buffers(pcodectx);
            printf("Got end of media, breaking\n");
            break;
        }
        /**
         * Discard the packet of pts before seek position
         */
        curr_s = packet->pts * av_q2d(pfmtctx->streams[stream]->time_base);
        if (seek_ts) {
            if (curr_s < seek_ts) {
                avcodec_flush_buffers(pcodectx);
                av_frame_unref(pFrame);
                continue;
            } else {
                seek_ts = 0;
            }
        }
        if (seek_req) {
            int64_t seek_abs;
            seek_req = 0;
            seek_abs = (seek_pos)*AV_TIME_BASE;
            printf("Seek to %lld, pts: %lld\n", seek_abs, packet->pts;
            if (seek_abs < 0) {
                seek_abs = 0;
            }
            if (avformat_seek_file(pfmtctx, -1, INT64_MIN, seek_abs, INT64_MAX, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD) >= 0) {
                avcodec_flush_buffers(pcodectx);
                seek_ts = seek_abs;
                continue;
            } else {
                printf("Failed to seek to %lld\n", seek_abs);
                seek_ts = 0;
            }
        }

        res = avcodec_send_packet(pcodectx, packet);
        while (res >= 0) {
            res = avcodec_receive_frame(pcodectx, pFrame);
            if (res == AVERROR(EAGAIN)) {
                break;
            } else if (res == AVERROR_EOF) {
                break;
            } else if (res >= 0) {
             /// Processing decoded frame
            }
        av_frame_unref(frame);
    }
}

So, how can I precisely (almost) seek to a timestamp with FFMPEG?

Upvotes: 1

Views: 49

Answers (0)

Related Questions