美文网首页
音视频 — PCM 转 WAV

音视频 — PCM 转 WAV

作者: 波波维奇c | 来源:发表于2019-06-20 00:36 被阅读0次

    不懂 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存储原声带的,是一种无损的音频文件格式。

    这个结构图整体分成了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

          本文链接:https://www.haomeiwen.com/subject/qcprfqtx.html