我怎样才能用 ffmpeg 来框架 X 号? [英] How can I seek to frame No. X with ffmpeg?

查看:29
本文介绍了我怎样才能用 ffmpeg 来框架 X 号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing a video editor, and I need to seek to exact frame, knowing the frame number.

stackoverflow 上的其他帖子告诉我 ffmpeg 可能会在查找后给我一些断帧,这对播放来说不是问题,但对视频编辑器来说是个大问题.

Other posts on stackoverflow told me that ffmpeg may give me a few broken frames after seeking, which is not a problem for playback but a big problem for video editors.

而且我需要按帧号不是按时间搜索,转换成帧号会不准确.

And I need to seek by frame number, not by time, which will become inaccurate when converted to frame number.

我读过 dranger 的 tuts(现在已经过时),最后得到:

I've read dranger's tuts (which is outdated now), and end up with:

av_seek_frame(fmt_ctx, video_stream_id, frame, AVSEEK_FLAG_ANY);

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

It always seek to frame No. 0, and always return 0 which means success. Then I tried to read Blender's source code and found it really complex(maybe I should implement an image buffer?).

那么,有没有什么简单的方法可以通过一个简单的调用来寻找一个框架,比如 seek(context, frame_number)(同时获得一个完整的框架,而不是一个损坏的框架)?或者,是否有任何轻量级库可以简化此操作?

So, is there any simple way to seek to a frame with just a simple call like seek(context, frame_number)(while getting a full frame, not a broken one)? Or, is there any lightweight library that simplifies this?

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

Thanks to praks411,I found the solution:

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);
    }
}

原来有一个库:FFMS2.它是一个基于 FFmpeg 的源库 [...],用于轻松准确地访问帧",并且是可移植的(至少在 Windows 和 Linux 之间).

Turns out there is a library for this: FFMS2. It is "an FFmpeg based source library [...] for easy frame accurate access", and is portable (at least across Windows and Linux).

推荐答案

av_seek_frame 只会根据时间戳寻找关键帧.由于它寻求关键帧,因此您可能无法获得所需的内容.因此建议寻找最近的关键帧,然后逐帧读取您到达所需帧.

av_seek_frame will only seek based on timestamp to the key-frame. Since it seeks to the keyframe, you may not get what you want. Hence it is recommended to seek to nearest keyframe and then read frame by frame util you reach the desired frame.

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

However, if you are dealing with fixed FPS value, then you can easily map timestamp to frame index.

在查找之前,如果您已指定流,则需要将时间转换为 AVStream.time_base 单位.阅读avformat.hav_seek_frame的ffmpeg文档.

Before seeking you will need to convert your time to AVStream.time_base units if you have specified stream. Read ffmpeg documentation of av_seek_frame in avformat.h.

例如,如果您想搜索 1.23 秒的剪辑:

For example, if you want to seek to 1.23 seconds of clip:

 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 ")
 }

这篇关于我怎样才能用 ffmpeg 来框架 X 号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆