windows下使用FFmpeg进行音频转换程序

http://www.verydemo.com/demo_c173_i168207.html


开发环境: windows 7

FFmpeg版本: 0.8 

FFmpeg windows下的动态链接库下载地址:

http://url.cn/IJJwo3

对于FFmpeg的版本,需要注意的是,旧的版本很多接口在新的版本中已经废弃,我的程序是在仅仅是针对FFmpeg-0.8版本。


支持的音频格式:
目前测试程序支持amr, wav(CodecID: GSM_MS), wav(PCM), 3gp, 3gpp, aac, mp3格式间的相互转换


以前有写过一个aac转wav的程序,工程文件可以直接下载的,初次在windows下使用FFmpeg的童鞋,就参考这篇文章提供的VS2008工程文件,进行配置FFmpeg库文件和头文件的配置,在这里我就不上传VS2008工程,直接附cpp。

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


音频测试文件下载地址:
http://url.cn/GXOAx5


  1. extern "C"{  
  2. #include "libavformat/avformat.h"  
  3. #include "libavcodec/avcodec.h"  
  4. #include "libavutil/fifo.h"  
  5. };  
  6.   
  7. #include <stdio.h>  
  8.   
  9. /* 单通道下,每个sample所占的字节数 
  10.     AV_SAMPLE_FMT_FLT = 4bytes 
  11.     AV_SAMPLE_FMT_S16 = 2bytes 
  12. */  
  13. static int g_in_bytes = 2;  
  14. static int g_out_bytes = 2;  
  15.   
  16. AVCodecContext* output_decode_init(AVCodecContext* in_cctx, AVFormatContext* out_fctx, int codec_id);  
  17. int output_decode_open(AVCodecContext* cc);  
  18.   
  19. int main()  
  20. {  
  21.     AVFormatContext* in_fctx;     
  22.     AVCodecContext* in_cctx;  
  23.     AVCodec* in_codec;  
  24.     const char* in_filename;  
  25.     const char* out_filename;  
  26.     char* decoded_buf;  
  27.     char* output_buf;  
  28.     char* resample_buf;  
  29.     char* before_encoding_buf;  
  30.     int ret = 0;  
  31.   
  32.     in_filename = "H:\\FileSample\\input\\input.aac";  
  33.     out_filename = "output/aac2mp3.mp3";  
  34.     decoded_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);  
  35.     output_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);  
  36.     resample_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);   
  37.     before_encoding_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);   
  38.   
  39.     avcodec_register_all();  
  40.     av_register_all();  
  41.   
  42.     in_fctx = avformat_alloc_context();  
  43.   
  44.     ret = av_open_input_file(&in_fctx, in_filename, NULL, 0, NULL);  
  45.     if ( ret != 0 )  
  46.     {  
  47.         printf("open input audio file[%s] fail\n", in_filename);  
  48.         return -1;  
  49.     }  
  50.   
  51.     ret = av_find_stream_info(in_fctx);  
  52.     if ( ret < 0 )  
  53.     {  
  54.         printf("find stream in audio file[%s] fail\n", in_filename);  
  55.         return -1;  
  56.     }  
  57.   
  58.     dump_format(in_fctx, 0, in_filename, 0);  
  59.   
  60.     //这里我们假设,如果一个文件包含多个<strong><strong>音频</strong></strong>流,  
  61.     //只对第一个<strong><strong>音频</strong></strong>流做转码,而对于视频流则忽略  
  62.     int i;  
  63.     int ast_index = -1;  
  64.     for (i = 0; i<(int)in_fctx->nb_streams; ++i)  
  65.     {  
  66.         if (in_fctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)  
  67.         {  
  68.             ast_index = i;  
  69.             break;  
  70.         }  
  71.     }  
  72.     if (ast_index == -1)  
  73.     {  
  74.         printf("there is not any audio stream in file[%s]\n", in_filename);  
  75.         return 0;  
  76.     }  
  77.     else  
  78.     {  
  79.         printf("find audio stream in file[%s]\n", in_filename);  
  80.     }  
  81.       
  82.     in_cctx = in_fctx->streams[ast_index]->codec;  
  83.     //in_cctx->codec_id = CODEC_ID_GSM;  
  84.     in_codec = avcodec_find_decoder(in_cctx->codec_id);  
  85.     if (!in_codec)  
  86.     {  
  87.         printf("find decoder for codec_id[%d] fail, file[%s]\n", in_cctx->codec_id, in_filename);  
  88.         return -1;  
  89.     }  
  90.     ret = avcodec_open(in_cctx, in_codec);  
  91.     if (ret >= 0)  
  92.     {  
  93.         printf("open codec[name:%s] for stream[idx:%d] of file[%s]\n", in_codec->name, ast_index, in_filename);  
  94.     }  
  95.   
  96.     // 输出部分初始化  
  97.     AVOutputFormat* out_fmt;  
  98.     AVFormatContext* out_fctx;  
  99.     AVCodecContext* out_cctx = NULL;  
  100.   
  101.     out_fmt = av_guess_format(NULL, out_filename, NULL);  
  102.     if (!out_fmt)  
  103.     {  
  104.         printf("Could not deduce output format from file extension: using MPEG-3.\n");  
  105.         out_fmt = av_guess_format("mp3", NULL, NULL);  
  106.     }  
  107.     if (!out_fmt)  
  108.     {  
  109.         fprintf(stderr, "Could not find suitable output format\n");  
  110.         exit(1);  
  111.     }  
  112.   
  113.     out_fctx = avformat_alloc_context();  
  114.     if (!out_fctx)  
  115.     {  
  116.         fprintf(stderr, "avformat_alloc_context fail\n");  
  117.         exit(1);  
  118.     }  
  119.     out_fctx->oformat = out_fmt;  
  120.   
  121.     out_cctx = output_decode_init(in_cctx, out_fctx, out_fmt->audio_codec);  
  122.     if (!out_cctx)  
  123.     {  
  124.         fprintf(stderr, "output_codec_init fail\n");  
  125.         exit(1);  
  126.     }  
  127.     /* set the output parameters (must be done even if no parameters). */  
  128.     if (av_set_parameters(out_fctx, NULL) < 0)   
  129.     {  
  130.         fprintf(stderr, "Invalid output format parameters\n");  
  131.         exit(1);  
  132.     }  
  133.     dump_format(out_fctx, 0, out_filename, 1);  
  134.   
  135.     output_decode_open(out_cctx);  
  136.   
  137.     /* open the output file */  
  138.     if (!(out_fmt->flags & AVFMT_NOFILE))   
  139.     {  
  140.         if (url_fopen(&out_fctx->pb, out_filename, URL_WRONLY) < 0)  
  141.         {  
  142.             fprintf(stderr, "Could not open '%s'\n", out_filename);  
  143.             exit(1);  
  144.         }  
  145.     }  
  146.     /* write the stream header, if any */  
  147.     if(av_write_header(out_fctx) < 0)  
  148.     {  
  149.         fprintf(stderr, "Could not write header for output file\n");  
  150.         return -1;  
  151.     }  
  152.   
  153.     int decoded_size;  
  154.     AVPacket in_packet;  
  155.     AVPacket out_packet;  
  156.     ReSampleContext *rs_ctx = NULL;  
  157.     /* 
  158.     参考链接:http://hi.baidu.com/wg_wang/item/34396781d20b4b1ec316270b 
  159.     两点需要注意: 
  160.     (1) 从输入文件中按帧读取数据,<strong>解码</strong>,按照输出文件的要求,编码,并按帧写入到输出文件中。 
  161.     在这里,由于sample_rate和channels可能不同,需要对<strong><strong>音频</strong></strong>数据<strong>进行</strong>重采样。 
  162.     (2) 由于不同编码类型对一帧<strong><strong>音频</strong></strong>的数据要求不同,可能需要将输入数据保存起来,直到够输出的编码<strong>使用</strong>, 
  163.     或者,一帧的输入数据可能需要被多次输出。 
  164.     这样,要求初始化重采样以及libavutil提供的fifo(libavutils/fifo.h声明)以临时保存数据。 
  165.     举个例子:aac的frame_size=1024,mp3的frame_size=1152。若不用这个fifo,则生成的mp3文件是有问题的 
  166.     */  
  167.     // 设置从采样  
  168.     rs_ctx = av_audio_resample_init(  
  169.                 out_cctx->channels, in_cctx->channels,  
  170.                 out_cctx->sample_rate, in_cctx->sample_rate,  
  171.                 out_cctx->sample_fmt, in_cctx->sample_fmt,  
  172.                 16, 10, 0, 0.8);  
  173.   
  174.     AVFifoBuffer *iofifo;  
  175.     iofifo = av_fifo_alloc(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);  
  176.     av_init_packet(&in_packet);  
  177.     av_init_packet(&out_packet);  
  178.   
  179.     while (av_read_frame(in_fctx, &in_packet) >= 0)  
  180.     {  
  181.         while (in_packet.size > 0)  
  182.         {  
  183.             int used_size;  
  184.             decoded_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;  
  185.             used_size = avcodec_decode_audio3(in_cctx, (int16_t *)decoded_buf, &decoded_size, &in_packet);  
  186.             if (used_size < 0)  
  187.             {  
  188.                 printf("avcodec_decode_audio3 fail\n");  
  189.                 exit(1);  
  190.             }  
  191.             int bs, frame_bytes;  
  192.   
  193.             bs = audio_resample(rs_ctx, (short *)resample_buf, (short *)decoded_buf, decoded_size/(in_cctx->channels*g_in_bytes));  
  194.             ret = av_fifo_generic_write(iofifo, (uint8_t *)resample_buf, bs*out_cctx->channels*g_out_bytes, NULL);  
  195.             //ret = av_fifo_generic_write(iofifo, (uint8_t *)decoded_buf, in_cctx->frame_size*in_cctx->channels*g_out_bytes, NULL);  
  196.   
  197.             frame_bytes = out_cctx->frame_size * g_out_bytes * out_cctx->channels;  
  198.             while(av_fifo_size(iofifo) >= frame_bytes)  
  199.             {  
  200.                 ret = av_fifo_generic_read(iofifo, before_encoding_buf, frame_bytes, NULL);  
  201.                 out_packet.size = avcodec_encode_audio(out_cctx, (uint8_t*)output_buf, frame_bytes, (short *)before_encoding_buf);  
  202.                 out_packet.data = (uint8_t *)output_buf;  
  203.                 av_write_frame(out_fctx, &out_packet);  
  204.             }  
  205.   
  206.             in_packet.size -= used_size;  
  207.             in_packet.data += used_size;  
  208.         }  
  209.     }  
  210.     /* write the trailer, if any */  
  211.     av_write_trailer(out_fctx);  
  212.     if (!(out_fmt->flags & AVFMT_NOFILE)) {  
  213.         /* close the output file */  
  214.         url_fclose(out_fctx->pb);  
  215.     }  
  216. }  
  217.   
  218. int output_decode_open(AVCodecContext* cc)  
  219. {  
  220.     AVCodec *codec;  
  221.   
  222.     /* find the audio encoder */  
  223.     codec = avcodec_find_encoder(cc->codec_id);  
  224.     if (!codec)   
  225.     {  
  226.         fprintf(stderr, "codec not found\n");  
  227.         exit(1);  
  228.     }  
  229.   
  230.     /* open it */  
  231.     if (avcodec_open(cc, codec) < 0) {  
  232.         fprintf(stderr, "could not open audio codec\n");  
  233.         exit(1);  
  234.     }  
  235.   
  236.     return 0;  
  237. }  
  238.   
  239. AVCodecContext* output_decode_init(AVCodecContext* in_cctx, AVFormatContext* out_fctx, int codec_id)  
  240. {  
  241.     AVCodecContext *cc;  
  242.     AVStream *st;  
  243.   
  244.     st = av_new_stream(out_fctx, 0);  
  245.     if (!st)   
  246.     {  
  247.         fprintf(stderr, "Could not alloc stream\n");  
  248.         exit(1);  
  249.     }  
  250.       
  251.     cc = st->codec;  
  252.     cc->codec_id = (CodecID)codec_id;  
  253.     cc->codec_type = AVMEDIA_TYPE_AUDIO;  
  254.     /*  
  255.        google keep的录音笔记的sample_fmt的格式为AV_SAMPLE_FMT_FLT 
  256.     */  
  257.     cc->sample_fmt = AV_SAMPLE_FMT_S16;  // 默认采用AV_SAMPLE_FMT_S16  
  258.     //cc->sample_fmt = in_cctx->sample_fmt;  
  259.     if (in_cctx->sample_fmt == AV_SAMPLE_FMT_FLT)  
  260.     {  
  261.         g_in_bytes = 4;  
  262.     }  
  263.     if (cc->sample_fmt == AV_SAMPLE_FMT_S16)  
  264.     {  
  265.         g_out_bytes = 2;  
  266.     }  
  267.       
  268.   
  269.     if (codec_id == CODEC_ID_AMR_NB)  
  270.     {  
  271.         cc->channels = 1;  
  272.         cc->bit_rate = 12200;  
  273.     }  
  274.     else  
  275.     {  
  276.         cc->channels = in_cctx->channels;  
  277.         cc->bit_rate = in_cctx->bit_rate;  
  278.     }  
  279.     //cc->sample_rate = in_cctx->sample_rate;  
  280.     //cc->sample_rate = 44100;  
  281.     cc->sample_rate = 8000;  
  282.       
  283.     return cc;  
  284. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值