通过ffmpeg将aac格式转换成wav格式

http://blog.csdn.net/ajaxhe/article/details/6761678

这是一个很简单的小程序,但也让我这个初学者折腾了好几天,走算是入门了,总结下学习的过程,希望能够初学者能有所帮助。

看源代码,首先得让让它跑起来。看了ffmpeg提供源码api-example.c,很好的入门程序,虽然对视频编解码十分顺利,但是源码提供的音频解码是有问题的,mp2文件不能正常的解码,这是很让人沮丧,特别是对一个初学者来说。

在对源程序进行单步调试的过程中,问题定位在了这个语句上:

  1. avcodec_decode_audio3(in_ast_cctx, (int16_t *)outbuf, &out_size, &packet);  
再看前面看看,有这样两行语句。
  1. /* decode until eof */  
  2.     avpkt.data = inbuf;  
  3.     avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);  
这两行代码的意思很明确,就是将待解码数据数据放入avpkt.data这个缓冲区中,通过avcodec_decode_audio3对其进行解码。这些看起来都很合理,但问题出在哪里呢?

且看video_decode_example函数中这段话:

  1. /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)  
  2.            and this is the only method to use them because you cannot  
  3.            know the compressed data size before analysing it.  
  4.   
  5.            BUT some other codecs (msmpeg4, mpeg4) are inherently frame  
  6.            based, so you must call them with all the data for one  
  7.            frame exactly. You must also initialize 'width' and  
  8.            'height' before initializing them. */  
  9.   
  10.         /* NOTE2: some codecs allow the raw parameters (frame size,  
  11.            sample rate) to be changed at any frame. We handle this, so  
  12.            you should also take care of it */  
  13.   
  14.         /* here, we use a stream based decoder (mpeg1video), so we  
  15.            feed decoder and see if it could decode a frame */  
这句话看起来与我们的音频解码没有任何关系,但”codecs are stream based“和“frame based”,却给我们很好的提示,很显然,ffmpeg提供的AAC decoder是基于帧解码的,我们在给avpkt.data缓冲区的填充的数据应该是一个完整的音频帧,不多也不少,而不是简单的一次从文件中fread AUDIO_INBUF_SIZE大小的数据。

问题已经很明朗了,通过在填充avpkt.data之前,需要进行一个预处理,即通过AAC帧中的同步字(帧头的12bit--0xFFF)来找出完整的一帧。
那就写预处理程序吧,转念一想,ffmpeg这么多行代码,不提供AAC帧解析的API也没有天理了,继续google,找到了下面一篇文章:

http://hi.baidu.com/wg_wang/blog/item/8e7e321796063a0c4b90a770.html

http://hi.baidu.com/wg_wang/blog/item/f78216f35465655d342acc16.html

http://hi.baidu.com/wg_wang/blog/item/4d55bd23eb3e2d49ac34de17.html

文章的标题是:利用libavcodec和libavformat对音频转码。附上了很详细的代码解析,我写的源程序大部分基于该文章。

下面就是test.c文件中的源码

  1. #include <stdio.h>  
  2.   
  3. #include "libavformat/avformat.h"  
  4. #include "libavcodec/avcodec.h"  
  5. #include "audio.h"  
  6. #include "neaacdec.h"  
  7.   
  8. int main(int argc, char **argv)  
  9. {  
  10.     AVFormatContext *in_fctx;  
  11.     AVCodecContext *in_ast_cctx;  
  12.     AVCodec *in_ast_codec;  
  13.     AVPacket packet;  
  14.     audio_file *aufile;  
  15.     char *outbuf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);  
  16.     int out_size;  
  17.     int samples;  
  18.   
  19.     //char *filename = "C:\\Users\\ajaxhe\\Desktop\\AudioCodec\\ffmpeg\\MyProject\\output_example2\\Debug\\higher1.aac";  
  20.     char *filename;  
  21.     char *wavfile = "debug_test.wav";  
  22.     //char *wavfile;  
  23.     int ret = 0;  
  24.     int ast_idx = -1;  
  25.     int i, first_time = 1;  
  26.   
  27.     if (argc == 3){  
  28.         filename = argv[1];  
  29.         wavfile = argv[2];  
  30.     }  
  31.     else{  
  32.         printf("usage: output_example.exe infile.aac outfile.aac\n");  
  33.         return -1;  
  34.     }  
  35.   
  36.     av_register_all();  
  37.     in_fctx = av_alloc_format_context();  
  38.   
  39.     ret = av_open_input_file(&in_fctx, filename, NULL, 0, NULL);  
  40.     if ( ret != 0 ){  
  41.         printf("open input audio file[%s] fail", filename);  
  42.         return -1;  
  43.     }  
  44.   
  45.     ret = av_find_stream_info(in_fctx);  
  46.     if ( ret < 0 ){  
  47.         printf("find stream in audio file[%s] fail", filename);  
  48.         return -1;  
  49.     }  
  50.   
  51.     //dump_format(in_fctx, 0, filename, 0);  
  52.     //这里我们假设,如果一个文件包含多个音频流,  
  53.     //只对第一个音频流做转码,而对于视频流则忽略  
  54.     for (i=0; i<(int)in_fctx->nb_streams; ++i){  
  55.         if (in_fctx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO){  
  56.             ast_idx=i;  
  57.             break;  
  58.         }  
  59.     }  
  60.     if (ast_idx == -1){  
  61.         printf("there is not any audio stream in [%s]", filename);  
  62.         return 0;  
  63.     }  
  64.     else{  
  65.         printf("find audio stream in [%s]\n", filename);  
  66.     }  
  67.   
  68.     in_ast_cctx = in_fctx->streams[ast_idx]->codec;  
  69.     in_ast_codec = avcodec_find_decoder(in_ast_cctx->codec_id);  
  70.     if (!in_ast_codec){  
  71.         printf("find decoder for codec_id[%d] fail, file[%s]", in_ast_cctx->codec_id, filename);  
  72.         return -1;  
  73.     }  
  74.   
  75.     ret = avcodec_open(in_ast_cctx, in_ast_codec);  
  76.     if (ret >= 0){  
  77.         printf("open codec[name:%s] for stream[idx:%d] of file[%s]\n", in_ast_codec->name, ast_idx, filename);  
  78.     }  
  79.   
  80.     av_init_packet(&packet);  
  81.     while (av_read_frame(in_fctx, &packet) >= 0){  
  82.         out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;  
  83.         ret = avcodec_decode_audio3(in_ast_cctx, (int16_t *)outbuf, &out_size, &packet);  
  84.         if (first_time){  
  85.             aufile = open_audio_file(wavfile, in_ast_cctx->sample_rate, in_ast_cctx->channels, FAAD_FMT_16BIT, OUTPUT_WAV, 0);  
  86.             first_time = 0;  
  87.         }  
  88.         samples = in_ast_cctx->frame_size * in_ast_cctx->channels;  
  89.         write_audio_file(aufile, outbuf, samples, 0);  
  90.     }  
  91.   
  92.     if (!first_time)  
  93.         close_audio_file(aufile);  
  94.       
  95.     avcodec_close(in_ast_cctx);  
  96.     av_free(in_ast_cctx);  
  97.   
  98.     return 0;  
  99. }  
由于仅仅是一个简单的小程序,只写了个main函数,还请见谅。

#include "audio.h"
#include "neaacdec.h"

这两个头文件是我从faad2源代码中弄过来,时间仓促,没有来得及自己整理下,需要的整个工程朋友就直接从下面这个链接下载吧

http://download.csdn.net/detail/ajaxhe/3585763

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值