怎么得到pcm编码的wav音频 PCM音频数据封装为WAV文件
PCM(Pulse Code Modulation,脉冲编码调制),PCM音频数据是指经过采样、量化、编码转换成的未压缩数字音频数据。
WAV最常见的声音文件格式之一,是微软公司专门为Windows开发的一种标准数字音频文件,该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。
WAV格式组成
RIFF(Resource Interchange File Format,资源交换档案标准),是一种把资料储存在被标记的区块(tagged chunks)中的档案格式(meta-format),不同编码的音频/视频流按照RIFF所定义的存储规则保存,在读取播放时,就可以按照RIFF规则分析文件,正常解析出音频/视频流。
示例代码
按照上述定义,声明如下数据结构
C 音视频开发学习资料:点击领取→音视频开发(资料文档 视频教程 面试题)(FFmpeg WebRTC RTMP RTSP HLS RTP)
struct RIFF_t {
char ID[4];
uint32_t size;
char format[4];
};
struct FMT_t {
char ID[4];
uint32_t size;
uint16_t audio_format;
uint16_t channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
};
struct DATA_t {
char ID[4];
uint32_t size;
//void *data; //此处因为数据需要从文件中边读取边存储,因此为了方便操作,不声明data
};
struct PCM_to_WAV_t {
char *in_file_name;
char *out_file_name;
FILE *in_file;
FILE *out_file;
uint16_t pcm_data; //保存从PCM文件中读取的数据,因为PCM数据大小必然是16的倍数,所以声明为uint16_t
struct RIFF_t riff;
struct FMT_t fmt;
struct DATA_t data;
};
- 初始化操作
int PCM_to_WAV_Init(PCM_to_WAV_t *p2w, int argc, char** argv)
{
if (argc == 3) {
p2w->in_file_name = argv[1];
p2w->fmt.sample_rate = 44100;
p2w->fmt.channels = 2;
p2w->fmt.bits_per_sample = 16;
p2w->out_file_name = argv[2];
} else if (argc == 6) {
p2w->in_file_name = argv[1];
p2w->fmt.sample_rate = atoi(argv[2]);
p2w->fmt.channels = atoi(argv[3]);
p2w->fmt.bits_per_sample = atoi(argv[4]);
p2w->out_file_name = argv[5];
} else {
printf("$.exe $.pcm $sample_rate $channels $bits_per_sample $.wav\n");
printf("Example: $.exe in.pcm 44100 2 16 out.wav\n");
printf("$.exe $.pcm $.wav\n");
printf("Example: $.exe in.pcm out.wav\n");
return -1;
}
p2w->pcm_data = 0;
p2w->in_file = NULL;
p2w->out_file = NULL;
memcpy(p2w->riff.ID, "RIFF", 4);
memcpy(p2w->riff.format, "WAVE", 4);
p2w->riff.size = 36;
memcpy(p2w->fmt.ID, "fmt ", 4);
p2w->fmt.size = 16;
p2w->fmt.audio_format = 1;
p2w->fmt.byte_rate = p2w->fmt.sample_rate * p2w->fmt.channels * p2w->fmt.bits_per_sample / 8;
p2w->fmt.block_align = p2w->fmt.channels * p2w->fmt.bits_per_sample / 8;
memcpy(p2w->data.ID, "data", 4);
p2w->data.size = 0;
return 0;
}
- 转换过程
int PCM_to_WAV(PCM_to_WAV_t *p2w)
{
p2w->in_file = fopen(p2w->in_file_name, "rb ");
p2w->out_file = fopen(p2w->out_file_name, "wb ");
if (p2w->in_file == NULL || p2w->out_file == NULL) {
printf("open file error\n");
return -1;
}
fseek(p2w->out_file, sizeof(struct RIFF_t), 1);
fwrite(&p2w->fmt, sizeof(struct FMT_t), 1, p2w->out_file);
fseek(p2w->out_file, sizeof(struct DATA_t), 1);
fread(&p2w->pcm_data, sizeof(uint16_t), 1, p2w->in_file);
while (! feof(p2w->in_file) ) {
p2w->data.size = 2;
fwrite(&p2w->pcm_data, sizeof(uint16_t), 1, p2w->out_file);
fread(&p2w->pcm_data, sizeof(uint16_t), 1, p2w->in_file);
}
p2w->riff.size = p2w->data.size;
rewind(p2w->out_file);
fwrite(&p2w->riff, sizeof(struct RIFF_t), 1, p2w->out_file);
fseek(p2w->out_file, sizeof(struct FMT_t), 1);
fwrite(&p2w->data, sizeof(struct DATA_t), 1, p2w->out_file);
fclose(p2w->in_file);
fclose(p2w->out_file);
return 0;
}
- 打印块信息
C 音视频开发学习资料:点击领取→音视频开发(资料文档 视频教程 面试题)(FFmpeg WebRTC RTMP RTSP HLS RTP)
void PCM_to_WAV_Info(PCM_to_WAV_t *p2w)
{
printf("in file: %s\nout file: %s\n", p2w->in_file_name, p2w->out_file_name);
printf("RIFF: \n\tID: %4.4s\n\tsize: %d\n\tformat: %4.4s\n",
p2w->riff.ID, p2w->riff.size, p2w->riff.format);
printf("FMT: \n\tID: %4.4s\n\tSize: %d\n\tAudio fmt: %d\n\tChannels: %d\n",
p2w->fmt.ID, p2w->fmt.size, p2w->fmt.audio_format, p2w->fmt.channels);
printf("\tsample rate: %d\n\tByte Rate: %d\n\tBlock Align: %d\n\tBits Per Sample: %d\n",
p2w->fmt.sample_rate, p2w->fmt.byte_rate, p2w->fmt.block_align, p2w->fmt.bits_per_sample);
printf("DATA: \n\tID: %4.4s\n\tSize: %d\n", p2w->data.ID, p2w->data.size);
}
- 调用
int main(int argc, char **argv)
{
struct PCM_to_WAV_t pcm2wav;
if (PCM_to_WAV_Init(&pcm2wav, argc, argv) != 0)
return -1;
if (PCM_to_WAV(&pcm2wav) != 0)
return -1;
PCM_to_WAV_Info(&pcm2wav);
return 0;
}
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com