我怎样才能用ffmpeg寻找第X帧?
Posted
技术标签:
【中文标题】我怎样才能用ffmpeg寻找第X帧?【英文标题】:How can I seek to frame No. X with ffmpeg? 【发布时间】:2013-07-06 22:23:00 【问题描述】:我正在编写一个视频编辑器,并且我需要知道帧号来寻找精确的帧。
*** 上的其他帖子告诉我,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)。
【问题讨论】:
你能保证固定稳定的fps吗?然后你可以按时间寻找。另见关于“关键帧”的讨论 只有用户知道。它可能是可变帧率视频。 【参考方案1】:av_seek_frame
只会根据时间戳寻找关键帧。由于它会寻找关键帧,因此您可能无法获得想要的结果。因此,建议寻找最近的关键帧,然后逐帧阅读,直到您到达所需的帧。
但是,如果您正在处理固定的 FPS 值,那么您可以轻松地将时间戳映射到帧索引。
如果您已指定流,则在搜索之前,您需要将时间转换为 AVStream.time_base
单位。在avformat.h
中阅读av_seek_frame
的ffmpeg 文档。
例如,如果你想寻找到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 ")
【讨论】:
哦,我终于知道文档在头文件里了,怪不得网上找不到。 那么,我怎么知道最近的关键帧在哪里呢? time_base.den/time_base.num 不是 fps 吗? seek_ts=time*fps 不是帧数吗? 您在谈论编解码器上下文时基,我采用了不同的流时间。用于寻找最近的时间关键帧。我认为你应该在寻找时保持一定的宽容度,那就是尝试在你想要的帧之前寻找 3 帧,这样如果它不是关键帧,你就不会错过你的帧。然后从那里逐帧阅读。 经过一番尝试,我发现我必须将标志设置为 AVSEEK_FLAG_BACKWARD 才能找到关键帧。而 seek_ts 是帧号。我还发现我之前试的视频文件只有4个关键帧(一个WebM,一共360帧,30fps,不知道为什么),确实干扰了我的寻道实验。以上是关于我怎样才能用ffmpeg寻找第X帧?的主要内容,如果未能解决你的问题,请参考以下文章
怎样才能得到ffmpeg的colorchannelmixer的colormatrix
熊猫,我怎样才能避免使用 iterrow (如何根据来自另一个数据帧的值将值分配给数据帧中的新列)
Python / DataReader / Yahoo - 不推荐使用 pandas 的面板,我怎样才能将股票数据带入多索引数据帧?