解码aac,并生成wav文件

小程在讲多媒体的编码格式时,详细介绍过pcm跟aac等概念。简单来说,pcm是没有压缩的数字信号,可以直接用于音频输出,而aac则是一种音频编码格式,需要解码后才能用于音频输出。

aac编码格式,已经是一种很常见的音频编码格式,硬件设备(比如电脑芯片、手机、其它终端设备)都集成了aac的解码功能,而且有些系统还提供了调用硬件解码的接口,比如iOS上的AudioConverterRef接口、Android上的MediaCodec接口等。

从性能的角度,使用硬件解码是最佳选择,但如果从通用的角度,使用软件解码(相当于写个程序)是最佳的选择。这一次,小程介绍的是音频的软解码。

本文讲解使用fadd,把aac音频解码成pcm数据,并以wav来封装。

对于aac的软解码,使用FFmpeg也是一个选择,但如果只为了解码aac而用FFmpeg,就有点大材小用了,而且要应对比较复杂的接口调用,另外FFmpeg体积也比较大(即便裁剪后可以使FFmpeg编译出来的库小很多),那么,是否有更加简单一点的解码库可以使用呢?

这个开源库就是faad。

接下来,小程介绍使用faad来解码aac,并生成wav文件的流程。

(1)下载faad

git clone git://git.code.sf.net/p/faac/faad2 faac-faad2

文件结构大概是这样的:

这个开源项目,似乎一直有维护与更新:

(2)编译faad

执行以下指令,生成configure配置文件,以及makefile编译脚本,然后,再make出faad的库文件。

aclocal
autoconf
autoheader
libtoolize --force
automake --add-missing
./configure
make

由于只考虑在macos上运行,而且是在mac系统上编译,所以confiure时并不需要指定特定的参数。

以上命令,使用automake来生成编译脚本(makefile),如果读者发现这类指令执行不了,那有可能还没有正确安装,可以查阅相关的知识,也可以参考以下的内容,这是小程在网上摘录到的内容(小程使用的是macos):



====install autoconf and automake(摘录)

curl -O http://mirrors.kernel.org/gnu/m4/m4-1.4.13.tar.gz
tar -xzvf m4-1.4.13.tar.gz
cd m4-1.4.13
./configure --prefix=/usr/local
make
sudo make install
cd ..
curl -O http://mirrors.kernel.org/gnu/autoconf/autoconf-2.65.tar.gz
tar -xzvf autoconf-2.65.tar.gz
cd autoconf-2.65
./configure --prefix=/usr/local # ironic, isn‘t it?
make
sudo make install
cd ..
# here you might want to restart your terminal session, to ensure the new autoconf is picked up and used in the rest of the script
curl -O http://mirrors.kernel.org/gnu/automake/automake-1.11.tar.gz
tar xzvf automake-1.11.tar.gz
cd automake-1.11
./configure --prefix=/usr/local
make
sudo make install
cd ..
curl -O http://mirrors.kernel.org/gnu/libtool/libtool-2.2.6b.tar.gz
tar xzvf libtool-2.2.6b.tar.gz
cd libtool-2.2.6b
./configure --prefix=/usr/local
make
sudo make install



最终,生成faad库文件:

通过lipo来查看库文件支持的指令集:

(3)调用faad

这里演示一下,把一个aac文件解码成pcm数据,并用wav容器来封装。

demo的文件结构:

demo的代码:

#include "libfaad/include/faad.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct WavFileHeader
{
    char        id[4];          // should always contain "RIFF"
    int     totallength;    // total file length minus 8
    char        wavefmt[8];     // should be "WAVEfmt "
    int     format;         // 16 for PCM format
    short     pcm;            // 1 for PCM format
    short     channels;       // channels
    int     frequency;      // sampling frequency
    int     bytes_per_second;
    short     bytes_by_capture;
    short     bits_per_sample;
    char        data[4];        // should always contain "data"
    int     bytes_in_data;
};
void write_wav_header(FILE* file, int totalsamcnt_per_channel, int samplerate, int channels){
    struct WavFileHeader filler;
    strcpy(filler.id, "RIFF");
    filler.bits_per_sample = 16;
    filler.totallength = (totalsamcnt_per_channel * channels * filler.bits_per_sample/8) + sizeof(filler) - 8; //81956
    strcpy(filler.wavefmt, "WAVEfmt ");
    filler.format = 16;
    filler.pcm = 1;
    filler.channels = channels;
    filler.frequency = samplerate;
    filler.bytes_per_second = filler.channels * filler.frequency * filler.bits_per_sample/8;
    filler.bytes_by_capture = filler.channels*filler.bits_per_sample/8;
    filler.bytes_in_data = totalsamcnt_per_channel * filler.channels * filler.bits_per_sample/8;
    strcpy(filler.data, "data");
    fwrite(&filler, 1, sizeof(filler), file);
}

int main(int argc, char *argv[])
{
    printf("hello faad\n");
    NeAACDecHandle faadhandle = NeAACDecOpen();
    if (faadhandle) {
        printf("aacopen ok\n");
        const char* aacfile = "aac20s.aac";
        FILE* file = fopen(aacfile, "rb");
        if (file) {
            printf("fopen aac ok\n");
            fseek(file, 0, SEEK_END);
            long filelen = ftell(file);
            fseek(file, 0, SEEK_SET);
            unsigned char* filebuf = (unsigned char*)malloc(filelen);
            int len = fread(filebuf, 1, filelen, file);
            fclose(file);
            unsigned long samplerate = 0;
            unsigned char channel = 0;
            int ret = NeAACDecInit(faadhandle, filebuf, len, &samplerate, &channel);
            if (ret >= 0) {
                printf("aacinit ok: sam=%lu, chn=%d\n", samplerate, channel);
                NeAACDecFrameInfo frameinfo;
                unsigned char* curbyte = filebuf;
                unsigned long leftsize = len;
                const char* wavename = "out.wav";
                FILE* wavfile = fopen(wavename, "wb");
                if (wavfile) {
                    int wavheadsize = sizeof(struct WavFileHeader);
                    fseek(wavfile, wavheadsize, SEEK_SET);
                    int totalsmp_per_chl = 0;
                    void* out = NULL;
                    while (out = NeAACDecDecode(faadhandle, &frameinfo, curbyte, leftsize)) {
                        printf("decode one frame ok: sam:%ld, chn=%d, samplecount=%ld, obj_type=%d, header_type=%d, consumed=%ld\n",
                                frameinfo.samplerate, frameinfo.channels, frameinfo.samples, frameinfo.object_type,
                                frameinfo.header_type, frameinfo.bytesconsumed);
                        curbyte += frameinfo.bytesconsumed;
                        leftsize -= frameinfo.bytesconsumed;
                        fwrite(out, 1, frameinfo.samples*2, wavfile); // frameinfo.samples是所有声道数的样本总和;16bit位深
                        totalsmp_per_chl += frameinfo.samples / frameinfo.channels;
                    }
                    printf("aac decode done, totalsmp_per_chl=%d\n", totalsmp_per_chl);
                    fseek(wavfile, 0, SEEK_SET);
                    write_wav_header(wavfile, totalsmp_per_chl, (int)samplerate, (int)channel);
                    fclose(wavfile);
                }
            }
            free(filebuf);
        }
        NeAACDecClose(faadhandle);
    }
    return 0;
}

以上代码保存到aac2pcm.c文件,然后,makefile编译文件可以这样写(或者直接用gcc来编译):

out=aac2pcm
obj=aac2pcm.c

$(out):$(obj)
    gcc -o $(out) $(obj) -lfaad -L./libfaad
clean:
    rm -rf $(out) *.o

执行这个程序,部分输出:

最后的输出:

(4)pcm数据观察

与FFmpeg的解码作一个对比。

可以使用ffmpeg命令来解码一个aac文件:

ffmpeg -i aac20s.aac out_ff.wav

可以看到,faad与FFmpeg解码出来的wav文件的大小,有一点差别:

使用Audition,来对比FFmpeg与faad解码后的pcm数据:

基本看不出差别。

至此,使用fadd来解码的流程就介绍完毕了。另外,对于aac的编码,可以使用faac或fdk-aac、neroaac,或硬编等,这些小程以后再作介绍。



总结一下,本文介绍了如何通过fadd来解码aac格式的音频文件,并生成wav文件。其中,介绍了faad的编译,操作的难度系数为2(考虑到有automake的使用),然后介绍了写代码调用fadd的接口,并把解码后的数据,保存到wav的文件容器中,操作的难度系数为3。



解码aac,并生成wav文件

原文地址:http://blog.51cto.com/13136504/2084647

时间: 2024-11-12 23:08:13

解码aac,并生成wav文件的相关文章

Qt由pcm数据生成wav文件

void AudioGrabber::saveWave(const QString &fileName, const QByteArray &raw, const QAudioFormat &format){    typedef struct{        char riff_fileid[4];//"RIFF"        DWORD riff_fileLen;        char waveid[4];//"WAVE"      

C++生成简单WAV文件(二)

既然生成声音已经没问题了,现在简单生成一下一个类似蜂鸣器的随机音乐文件.(注:可能书写有格式不正式之类问题,反正思路应该没问题,测试可以运行) 因为是随机,那么先弄个产生随机数的类 R.H和R.CPP R.H: #ifndef R_H_ #define R_H_ class R{ public: R(); int suiji(int i); int suiji(); private: int shuchu(int number); }; #endif /* R_H_ */ R.cpp: #inc

C++生成简单WAV文件(三)——根据简谱生成菊花台

上一次已经可以生成随机的音乐,要从单调的声音变成音乐,最简单的是模仿,那么先根据菊花台的简谱整一个吧.简谱是网上找的.为了简单,乐曲只生成中间一段. 写头文件没变,依然是:Head.h,Head.cpp,因为不需要随机产生音符,那么随机数那个就不用了. Head.h: #ifndef HEAD_H_ #define HEAD_H_ class Head{ public: Head(); void setsize(int); long int getsa(); long int getsize()

C++生成简单WAV文件(一)

有了WAV头文件的格式,要生成一个WAV格式的声音文件就比较简单了,只要将头文件输出,在简单生成一点内容就可以了.为了简单,就生成一个单声道,11025HZ的,长度一秒的声音文件. 那么开做,要生成一个文件,那么文件的输出流<fstream>肯定要用到,参考了一下资料,简单整了如下的一个程序: #include <iostream> #include<fstream> //文件输出 #include<math.h> //主要生产波形使用SIN函数,所以弄了这

Android 音视频深入 九 FFmpeg解码视频生成yuv文件(附源码下载)

项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8%BD%ACyuv%EF%BC%89 这一次是将MP4解码出yuv文件出来,先介绍一波yuv文件 YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大.YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很多种

使用FAAD库解码AAC实例及 及 faad解码后的通道数不正确的问题

使用FAAD解码AAC音频为PCM数据流程可以参考下面的文章 http://blog.csdn.net/gavinr/article/details/6959198#reply /** * faaddec.c * use faad library to decode AAC, only can decode frame with ADTS head */ #include <stdio.h> #include <memory.h> #include "faad.h&quo

Android中如何提取和生成mp4文件

随着Android 4.4及以上版本的逐渐普及,Android 4.1引入的MediaExtractor类,以及Android 4.3引入的MediaMuxer类,终于可以开始正式地"发光发热"了. MediaMuxer类主要用于将音频和视频数据进行混合生成多媒体文件(如:mp4文件),而MediaExtractor则刚好相反,主要用于多媒体文件的音视频数据的分离. 本文将介绍如何利用Android SDK提供的MediaExtractor和MediaMuxer类来完成mp4文件的提取

Python解析Wav文件并绘制波形的方法

资源下载 #本文PDF版下载 Python解析Wav文件并绘制波形的方法 #本文代码下载 Wav波形绘图代码 #本文实例音频文件night.wav下载 音频文件下载 (石进-夜的钢琴曲) 前言 在现在繁忙的生活中,我们经常会听些歌来放松一下自己,我们经常会从各种播放软件中听自己喜欢的歌,并且往往我们会下载一部分歌曲,而现在音频的种类也相当繁多,像是Wav,Mp3,FLAC,AAC等等很多格式,最近由于需要做一个能够分析Wav格式音频的波形来取得一些数据比如获取人录音时是否说完等等用途.本周先对解

asp.net使用SpeechSynthesizer类生成语音文件部署到iis遇到的几个坑

首先需要引入命名空间System.Speech.Synthesis,代码如下: using (var speechSyn = new SpeechSynthesizer()) { speechSyn.Volume = 60;//语速 speechSyn.Rate = -2;//音量 speechSyn.SetOutputToDefaultAudioDevice(); speechSyn.SetOutputToWaveFile(fullFileName);//"D:\\Record.wav&quo