修订:2017.3.6 22:51
据团队测试,基于FFmpeg 0.10.16 "Freedom"进行atempo滤镜变速音频在开始时不会有明显噪声(ci ci ci声),特别是慢速情况下,转码命令如下所示。升级为FFmpeg 2.x及FFmpeg 3.x,相同操作音质明显变差。
ffmpeg -i source.wav -filter:a "atempo=0.5, atempo=0.5" -vn destination.wav
失败地NDK直接翻译AVFilter模块尝试
尝试直接通过NDK编译FFmpeg 0.10.16的AVFilter模块,因其依赖关系较为复杂,不少文件又引用了libavcodec、libavformat等模块,处理起来需要较大工作量。
尝试SoundTouch
简单起见,使用SoundTouch Audio Processing Library实现音频变速。它只支持WAV格式,可先由FFmpeg解码AAC等数据,再进行处理。
SoundTouch使用的音频处理算法参考为Time and pitch scaling in audio processing,其实和FFmpeg一样都使用了wsola算法。
下载SoundTouch源码,在source目录有Android项目Android-lib,它在Application.mk中没定义Android版本,具体版本内容写在AndroidManifest.xml。其实这并不会令NDK编译成它指定的版本,因为执行ndk-build时有如下日志。
Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 11 in /soundtouch/source/Android-lib/AndroidManifest.xml
由于需要编译成动态库,给Application.mk添加了版本信息。
APP_PLATFORM := android-11
将编译后的动态库放到其他工程中,链接时出现未定义符号问题,原因是Android.mkd中定义了隐藏符号,编译指令如下所示。
# Custom Flags:
# -fvisibility=hidden : don't export all symbols
#LOCAL_CFLAGS += -fvisibility=hidden -I ../../../include -fdata-sections -ffunction-sections
SoundTouch在iOS、Android上使用存在的问题
1、NDK链接时动态库符号被隐藏
屏蔽Android.mk相关指令即可。
2、PCM存储格式及平面音频
默认情况下,SoundTouch头文件定义PCM为单精度浮点数(float)。而通常在Android上播放PCM是16位整形,根据之前参考过的资料,不使用float格式处理PCM是因为浮点数计算在armeabi-v7a之前都是软实现,性能较差。
当配合FFmpeg使用时,比如解码mp3得到的是s16p,此时需要将左右平面(左右声道)混合成一个平面,比如LR LR LR,再传递给SoundTouch处理。
学习资料
WELEN写了不少音频信号处理的博客,可以参考阅读。