音视频数据处理入门:pcm转wav格式

将PCM16LE双声道采样数据转换成WAVE格式音频数据

wave格式(.wav), 是一种无损的音频文件格式, 所有的wav都有一个文件头, 这个文件头包含音频流的编码参数.

pcm文件前面加一个wave文件头, 可以封装为.wav格式音频.

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct wav_head {
    char fccID[4];          // 规范标识符,RIFF
    unsigned int dwSize;   
    char fccType[4];        // 格式,WAVE
} head_t;

typedef struct wav_fmt {
    char fccID[4];
    unsigned int dwSize;
    unsigned short wFormatTag;      // 编码格式
    unsigned short wChannels;       // 通道数
    unsigned int dwSamplesPerSec;   // 采样率
    unsigned int dwAvgBytesPerSec;  // 每秒码率
    unsigned short wBlockAgain;     // 对齐占位数据, 2-单声道,4-立体
    unsigned short uiBitsPerSample; // 采样精度
} fmt_t;

typedef struct wav_data {
    char fccID[4];
    unsigned int dwSize;
} data_t;

/* WAV音频格式文件结构
 * WAVE_HEAD
 * WAVE_FMT
 * WAVE_DATA
 * 原PCM数据
 */

// WAV文件头:head + fmt + data = 12 + 24 + 8 = 44 Bytes 
void pcm16le_to_wav(const char *file, int channels, int sample_rate, const char *wavfile) {
    if (channels == 0 || sample_rate == 0) {
        channels = 2; sample_rate = 44100;  // default
    }
    int bits = 16;

    head_t pcm_head;
    fmt_t pcm_fmt;
    data_t pcm_data;


    FILE *fp, *fpout;
    fp = fopen(file, "r");
    fpout = fopen(wavfile, "w+");
    
    // HEAD
    memcpy(pcm_head.fccID, "RIFF", 4);
    memcpy(pcm_head.fccType, "WAVE", 4);

    // FMT
    fseek(fpout, sizeof(head_t), SEEK_SET);
    pcm_fmt.dwSamplesPerSec = sample_rate;
    pcm_fmt.dwAvgBytesPerSec = sample_rate * 4; // 每次采样 = 2字节*2 
    pcm_fmt.uiBitsPerSample = bits;
    memcpy(pcm_fmt.fccID, "fmt ", 4);
    pcm_fmt.dwSize = 16;
    pcm_fmt.wBlockAgain = 4;        // 2-单声道 
    pcm_fmt.wChannels = channels;   // 声道数
    pcm_fmt.wFormatTag = 1;     // 标签,1表示PCM编码

    // 1. 填充head_msg
    fwrite(&pcm_fmt, sizeof(fmt_t), 1, fpout);
    
    // DATA
    fseek(fpout, sizeof(fmt_t), SEEK_CUR); // 偏移
    memcpy(pcm_data.fccID, "data", 4);
    pcm_data.dwSize = 0;

    
    char sample[4];
    while (!feof(fp)) {
        fread(sample, 4, 1, fp);
        pcm_data.dwSize += 4;
        fwrite(sample, 4, 1, fpout);
    }
    pcm_head.dwSize = 44 + pcm_data.dwSize; // wav文件头44字节,加上原音频数据
    
    // 2. 填充head_msg和data_msg
    rewind(fpout);
    fwrite(&pcm_head, sizeof(head_t), 1, fpout);
    fseek(fpout, sizeof(fmt_t), SEEK_CUR);
    fwrite(&pcm_data, sizeof(data_t), 1, fpout);

    fclose(fp);
    fclose(fpout);
}

int main(int argc, char const* argv[])
{
    pcm16le_to_wav("samples/test.pcm", 2, 44100, "output_wav.wav");    
    return 0;
}

测试:

image-20210420154349212

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值