6

我正在使用 ffmpeg 实现音频解码器。虽然阅读音频甚至搜索已经有效,但我无法找到一种在搜索后清除缓冲区的方法,因此当应用程序在搜索后立即开始阅读音频时,我没有任何伪影。

avcodec_flush_buffers似乎对内部缓冲区没有任何影响。所有解码器(mp3、aac、wma、...)都会出现此问题,但 PCM/WAV(由于音频未压缩,因此不使用内部缓冲区来保存要解码的数据)。

代码片段很简单:

av_seek_frame(audioFilePack->avContext, audioFilePack->stream, posInTimeFrame, AVSEEK_FLAG_ANY);
avcodec_flush_buffers(audioFilePack->avContext->streams[audioFilePack->stream]->codec);

解释:

audioFilePack->avContext = FormatContext
audioFilePack->stream = Stream Position (also used to read audio packets)
audioFilePack->avContext->streams[audioFilePack->stream]->codec = CodecContext for the codec used

关于我应该做什么的任何想法,以便我可以寻找并获得没有残留的音频?谢谢!

4

2 回答 2

3

这是ffmpeg中的一个错误。内部缓冲区没有被刷新,因此当您在刷新后获取数据包/帧时,您将获得预搜索数据。它似乎在 2012 年 3 月 16 日已修复,因此您可以自己合并此修复程序,或升级 ffmpeg。

http://permalink.gmane.org/gmane.comp.video.libav.devel/23455

作为更新,上面的错误确实是一个问题,但还有第二个专门针对 AAC 的错误。

截至五个月前,另一位用户发现了此错误,并报告已修复。 https://ffmpeg.org/trac/ffmpeg/ticket/420

修复是添加到 aacdec.c 的刷新函数,该函数清除其内部缓冲区。问题是在 aacdec.c 中定义了两个解码器,并且只有一个被赋予了 flush 函数指针。如果您使用其他(更常见的)解码器,它仍然无法正确清除。

如果您能够自己构建 ffmpeg,解决方法是将 .flush = flush, 添加到 AVCodec ff_aac_decoder 定义的底部(位于文件底部。)

我会让 ffmpeg 家伙知道所以希望它可以包含在主分支中。

于 2012-04-23T21:34:06.850 回答
2

我从未编写过具有搜索功能的音频播放器,但我怀疑正在发生的事情是这样的。每个音频包都解码为原始声波的片段。通常,这些片段顺序地相互邻接,结果是一个连续的波,人们将其作为没有伪影的音频听到。当您寻找时,您会强制文件不同部分的两个片段彼此邻接。这通常会在生成的声波中引入不连续性,耳朵将其感知为咔哒声或爆裂声,或者如您所说(我猜)是人工制品。

这是一个更具体的例子。假设您在搜索之前已经播放了前 ​​25 个音频包。假设数据包 25 解码为最后一个样本为 12345 的波。当数据包 25 被呈现给扬声器时,您寻找数据包 66。假设数据包 66 的第一个样本是 -23456。因此,数字音频流在寻道过程中从 12345 跳到 -23456。这是一个巨大的不连续性,并且会像流行音乐一样被听到。

我认为一种解决方案是在开始搜索之前获取一个额外的数据包(在我的示例中为数据包 26),将其解码为离线缓冲区,应用淡出,然后将其放入播放队列。找到所需位置后,获取第一个数据包(在我的示例中为 66 个),将其解码到另一个离线缓冲区,应用淡入,然后将其放入播放队列。这应该确保平滑的声波和无伪影的搜索。

如果您很聪明,您可以根据需要将淡出和淡入设置为短或长。我认为只有几毫秒就足以防止伪影。您甚至可以应用新旧数据包的交叉淡入淡出。也可能仅在查找之前记录最后一个数据包中的最后一个样本值,并在几个样本中逐渐将其降低到零,而不是立即将其拉到零。这可能比解码额外的数据包更容易。

这是我对如何解决这个问题的猜测。这显然是一个已解决的问题,所以我鼓励你也看看开源音频播放器,看看他们是如何实现搜索的。Audacity、Totem、Banshee、RhythmBox、Amarok 或 VLC 等程序或 GStreamer 等框架可能是值得学习的好例子。如果您发现他们采用了显着的技术,请在此处报告主题。我认为人们会想知道他们是什么。祝你好运!

于 2011-11-11T07:31:31.327 回答