You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FFmpeg C++视频定位后获取当前帧索引的方法求助

FFmpeg视频定位后获取当前帧索引/时间戳的解决方案

问题背景

我目前用FFmpeg实现视频定位,代码如下:

int64_t pts = (int64_t)( ((float) timestamp_to_go / 1000)* (double)time_base.den / (double)time_base.num);
if(av_seek_frame(av_format_ctx, video_stream_index, pts, AVSEEK_FLAG_BACKWARD) < 0 )
    exit(0);

这段代码能定位到最近的I帧(比如目标10秒,实际跳到8.5秒),这个情况可接受,但定位后无法获取当前帧的索引或时间戳,导致不知道需要解码多少帧才能到达目标位置(比如30fps视频中,8.5秒对应255帧,目标10秒对应300帧,需要明确当前帧索引来计算解码量)。

实现步骤

要获取定位后的帧信息,必须在av_seek_frame后重置解码器并读取解码第一帧,从帧数据中提取关键信息:

1. 重置解码器缓存

定位操作会打乱解码器的内部状态,必须先清空缓存:

avcodec_flush_buffers(av_codec_ctx);

2. 读取并解码定位后的首帧

循环读取数据包并解码,直到拿到第一个有效视频帧:

AVPacket pkt;
AVFrame* frame = av_frame_alloc();
int ret;
double fps = av_q2d(av_stream->avg_frame_rate); // 获取视频帧率
double target_seconds = 10.0; // 你的目标时间戳(秒)

while (av_read_frame(av_format_ctx, &pkt) >= 0) {
    if (pkt.stream_index != video_stream_index) {
        av_packet_unref(&pkt);
        continue;
    }

    // 发送数据包到解码器
    ret = avcodec_send_packet(av_codec_ctx, &pkt);
    if (ret < 0) {
        av_packet_unref(&pkt);
        continue;
    }

    // 接收解码后的帧
    while (ret >= 0) {
        ret = avcodec_receive_frame(av_codec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            break;
        } else if (ret < 0) {
            av_frame_unref(frame);
            av_packet_unref(&pkt);
            goto cleanup;
        }

        // 提取当前帧的时间戳和索引
        if (frame->pts != AV_NOPTS_VALUE) {
            double current_seconds = frame->pts * av_q2d(av_stream->time_base);
            int current_frame_idx = round(current_seconds * fps);
            int target_frame_idx = round(target_seconds * fps);
            int frames_to_decode = target_frame_idx - current_frame_idx;

            // 这里可以处理当前帧,然后继续解码frames_to_decode帧到达目标位置
            printf("当前时间戳:%.2f秒,当前帧索引:%d,还需解码%d帧\n", 
                   current_seconds, current_frame_idx, frames_to_decode);
            
            // 拿到所需信息后可退出循环,或继续解码
            goto cleanup;
        }

        av_frame_unref(frame);
    }

    av_packet_unref(&pkt);
}

cleanup:
av_frame_free(&frame);

3. 注意事项

  • 如果是可变帧率(VFR)视频,不要用帧索引判断进度,直接比较时间戳更可靠
  • frame->pts是基于视频流的time_base的,必须通过av_q2d()转换为实际秒数
  • 定位后的第一个解码帧就是你找到的I帧,无需额外判断帧类型

内容的提问来源于stack exchange,提问作者Turgut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 14:25:30