Android 9 AAC 解码器使用 ffmpeg 编码文件输出零样本
Android 9 AAC decoder outputs zero samples with ffmpeg-encoded files
我有一些自动化测试尝试使用 Android 的 MediaDecoder
和 MediaExtractor
将一些 m4a 文件解码为 PCM 数据。这些文件是使用各种编码器生成的:fdk-aac、ffmpeg(使用 fdk 或默认的 aac 编码器)、iOS.
在 Android 9 上,使用 ffmpeg
创建的剪辑测试失败,导致 PCM 文件为空。相同的剪辑在 Android.
的旧版本上可以很好地解码
我仔细检查了我的代码,解码过程按预期进行:
- 我使用
MediaExtractor
提取压缩数据
- 将其加入编解码器
- 从编解码器中取出输出缓冲区。
问题是,当最后一个可用的输入缓冲区入队并且 MediaCodec.BUFFER_FLAG_END_OF_STREAM
的输出缓冲区出队时,所有输出缓冲区都是空的!
然后我注意到使用 MediaExtractor.getTrackFormat(int track)
从音频文件中提取的 MediaFormat
信息包含一个未记录的 "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 数据中确实显示延迟(这是一个已知问题)。
但是...虽然 "fdkaac with ISO delay info" 情况的值是正确的并且导致没有初始填充的有效 PCM 文件(终于!),值因为 ffmpeg 生成的文件看起来很大而且可能是错误的!
我知道 ffmpeg 情况下的实际编码器延迟值为 1024,ffmpeg (fdk) 情况下为 2048,并且我认为提取格式中 key 的高值是文件为空的原因。
事实上,如果我在将 "encoder-delay"
键传递给 MediaCodec.configure(...)
之前尝试将格式中的 "encoder-delay"
键设置为 0,我会得到具有预期延迟的正确未压缩数据。
我现在的猜测是 MediaExtractor
编码器延迟值检索有一些错误,但也许我忽略了一些东西。
由于 ffmpeg 非常流行,我的许多应用程序用户很可能会尝试导入使用它生成的文件,此时我看不到该问题的万无一失的解决方案。
有人有建议/解决方法吗?
我在 android 问题跟踪器上打开了一个问题:
https://issuetracker.google.com/issues/118398811
现在我只是实施了一个解决方法:当 "encoder-delay" 值出现在 MediaFormat
对象中并且它是一个不可能高的值时,我只是将其设置为零。类似于:
if (format.containsKey("encoder-delay") && format.getInteger("encoder-delay") > THRESHOLD) {
format.setInteger("encoder-delay", 0);
}
注意: 这意味着初始间隙不会被修剪掉,但是对于没有此类信息的 M4a 文件,这已经是 [=22 之前的情况了=]-9 台设备。
我有一些自动化测试尝试使用 Android 的 MediaDecoder
和 MediaExtractor
将一些 m4a 文件解码为 PCM 数据。这些文件是使用各种编码器生成的:fdk-aac、ffmpeg(使用 fdk 或默认的 aac 编码器)、iOS.
在 Android 9 上,使用 ffmpeg
创建的剪辑测试失败,导致 PCM 文件为空。相同的剪辑在 Android.
我仔细检查了我的代码,解码过程按预期进行:
- 我使用
MediaExtractor
提取压缩数据
- 将其加入编解码器
- 从编解码器中取出输出缓冲区。
问题是,当最后一个可用的输入缓冲区入队并且 MediaCodec.BUFFER_FLAG_END_OF_STREAM
的输出缓冲区出队时,所有输出缓冲区都是空的!
然后我注意到使用 MediaExtractor.getTrackFormat(int track)
从音频文件中提取的 MediaFormat
信息包含一个未记录的 "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 数据中确实显示延迟(这是一个已知问题)。
但是...虽然 "fdkaac with ISO delay info" 情况的值是正确的并且导致没有初始填充的有效 PCM 文件(终于!),值因为 ffmpeg 生成的文件看起来很大而且可能是错误的!
我知道 ffmpeg 情况下的实际编码器延迟值为 1024,ffmpeg (fdk) 情况下为 2048,并且我认为提取格式中 key 的高值是文件为空的原因。
事实上,如果我在将 "encoder-delay"
键传递给 MediaCodec.configure(...)
之前尝试将格式中的 "encoder-delay"
键设置为 0,我会得到具有预期延迟的正确未压缩数据。
我现在的猜测是 MediaExtractor
编码器延迟值检索有一些错误,但也许我忽略了一些东西。
由于 ffmpeg 非常流行,我的许多应用程序用户很可能会尝试导入使用它生成的文件,此时我看不到该问题的万无一失的解决方案。
有人有建议/解决方法吗?
我在 android 问题跟踪器上打开了一个问题: https://issuetracker.google.com/issues/118398811
现在我只是实施了一个解决方法:当 "encoder-delay" 值出现在 MediaFormat
对象中并且它是一个不可能高的值时,我只是将其设置为零。类似于:
if (format.containsKey("encoder-delay") && format.getInteger("encoder-delay") > THRESHOLD) {
format.setInteger("encoder-delay", 0);
}
注意: 这意味着初始间隙不会被修剪掉,但是对于没有此类信息的 M4a 文件,这已经是 [=22 之前的情况了=]-9 台设备。