音视频---------pcm16le转wav

本篇记录了学习雷霄骅的pcm16le转wav代码后,为其添加了注释和自己的理解,方便以后自己阅读。

可能用到的基础知识:

           音视频--------pcm数据入门知识

           帧、采样率、Hz、比特率

           pcm-------原始的音频数据,windows没法直接播放,因为不知道这是什么。

           WAVE格式音频(扩展名为“.wav”)是Windows系统中最常见的一种音频。该格式的实质就是在PCM文件的前面加了一个             文件头。


//本程序的函数就可以通过在PCM16le文件前面加一个WAVE文件头从而封装为WAVE格式音频。
int simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,const char *wavepath)
{
	typedef struct WAVE_HEADER{
		char fccID[4]; //RIFF
		//wav整个文件大小
		unsigned long dwSize;
		char fccType[4]; //WAVE
	}WAVE_HEADER;

	typedef struct WAVE_FMT{
		char  fccID[4]; //"fmt ",注意后面有一个空过渡字节‘ ’
		//WAVE_FMT的字节字段长度减去fccID和dwSize的字节长度
		unsigned long dwSize; //sizeof(WAVE_FMT)-sizeof(fccID)-sizeof(dwSize)
		//音频格式
		unsigned short audioFormat;//表示Data区块存储的音频数据的格式,PCM音频数据的值为1
		//声道
		unsigned short wChannels;
		//采样率
		unsigned long sampleRate;
		//比特率
		unsigned long byteRate;//存储比特率 SampleRate *NumChannels * BitsPerSample/8
		//块对齐
		unsigned short wBlockAlign; //每次采样所需的字节数 = NumChannels * BitsPerSample / 8
		//每次采样的bit数-----位深度
		unsigned short bitsPerSample;
	}WAVE_FMT;

	typedef struct WAVE_DATA{
		char       fccID[4];//data
		// wave 数据大小,这个例子即使pcm的大小
		unsigned long dwSize;
	}WAVE_DATA;


	if(channels==0||sample_rate==0){
		channels = 2;
		sample_rate = 44100;
	}
	int bits = 16;

    WAVE_HEADER pcmHEADER;
    WAVE_FMT pcmFMT;
    WAVE_DATA pcmDATA;

	//一次采样数据
    unsigned short m_pcmData;
    FILE *fp,*fpout;

	fp=fopen(pcmpath,"rb+");
    if(fp == NULL) {
        printf("Open pcm file error\n");
        return -1;
    }
	fpout=fopen(wavepath,"wb+");
    if(fpout == NULL) {
        printf("Create wav file error\n");
        return -1;
    }
	//WAVE_HEADER
    memcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));
    memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));
	//先跳过WAVE_HEADER的存储位置不写,因为还不知道WAVE_HEADER.dwSize的值(整个文件的大小)
    fseek(fpout,sizeof(WAVE_HEADER),1);
	//WAVE_FMT
    pcmFMT.sampleRate=sample_rate;
    pcmFMT.byteRate=pcmFMT.sampleRate*16*2/8;
    pcmFMT.bitsPerSample=bits;
    memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));
    pcmFMT.dwSize=16;
	pcmFMT.wBlockAlign = 16 * 2 / 8;
    pcmFMT.wChannels=channels;
    pcmFMT.audioFormat=1;

	//写WAVE_FMT
    fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout);

    //WAVE_DATA;
    memcpy(pcmDATA.fccID,"data",strlen("data"));
    pcmDATA.dwSize=0;
	//跳过WAVE_DATA不写,等知道了WAVE_DATA.dwSize再写
    fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);

    fread(&m_pcmData,sizeof(unsigned short),1,fp);
    while(!feof(fp)){
		//最终获得pcm的大小
        pcmDATA.dwSize+=2;
		//向文件尾部写pcm数据
        fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
        fread(&m_pcmData,sizeof(unsigned short),1,fp);
    }

	//计算出整个文件的大小
	pcmHEADER.dwSize = sizeof(WAVE_HEADER)+sizeof(WAVE_FMT)+sizeof(WAVE_DATA)+pcmDATA.dwSize;

	//设置文件位置为给定流 stream 的文件的开头
    rewind(fpout);
	//写WAVE_HEADER
    fwrite(&pcmHEADER,sizeof(WAVE_HEADER),1,fpout);
	//WAVE_FMT已经写过了,跳过
    fseek(fpout,sizeof(WAVE_FMT),SEEK_CUR);
	//写WAVE_DATA
    fwrite(&pcmDATA,sizeof(WAVE_DATA),1,fpout);
	
	fclose(fp);
    fclose(fpout);
	system("pause");
    return 0;
}

添加的头文件


        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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值