通过FFmpeg进行视频倒放播放

4
我正在使用FFmpeg多媒体框架实现视频播放器。我已经可以实现播放、暂停、加速、减速、快进和后退功能。但是,视频的倒放不够流畅,会出现很多卡顿。请帮助我理解视频倒放。有没有更好的方法?
是否有其他支持视频倒放的多媒体框架?
非常感谢您的帮助。

尝试使用小GOP进行视频编码,例如“-g 9”或更低。 - Gyan
还有一些reverse滤镜可以提供一些见解。 - llogan
1个回答

7
首先,需要对这个问题进行一些概述。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帧保留在内存中,并显示索引= 6、5等,直到0。
我实际上已经使用这种方法实现了这个精确功能,它的工作效果非常好,而且它确实正确地使用了(几乎)多线程。对于高分辨率视频中的大N值,需要相当多的内存,因此建议您使N依赖于帧大小,并使N * 分辨率可以在应用程序首选项中设置,或者至少取决于软件运行所在计算机上可用的总内存量。
请注意,寻找并不是最容易的事情,因为您不能随机地寻找任何视频中的任何点并期望它能正常工作。对于大多数实现P帧或B帧的编解码器,您只能寻找关键帧或I/IDR帧。这意味着文件格式需要在其索引中设置关键帧标志。如果不是这种情况,则您将不得不在初始加载文件时合成一个索引(例如,调用av_read_frame()直到达到EOF)。
关于你的另一个问题:我相信有其他媒体框架实现了特技播放(比如倒放等),例如GStreamer。然而,这通常只适用于有限数量的文件格式,在媒体框架中并非所有支持的文件格式都能使用此功能。请参考链接:GStreamer不适用于所有支持的文件格式

你好,Ronald。非常感谢你详细的解释。目前我已经实现了你所解释的相同逻辑。对于一些GOP较小的文件,它运行良好。我将分析gstreamer框架。祝你愉快 :) - Raju
您会发现,对于更大的GOP,GStreamer会提前预缓存,即每25帧一个关键帧,但您只缓存10帧。这意味着您需要解码25帧才能播放15-25,另外15帧才能解码5-15,并且f帧才能播放前5帧。关键帧间隔越大,开销就越大。解决方案是增加N(缓存大小)并在接近缓存开始时进行预加载(即在播放17而不是15时开始加载5-15)。GStreamer可能会自动完成大部分操作。 - Ronald S. Bultje

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接