陈江川

邮箱:jiangchuanc@gmail.com

Andorid平台下的两个音频文件的合并

这个项目是2014年做的,其中有一个功能要求把已录制好的录音文件和音乐文件进行合并。之前也没怎么也没怎么接触过音频视频方面的知识,然后就google,但是国内的论坛关于音频合并的Demo基本上都是边播放音乐文件边录音。
下面就说说我是如何解决这个问题的。


音频的基础知识 (不过多累赘,想了解可问度娘)

1)Riff:一种文件规范,所有的wav前44字节就是Riff,它描述了该wav文件的相关信息;
2)PCM:媒体数据的元数据,直接记录声音数据;
3)Raw:PCM元数据就是以raw为后缀,比如:abcd.raw;
4)WAV:Riff + PCM;
5)MP3:将PCM元数据通过算法进行压缩;


思路

  • 把需要合并的两个音频文件转成PCM元数据;
  • 再把两个音频每个字节的数据读出来进行相加。

转PCM数据

如果音频格式为WAV,直接去掉头44个字节的Riff就能获取PCM数据。对于MP3文件,我使用ffmepg库,先把MP3转成WAV格式,然后就处理掉头44个字节。
使用ffmpeg把MP3转WAV的过程可能要花上3秒左右,所以我们在获得录音文件的时候,对生成的录音文件直接转为WAV格式,而且客户提供的音乐文件都采用了WAV格式,这样就省去了转换的时间。


音频合并

因为要实现两个音频边播放边录音,所以这里使用AudioRecord,这样就能获取播放一秒的字节数组。合并的算法是参考国外一位大牛的,因时间太久了,网站已经找不到了......

// sourceA,sourceB是从AudioRecord获取到每一秒的字节数组
private void mixByte(byte[] sourceA, byte[] sourceB) {
    
    int aSize = sourceA.length;
    int bSize = sourceB.length;
    int stander = aSize > bSize ? bSize : aSize;
    byte[] bytes = new byte[stander];   
    for (int i = 0; i < stander; i++) {
        byte a = sourceA[i];
        byte b = sourceB[i];
        
        float sampleA = a / 128.0f;
        float sampleB = b / 128.0f;
        float mixed = sampleA + sampleB;
        
        mixed *= 0.8;
        if (mixed > 1.0f) {
            mixed = 1.0f;
        } 
        if (mixed < -1.0f) {
            mixed = -1.0f;
        }
        
        // 这里就是我们需要的合并数据
        bytes[i] = (byte)(mixed * 128.0f);
    }
}

« 直播基础知识 视频直播学习<-> »