音视频 Day 09 PCM 转 WAV

2021-04-27  本文已影响0人  iOS的火影乱斗

1. 在 FFmpeg 的源码中,经常能看到 >>3 是什么意思?

2. 如何通过命名行得知录音设备的采样率声道数采样格式

Input #0, avfoundation, from ':0':
Duration: N/A, start: 87533.086750, bitrate: 256 kb/s
Stream #0:0: Audio: pcm_f32le, 8000 Hz, mono, flt, 256 kb/s

3. 如何在代码中获取录音设备的采样率声道数采样格式

4. RIFF 是什么?哪两个比较主流的音频格式是遵守 RIFF 的?

5. chunk 是什么意思?一个 chunk 由哪三部分组成?

6. 解剖 WVA 文件

// out.wav 的首部部分16 进制数据
00000000: 52 49 46 46 24 50 05 00 57 41 56 45 66 6D 74 20    RIFF$P..WAVEfmt.
00000010: 10 00 00 00 01 00 02 00 44 AC 00 00 10 B1 02 00    ........D,...1..
00000020: 04 00 10 00 64 61 74 61 00 50 05 00 00 00 0E BB    ....data.P.....;
52 49 46 46(ChunkID,4 字节) = ‘RIFF’

24 50 05 00 (ChunkSize,4 字节)=  348196  = 348204 - 8

57 41 56 45 (Format,4 字节) = ‘WAVE’

66 6D 74 20 (Subchunk1ID,4 字节) = ‘fmt ’

10 00 00 00 (Subchunk1 Size,4 字节) = 16

01 00(AudioFormate,2 字节) = 音频格式 = 1

02 00 (NumChannels,2 字节)= 声道数 = 2

44 AC 00 00(SampleRate,4 字节)= 采样率 = 44100

10 B1 02 00(ByteRate,4 字节)= 字节率 = 176400

04 00 (BlockAlign,2 字节)= 内存对齐 = 4

10 00 (BitsPerSample)= 每个样本的位深度 =  16

64 61 74 61(Subchunk2ID,4 字节) = ‘data’

00 50 05 00 (Subchunk2 Size,4 字节) = 音频PCM数据大小 = 348160 = 348204 - 44

有资料需求的可以了解下,有关于包括 数据结构、底层进阶、图形视觉、音视频、架构设计、逆向安防、RxSwift、flutter,算法等方面的资料,面试资料就在群文件里面可自行下载,891点击 488进入 181有什么问题也可以直接在里面提出来,互相交流,同时内有好友发内推机会,一起共同进步!

7. 需要理解的三幅图

WAV 文件格式 WAV 文件格式

8. 命令行实现 PCM 转 WAV

ffmpeg -ar 44100 -ac 2 -f s16le -i out.pcm -bitexact out2.wav

9. 代码实现 PCM 转 WAV

void FFmpegs::pcm2wav(WAVHeader &header, const char *pcmFilename, const char *wavFilename) {
 header.blockAlign = header.bitsPerSample * header.numChannels >> 3;
 header.byteRate = header.sampleRate * header.blockAlign;

 // 打开 pcm 文件
 QFile pcmFile(pcmFilename);
 if (!pcmFile.open(QFile::ReadOnly)) {
     qDebug() << "文件打开失败" << pcmFilename;
     return;
 }

 header.dataChunkDataSize = pcmFile.size();
 header.riffChunkDataSize = header.dataChunkDataSize
                            + sizeof (WAVHeader)
                            - sizeof (header.riffChunkId)
                            - sizeof (header.riffChunkDataSize);

 // 打开 wav 文件
 QFile wavFile(wavFilename);
 if (!wavFile.open(QFile::WriteOnly)) {
     qDebug() << "文件打开失败" << wavFilename;

     pcmFile.close();
     return;
 }

 // 写入头部
 wavFile.write((const char*)&header, sizeof(WAVHeader));

 // 写入 pcm 数据
 char buf[1024];
 int size;
 while ((size = pcmFile.read(buf, sizeof(buf))) > 0) {
     wavFile.write(buf, size);
 }

 // 关闭文件
 pcmFile.close();
 wavFile.close();
}
WAVHeader header;
header.sampleRate = 44100;
header.bitsPerSample = 16;
header.numChannels = 2;

FFmpegs::pcm2wav(header,
              "/Users/linsipei/Documents/ffmpeg_workspcace/05_tmp/in.pcm",
              "/Users/linsipei/Documents/ffmpeg_workspcace/05_tmp/out.wav");

10. 代码实现 录制的PCM 直接转 WAV(包含动态获取录音设备的相关信息操作)

// 获取输入流
AVStream *stream = ctx->streams[0];
// 获取音频参数
AVCodecParameters *params = stream->codecpar;

//pcm 转 wav 文件
WAVHeader header;
header.sampleRate = params->sample_rate;
header.bitsPerSample = av_get_bits_per_sample(params->codec_id);
header.numChannels = params->channels;
if (params->codec_id >= AV_CODEC_ID_PCM_F32BE) {
 header.audioFormat = AUDIO_FORMAT_FLOAT;
}
FFmpegs::pcm2wav(header, filename.toUtf8().data(), wavFilename.toUtf8().data());

作者:carrot__lsp
链接:https://juejin.cn/post/6955032831466684453

上一篇 下一篇

猜你喜欢

热点阅读