23

我正在写一个视频编辑器,我需要寻找精确的帧,知道帧号

stackoverflow 上的其他帖子告诉我,ffmpeg 搜索后可能会给我一些碎帧,这对于播放来说不是问题,但对于视频编辑器来说是个大问题。

而且我需要按帧号不是时间来寻找,当转换为帧号时会变得不准确。

我读过danger's tuts(现在已经过时了),最终得到:

av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);

它总是寻求框架No. 0,并且总是return 0意味着成功。然后我尝试阅读 Blender 的源代码,发现它真的很复杂(也许我应该实现一个图像缓冲区?)。

那么,有没有什么简单的方法可以通过一个简单的调用来寻找一个帧seek(context, frame_number)(同时获得一个完整的帧,而不是一个破碎的帧)?或者,是否有任何轻量级库可以简化这一点?

编辑: 感谢praks411,我找到了解决方案:

void AV_seek(AV * av, size_t frame)
{
    int frame_delta = frame - av->frame_id;
    if (frame_delta < 0 || frame_delta > 5)
        av_seek_frame(av->fmt_ctx, av->video_stream_id,
                frame, AVSEEK_FLAG_BACKWARD);
    while (av->frame_id != frame)
        AV_read_frame(av);
}

void AV_read_frame(AV * av)
{
    AVPacket packet;
    int frame_done;

    while (av_read_frame(av->fmt_ctx, &packet) >= 0) {
        if (packet.stream_index == av->video_stream_id) {
            avcodec_decode_video2(av->codec_ctx, av->frame, &frame_done, &packet);
            if (frame_done) {
                ...
                av->frame_id = packet.dts;
                av_free_packet(&packet);
                return;
            }
        }
        av_free_packet(&packet);
    }
}

EDIT2: 原来有一个库:FFMS2。它是“一个基于 FFmpeg 的源库 [...],便于帧准确访问”,并且是可移植的(至少跨 Windows 和 Linux)。

4

1 回答 1

11

av_seek_frame只会根据关键帧的时间戳寻找。由于它会寻找关键帧,因此您可能无法获得想要的结果。因此,建议寻找最近的关键帧,然后逐帧阅读,直到您到达所需的帧。

但是,如果您正在处理固定的 FPS 值,那么您可以轻松地将时间戳映射到帧索引。

AVStream.time_base如果您已指定流,则在搜索之前,您需要将时间转换为单位。av_seek_frame阅读in 的ffmpeg 文档avformat.h

例如,如果你想寻找1.23几秒钟的剪辑:

 double m_out_start_time = 1.23;
 int flgs = AVSEEK_FLAG_ANY;
 int seek_ts = (m_out_start_time*(m_in_vid_strm->time_base.den))/(m_in_vid_strm->time_base.num);
 if(av_seek_frame(m_informat, m_in_vid_strm_idx,seek_ts, flgs) < 0)
 {
     PRINT_MSG("Failed to seek Video ")
 }
于 2013-07-09T13:50:12.467 回答