通过ffmpeg反向播放视频

Posted

技术标签:

【中文标题】通过ffmpeg反向播放视频【英文标题】:Reverse video playback through ffmpeg 【发布时间】:2016-04-20 15:33:14 【问题描述】:

我正在使用 ffmpeg 多媒体框架实现视频播放器。我能够实现播放、暂停、提高速度、降低速度、向前搜索、向后搜索功能。但是视频的反向播放就不是那么流畅了,卡顿很多。请帮助我理解视频反向播放。对此有什么更好的方法?

还有其他支持反向播放的多媒体框架吗?

非常感谢。

【问题讨论】:

尝试使用较小的 GOP 对视频进行编码,例如 -g 9 或更低 还有reverse 过滤器可以提供一些见解。 【参考方案1】:

所以,首先,对这个问题进行一些框架。 FFmpeg 是一个极低级的库,它试图在原始媒体文件访问之上提供一个精简的 API。这意味着您基本上可以完全了解媒体文件中的内容。对于视频,这是来自解复用器的压缩视频数据包流,然后是来自解码器的解码图像流。由于 B/P 帧预测,这是一个严格的线性和单向过程。还要注意,在大多数实际情况下,FFmpeg 使用多线程,这又是一个严格的线性过程。如果您有 4 线程解码第 8、9、10、11 帧,然后您在此之后寻找第 7 帧(因此解码第 7、8、9 和 10 帧),那么您实际上是在产生永恒的浪费。

所以:使用逆序 av_seek_frame() 进行反向播放本质上与 FFmpeg 基本设计不兼容。这并不意味着你不能使用 FFmpeg 来做,但它确实意味着如果你 使用 FFmpeg 来做它,它需要一些努力。说了这么多,你将如何完成反向播放?你缓存!

您可以创建 N 帧组(其中 N 至少与线程数一样大,但仍允许您在内存中保存这么多帧),例如N=10 或 N=100(取决于帧大小)。然后,使用对av_read_frame()avcodec_decode_videoN() 的顺序调用前向解码 N 帧,并将它们保存在应用程序的内存中。例如,您现在可能在内存中有第 7-17 帧。开始显示第 17 帧,然后显示第 16、15 帧,依此类推(从内存中),直到您点击 index=7。当你点击 7 时,寻找下一个位置,允许你在内存中保存 N 帧(在 N=10 的情况下,这将是 index=0),并在内存中保存第 0-6 帧,并显示 index=6, 5 以此类推,直到 0。

我实际上已经实现了这个确切的功能,并且使用这种方法效果很好,并且它仍然(几乎)正确地使用了多线程。高分辨率视频上的大 N 值确实需要相当多的内存,因此我们鼓励您使 N 取决于帧大小,并使 N * 分辨率可以在您的应用程序的首选项中设置,或者至少使其取决于运行软件的计算机上的可用内存总量。

请注意,搜索并不是最简单的事情,因为您不能随机搜索到任何视频中的任何点并期望它能够正常工作。对于大多数实现 P 帧或 B 帧的编解码器,您只能寻找关键帧或 I/IDR 帧。这意味着文件格式需要在其索引中设置关键帧标志。如果不是这种情况,您必须在最初加载文件时综合生成索引(例如,调用 av_read_frame() 直到您点击 EOF)。

关于您的其他问题:我确信还有其他媒体框架实现了特技播放(反向播放等),例如GStreamer 确实如此。但是,这通常只适用于有限数量的文件格式,媒体框架中的not for all supported file formats。

【讨论】:

罗纳德您好,非常感谢您的详细解释。目前我已经实现了你解释的相同逻辑。它适用于 gop 较小的少数文件。我将分析 gstreamer 框架。有时间 :) 您会发现对于较大的 GOP,GStreamer 会提前预缓存,即假设每 25 帧有一个关键帧,但您只缓存 10 帧。这意味着您必须解码 25 帧来播放 15-25,再解码 15 帧来解码 5-15,并使用 f 帧来播放前 5 帧。KF 间隔越大,开销越大。解决方案是增加 N(缓存大小)并在接近缓存开始时预加载(即在玩 17,而不是 15 时开始加载 5-15)。 GStreamer 可能会自动完成大部分操作。

以上是关于通过ffmpeg反向播放视频的主要内容,如果未能解决你的问题,请参考以下文章

怎么通过rtp协议播放ffmpeg采集到的视频?

希望播放非编码视频上传,然后通过 FFMPEG 从选择点导出 gif

使用ffmpeg+nginx使用视频切片播放

FFmpeg 播放器视频渲染优化

QT软件开发-基于FFMPEG设计视频播放器-支持软解与硬解

基于FFmpeg的视频播放器之四:视频解码