我有一些自动化测试,尝试使用Android的MediaDecoder
和MediaExtractor
将一些m4a文件解码为PCM数据。这些文件是使用各种编码器生成的:fdk-aac,ffmpeg(使用fdk或默认的aac编码器),iOS。
在Android 9上,使用ffmpeg
创建的剪辑的测试失败,这将导致PCM文件为空。相同的剪辑在较旧的Android版本上可以很好地解码。
我仔细检查了我的代码,解码过程按预期进行:
MediaExtractor
问题在于,当最后一个可用的输入缓冲区入队,带有MediaCodec.BUFFER_FLAG_END_OF_STREAM
的输出缓冲区出队时,所有输出缓冲区都为空!
然后,我注意到使用MediaFormat
从音频文件中提取的MediaExtractor.getTrackFormat(int track)
信息包含一个未记录的"encoder-delay"
密钥。
对于android 8及更低版本,该密钥仅适用于使用iTunSMPB
标签信息编码的m4a剪辑。这是我为测试文件获得的值的摘要:
iOS-encoded file: 2112 frames
fdkaac with iTunSMPB tag: 2048 frames
fdkaac with ISO delay info: key not present
ffmpeg: key not present
ffmpeg (fdk): key not present
在Android 9上,我得到以下结果:
iOS-encoded file: 2112 frames
fdkaac with iTunSMPB tag: 2048 frames
fdkaac with ISO delay info: 2048 frames
ffmpeg: 45158 frames
ffmpeg (fdk): 90317 frames
看起来有些变化,MediaExtractor
现在可以检索所有被测文件的编码器延迟。从理论上讲,这是好的,因为没有"encoder-delay"
信息的文件的确在解码的PCM数据中显示了延迟(这是一个已知问题)。
但是...虽然“具有ISO延迟信息的fdkaac具有ISO延迟信息” 情况下的值是正确的,并导致没有初始填充的有效PCM文件(最终!),但ffmpeg的值生成的文件看起来很大,很可能是错误的!
我知道 ffmpeg 情况下的实际编码器延迟值为1024,而 ffmpeg(fdk)情况下的编码器延迟值为2048,我认为键入的高值提取的格式是文件为空的原因。
实际上,如果我在将"encoder-delay"
键传递给MediaCodec.configure(...)
之前尝试将其格式设置为0,则会得到正确的未压缩数据,并具有预期的延迟。
在这一点上,我的猜测是MediaExtractor
编码器延迟值检索存在一些错误,但是也许我忽略了某些事情。
由于ffmpeg非常流行,因此我的许多应用程序用户很可能会尝试导入使用ffmpeg生成的文件,而在这一点上,我看不到一个万无一失的解决方案。
有人有建议/解决方法吗?
答案 0 :(得分:1)
我在android问题跟踪器上打开了一个问题: https://issuetracker.google.com/issues/118398811
现在,我只是实现了一种解决方法:当MediaFormat
对象中存在“ encoder-delay”值并且该值不可能很高时,我只需将其设置为零即可。像这样:
if (format.containsKey("encoder-delay") && format.getInteger("encoder-delay") > THRESHOLD) {
format.setInteger("encoder-delay", 0);
}
注意::这意味着不会消除初始差距,但是对于没有此类信息的M4a文件,在android-9之前的设备上已经存在这种情况。