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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容