音视频 — PCM 转 WAV

不懂 PCM 的请看上一篇文章 https://www.jianshu.com/p/b6e951510cf0

什么是 WAV ?

想详细了解 WAV http://soundfile.sapp.org/doc/WaveFormat/
WAV为微软公司开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,RIFF文件以文件头开头,后跟一系列数据块(chunk)。WAV文件一般是用于CD存储原声带的,是一种无损的音频文件格式。

音视频 — PCM 转 WAV_第1张图片

这个结构图整体分成了3部分

RIFF部分:

ChunkID 存储了“RIFF”字段,表示这是一个“RIFF”格式的文件。
ChunkSize 记录整个wav文件的字节数
Format 存储了“WAVE”字段,表示这是一个wav文件。

fmt部分:

Subchunk1 ID 存储了“fmt”字段
Subchunk1 Size 存储“fmt”字段的长度
AudioFormat 表示Data区块存储的音频数据的格式,PCM音频数据的值为1
Num Channels 存储声道数,1:单声道,2:双声道
SampleRate 音频采样采样率
ByteRate 存储比特率 SampleRate *NumChannels * BitsPerSample/8
BlockAlign 每个采样所需的字节数 = NumChannels * BitsPerSample / 8
BitsPerSample 每个采样存储的bit数,8:8bit,16:16bit,32:32bit

data:

Subchunk2 ID 存储data字段
Subchunk2 Size 语音数据的长度

转换

WAV = PCM + 文件头
根据上面点结构图,和公式我们就能转换了, 标准模板如下


        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalWavSize & 0xff);//数据大小
        header[5] = (byte) ((totalWavSize >> 8) & 0xff);
        header[6] = (byte) ((totalWavSize >> 16) & 0xff);
        header[7] = (byte) ((totalWavSize >> 24) & 0xff);
        header[8] = 'W';//WAVE
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        //FMT Chunk
        header[12] = 'f'; // 'fmt '
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';//过渡字节
        //数据大小
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        //编码方式 10H为PCM编码格式
        header[20] = 1; // format = 1
        header[21] = 0;
        //通道数
        header[22] = (byte) channels;
        header[23] = 0;
        //采样率,每个通道的播放速度
        header[24] = (byte) (sampleRate & 0xff);
        header[25] = (byte) ((sampleRate >> 8) & 0xff);
        header[26] = (byte) ((sampleRate >> 16) & 0xff);
        header[27] = (byte) ((sampleRate >> 24) & 0xff);
        //音频数据传送速率,采样率*通道数*采样深度/8
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        // 确定系统一次要处理多少个这样字节的数据,确定缓冲区,通道数*采样位数
        header[32] = (byte) (channels * 16 / 8);
        header[33] = 0;
        //每个样本的数据位数
        header[34] = 16;
        header[35] = 0;
        //Data chunk
        header[36] = 'd';//data
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalPcmSize & 0xff);
        header[41] = (byte) ((totalPcmSize >> 8) & 0xff);
        header[42] = (byte) ((totalPcmSize >> 16) & 0xff);
        header[43] = (byte) ((totalPcmSize >> 24) & 0xff);
        os.write(header, 0, 44);

转换文件头的模版,跟上面的结构图一样,是按顺序的,值就是上面概念中提到的,按顺序写就可以了,其中:
totalWavSize: 总wav的文件大小
byteRate: 音频数据传送速率,采样率通道数采样深度/8
上一篇文章的代码有定义
long byteRate = SAMPLE_RATE_INHZ * CHANNEL_CONFIG * ENCODING_FORMAT / 8;
totalPcmSize:PCM的大小
有了文件头和PCM数据之后就可以开始合成了,还是通过流来操作,关键代码:

long byteRate = SAMPLE_RATE_INHZ * CHANNEL_CONFIG * ENCODING_FORMAT / 8;
 WavHeader.WavHeader(mOutStream, totalPcmSize, totalWavSize, Config.SAMPLE_RATE_INHZ,
                    Config.CHANNEL_CONFIG, byteRate);

            int length = 0;
            while ((length = mInputStream.read(mBuffer)) > 0) {
                mOutStream.write(mBuffer, 0, length);
            }

至此,PCM就转换成WAV文件了
Demo:https://github.com/wubobo952/LearnAudio

你可能感兴趣的:(音视频 — PCM 转 WAV)