背景
最近在测试视频录制功能时发现,AudioRecord + MediaCodec + MediaMuxer生成的MP4,PC浏览器无法播放 ,但是Android、Windows、Mac的播放器应用都能正常播放。虽然不禁想吐槽浏览器视频组件的容错性差,但我也意识生成的文件格式肯定也是有问题的。
然后尝试了合成MP4视频时,只保留视频通道,不要音频,发现拖到浏览器中可以正常播放。使用ffprobe检查有问题的MP4文件,有如下错误输出:
[aac @ 0x7f95c9c0e7c0] Input buffer exhausted before END element found
至此,基本确定问题出现在生成的音频数据上。
解决过程
由于此前个人音视频开发经验不足,MediaCodec、MediaMuxer编码和合成视频的相关代码参考了一些开源项目及博客。
但由于开发周期紧急,没有足够的时间来仔细研究和排查,当时就采用了一种曲线救国的方案。
曲线修复方案
能想到这个方案也比较偶然。当时查阅了一些资料和博客,用到了ffmpeg和ffprobe工具对问题视频进行分析。
在尝试了使用ffmpeg工具对问题视频进行转换后,意外地发现,虽然命令也会报错[aac @ 0x7f95c9c0e7c0] Input buffer exhausted before END element found,但是,问题视频经过fmpeg转换后,生成的新视频,用ffprobe命令查看是没有错误输出的,也可以正常播放!也就是说,ffmpeg在处理转换有问题的音频时,会自动跳过那些有问题的数据。
由此,想到了一个比较曲折的方案:先用AudioRecord + MediaCodec + MediaMuxer生成MP4,然后使用ffmpeg命令对生成的视频进行一点无关紧要的转换(重点是让它处理掉有问题的数据),然后就能得到一个格式正确的音频数据,然后用MediaExtractor提取出原MP4中的视频数据,最后用MediaMuxer合成最终格式正确的mp4文件。
因为是音频有问题,所以实践中我就使用了如下命令来转换:
ffmpeg -i input.mp4 -vn -ab 96k out.m4a
-vn参数指定不要视频数据,-ab 96k将音频码率转为96k。
现在,只需要裁剪、交叉编译一个满足以上需求的arm版本的ffmpeg可执行程序就好了。关于如何裁剪和编译ffmpeg,网上音视频相关的技术文章一大把,就不赘述细节了。
这里记录一下我反复测试编译配置参数后,能输出较小体积(约2.6MB)arm版ffmpeg可执行命令的编译脚本,方便以后查看。因为我只需要处理音频,所以这个配置编译出的ffmpeg只能解码MP4和aac,并且只支持输出m4a音频。
#!/bin/sh
# NDK路径,根据电脑环境配置情况调整
NDK_HOME="/Users/shenyong/Library/Android/sdk/ndk/21.4.7075529"
TOOLCHAIN="$NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64"
SYSROOT="$TOOLCHAIN/sysroot"
# 默认使用arm编译配置
API=29
ARCH=arm
CPU=armv7-a
TOOL_CPU_NAME=armv7a
# CROSS_PREFIX, CC and CXX for arm
CROSS_PREFIX="$TOOLCHAIN/bin/arm-linux-androideabi-"
CC="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-androideabi$API-clang"
CXX="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-androideabi$API-clang++"
OUTPUT_DIR="./android/$CPU"
OPTIMIZE_CFLAGS="-march=$CPU"
function config_arm64() {
ARCH=arm64
CPU=armv8-a
TOOL_CPU_NAME=aarch64
# CROSS_PREFIX, CC and CXX for arm64
CROSS_PREFIX="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-android-"
CC="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-android$API-clang"
CXX="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-android$API-clang++"
OUTPUT_DIR="./android/$CPU"
OPTIMIZE_CFLAGS="-march=$CPU"
#libmediandk.so路径
MEDIA_NDK_LIB=$TOOLCHAIN/sysroot/usr/lib/aarch64-linux-android/$API
ADD_MEDIA_NDK_SO="--extra-ldflags=-L$MEDIA_NDK_LIB --extra-libs=-lmediandk "
}
# 如果需要编译arm64版本,将以下行取消注释即可
config_arm64
#清除之前的编译配置及输出
make distclean
./configure \
--prefix=$OUTPUT_DIR \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--enable-cross-compile \
--cross-prefix=$CROSS_PREFIX \
--sysroot=$SYSROOT \
--cc=$CC \
--cxx=$CXX \
--extra-cflags=

文章讲述了作者在测试视频录制功能时遇到的问题,即生成的MP4在PC浏览器无法播放,通过分析发现音频数据存在问题。作者分享了使用ffmpeg处理音频数据,以及在MediaCodec和MediaMuxer代码中的关键修复策略,解决了这个问题。
最低0.47元/天 解锁文章
9913






