音视频编程: iOS 使用 faad2
最近在看人工智能相关的知识,无意中发现了一个巨牛的 人工智能教程,分享一下给大家。
教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点 这里 可以直接看教程。
简介
本次分享使用 faad2 解码 AAC 音频文件, 将 AAC 文件转换为 WAV 文件并使用 AVAudioPlayer 进行播放。
在博文 音视频编程: 简单分析 WAV 文件 给大家简单的分析了一下 WAV 的数据头协议, 其实也是为了这篇博文来服务的, 所以阅读本文之前, 建议先看上文。
该系列博文:
例子介绍
本文以一个实际的例子, 使用 faad2的各个函数来解码 AAC 数据.
主要有以下几个步骤:
- 获取输入文件
- 获取 faad 解码器句柄
- 初始化 faad 解码器
- 根据文件解析文件帧, 并写入输出文件中
- 写入文件头将其封装为 WAV 格式的音频文件
- 关闭 faad 解码器句柄
工程实战
引入 faad2
将编译好的 faad2 导入工程即可.
其中关键的 API 在 neaacdec.h 中有描述.
工程效果图:
编码实现
在 音视频编程: 简单分析 WAV 文件 中已经定义了 WAV 的数据头.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct MZWavAudioFileHeader { char riff[4]; uint32_t totalLength; char wave[4]; char fmt[4]; uint32_t format; uint16_t pcm; uint16_t channels; uint32_t frequency; uint32_t bytes_per_second; uint16_t bytes_by_capture; uint16_t bits_per_sample; char data[4]; uint32_t bytes_in_pcmdata; };
|
现在实现写入数据头的方法 mz_write_wav_header
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
void mz_write_wav_header(FILE *file, int total_samples_per_channel, int samplerate, int channels) { if (NULL == file) { return; } if (total_samples_per_channel <= 0) { return; } printf("FAAD. total_samples_per_channel: %i, samplerate: %i, channels: %i\n", total_samples_per_channel, samplerate, channels); struct MZWavAudioFileHeader wavHeader; strcpy(wavHeader.riff, "RIFF"); wavHeader.bits_per_sample = 16; wavHeader.totalLength = (total_samples_per_channel * channels * wavHeader.bits_per_sample/8) + sizeof(wavHeader) - 8; strcpy(wavHeader.wave, "WAVE"); strcpy(wavHeader.fmt, "fmt "); wavHeader.format = 16; wavHeader.pcm = 1; wavHeader.channels = channels; wavHeader.frequency = samplerate; wavHeader.bytes_per_second = wavHeader.channels * wavHeader.frequency * wavHeader.bits_per_sample/8; wavHeader.bytes_by_capture = wavHeader.channels*wavHeader.bits_per_sample/8; wavHeader.bytes_in_pcmdata = total_samples_per_channel * wavHeader.channels * wavHeader.bits_per_sample/8; strcpy(wavHeader.data, "data"); fwrite(&wavHeader, 1, sizeof(wavHeader), file); }
|
解码主要用到了 FAAD2 中的 NeAACDecDecode
函数. 函数原型如下:
1 2 3 4
| void* NEAACDECAPI NeAACDecDecode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo, unsigned char *buffer, unsigned long buffer_size);
|
对应帧定义的结构体: NeAACDecFrameInfo
, 定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| typedef struct NeAACDecFrameInfo { unsigned long bytesconsumed; unsigned long samples; unsigned char channels; unsigned char error; unsigned long samplerate;
unsigned char sbr;
unsigned char object_type;
unsigned char header_type;
unsigned char num_front_channels; unsigned char num_side_channels; unsigned char num_back_channels; unsigned char num_lfe_channels; unsigned char channel_position[64];
unsigned char ps; } NeAACDecFrameInfo;
|
具体的解码实现, 我放到了 Github 上面了, 大家可以去 这里 查看.
麻烦
解码 aac, 解决采样频率和通道数不对的问题
1 2 3 4
| NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); conf->dontUpSampleImplicitSBR = 1; NeAACDecSetConfiguration(decoder, conf);
|
1 2 3 4 5 6
| for(i=0,j=0; i<4096 && j<2048; i+=4, j+=2) {
frame_mono[j]=pcm_data[i]; frame_mono[j+1]=pcm_data[i+1]; }
|
具体可以查阅 FAAD2 的源码. 感谢 使用FAAD库解码AAC实例及 及 faad解码后的通道数不正确的问题 提供.