http://blog.csdn.net/leixiaohua1020/article/details/25430449

本文介绍一个最简单的基于FFMPEG的音频编码器。该编码器实现了PCM音频采样数据编码为AAC的压缩编码数据。编码器代码十分简单,但是每一行代码都很重要。通过看本编码器的源代码,可以了解FFMPEG音频编码的流程。

本程序使用最新版的类库(编译时间为2014.5.6),开发平台为VC2010。所有的配置都已经做好,只需要运行就可以了。

流程(2014.9.29更新)

下面附一张使用FFmpeg编码音频的流程图。使用该流程,不仅可以编码AAC的音频,而且可以编码MP3,MP2等等各种FFmpeg支持的音频。图中蓝色背景的函数是实际输出数据的函数。浅绿色的函数是音频编码的函数。

简单介绍一下流程中各个函数的意义:

av_register_all():注册FFmpeg所有编解码器。

avformat_alloc_output_context2():初始化输出码流的AVFormatContext。

avio_open():打开输出文件。

av_new_stream():创建输出码流的AVStream。

avcodec_find_encoder():查找编码器。

avcodec_open2():打开编码器。

avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。

avcodec_encode_audio2():编码音频。即将AVFrame(存储PCM采样数据)编码为AVPacket(存储AAC,MP3等格式的码流数据)。

av_write_frame():将编码后的视频码流写入文件。

av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。

代码

  1. /**
  2. *最简单的基于FFmpeg的音频编码器
  3. *Simplest FFmpeg Audio Encoder
  4. *
  5. *雷霄骅 Lei Xiaohua
  6. *leixiaohua1020@126.com
  7. *中国传媒大学/数字电视技术
  8. *Communication University of China / Digital TV Technology
  9. *http://blog.csdn.net/leixiaohua1020
  10. *
  11. *本程序实现了音频PCM采样数据编码为压缩码流(MP3,WMA,AAC等)。
  12. *是最简单的FFmpeg音频编码方面的教程。
  13. *通过学习本例子可以了解FFmpeg的编码流程。
  14. *This software encode PCM data to AAC bitstream.
  15. *It's the simplest audio encoding software based on FFmpeg.
  16. *Suitable for beginner of FFmpeg
  17. */
  18. #include <stdio.h>
  19. #define __STDC_CONSTANT_MACROS
  20. #ifdef _WIN32
  21. //Windows
  22. extern "C"
  23. {
  24. #include "libavcodec/avcodec.h"
  25. #include "libavformat/avformat.h"
  26. };
  27. #else
  28. //Linux...
  29. #ifdef __cplusplus
  30. extern "C"
  31. {
  32. #endif
  33. #include <libavcodec/avcodec.h>
  34. #include <libavformat/avformat.h>
  35. #ifdef __cplusplus
  36. };
  37. #endif
  38. #endif
  39. int flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){
  40. int ret;
  41. int got_frame;
  42. AVPacket enc_pkt;
  43. if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
  44. CODEC_CAP_DELAY))
  45. return 0;
  46. while (1) {
  47. enc_pkt.data = NULL;
  48. enc_pkt.size = 0;
  49. av_init_packet(&enc_pkt);
  50. ret = avcodec_encode_audio2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,
  51. NULL, &got_frame);
  52. av_frame_free(NULL);
  53. if (ret < 0)
  54. break;
  55. if (!got_frame){
  56. ret=0;
  57. break;
  58. }
  59. printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);
  60. /* mux encoded frame */
  61. ret = av_write_frame(fmt_ctx, &enc_pkt);
  62. if (ret < 0)
  63. break;
  64. }
  65. return ret;
  66. }
  67. int main(int argc, char* argv[])
  68. {
  69. AVFormatContext* pFormatCtx;
  70. AVOutputFormat* fmt;
  71. AVStream* audio_st;
  72. AVCodecContext* pCodecCtx;
  73. AVCodec* pCodec;
  74. uint8_t* frame_buf;
  75. AVFrame* pFrame;
  76. AVPacket pkt;
  77. int got_frame=0;
  78. int ret=0;
  79. int size=0;
  80. FILE *in_file=NULL;                         //Raw PCM data
  81. int framenum=1000;                          //Audio frame number
  82. const char* out_file = "tdjm.aac";          //Output URL
  83. int i;
  84. in_file= fopen("tdjm.pcm", "rb");
  85. av_register_all();
  86. //Method 1.
  87. pFormatCtx = avformat_alloc_context();
  88. fmt = av_guess_format(NULL, out_file, NULL);
  89. pFormatCtx->oformat = fmt;
  90. //Method 2.
  91. //avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
  92. //fmt = pFormatCtx->oformat;
  93. //Open output URL
  94. if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){
  95. printf("Failed to open output file!\n");
  96. return -1;
  97. }
  98. audio_st = avformat_new_stream(pFormatCtx, 0);
  99. if (audio_st==NULL){
  100. return -1;
  101. }
  102. pCodecCtx = audio_st->codec;
  103. pCodecCtx->codec_id = fmt->audio_codec;
  104. pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
  105. pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
  106. pCodecCtx->sample_rate= 44100;
  107. pCodecCtx->channel_layout=AV_CH_LAYOUT_STEREO;
  108. pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
  109. pCodecCtx->bit_rate = 64000;
  110. //Show some information
  111. av_dump_format(pFormatCtx, 0, out_file, 1);
  112. pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
  113. if (!pCodec){
  114. printf("Can not find encoder!\n");
  115. return -1;
  116. }
  117. if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){
  118. printf("Failed to open encoder!\n");
  119. return -1;
  120. }
  121. pFrame = av_frame_alloc();
  122. pFrame->nb_samples= pCodecCtx->frame_size;
  123. pFrame->format= pCodecCtx->sample_fmt;
  124. size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
  125. frame_buf = (uint8_t *)av_malloc(size);
  126. avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
  127. //Write Header
  128. avformat_write_header(pFormatCtx,NULL);
  129. av_new_packet(&pkt,size);
  130. for (i=0; i<framenum; i++){
  131. //Read PCM
  132. if (fread(frame_buf, 1, size, in_file) <= 0){
  133. printf("Failed to read raw data! \n");
  134. return -1;
  135. }else if(feof(in_file)){
  136. break;
  137. }
  138. pFrame->data[0] = frame_buf;  //PCM Data
  139. pFrame->pts=i*100;
  140. got_frame=0;
  141. //Encode
  142. ret = avcodec_encode_audio2(pCodecCtx, &pkt,pFrame, &got_frame);
  143. if(ret < 0){
  144. printf("Failed to encode!\n");
  145. return -1;
  146. }
  147. if (got_frame==1){
  148. printf("Succeed to encode 1 frame! \tsize:%5d\n",pkt.size);
  149. pkt.stream_index = audio_st->index;
  150. ret = av_write_frame(pFormatCtx, &pkt);
  151. av_free_packet(&pkt);
  152. }
  153. }
  154. //Flush Encoder
  155. ret = flush_encoder(pFormatCtx,0);
  156. if (ret < 0) {
  157. printf("Flushing encoder failed\n");
  158. return -1;
  159. }
  160. //Write Trailer
  161. av_write_trailer(pFormatCtx);
  162. //Clean
  163. if (audio_st){
  164. avcodec_close(audio_st->codec);
  165. av_free(pFrame);
  166. av_free(frame_buf);
  167. }
  168. avio_close(pFormatCtx->pb);
  169. avformat_free_context(pFormatCtx);
  170. fclose(in_file);
  171. return 0;
  172. }

结果

程序运行完成后,会将一个PCM采样数据文件(*.pcm)编码为AAC码流文件(*.aac)。

下载

simplest ffmpeg audio encoder

项目主页

SourceForge:https://sourceforge.net/projects/simplestffmpegaudioencoder/

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_audio_encoder

开源中国:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_audio_encoder

CSDN工程下载地址:

http://download.csdn.net/detail/leixiaohua1020/7324091

PUDN工程下载地址:

http://www.pudn.com/downloads644/sourcecode/multimedia/detail2605236.html

更新-1.1 (2015.2.13)=========================================

这次考虑到了跨平台的要求,调整了源代码。经过这次调整之后,源代码可以在以下平台编译通过:

VC++:打开sln文件即可编译,无需配置。

cl.exe:打开compile_cl.bat即可命令行下使用cl.exe进行编译,注意可能需要按照VC的安装路径调整脚本里面的参数。编译命令如下。

  1. ::VS2010 Environment
  2. call "D:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
  3. ::include
  4. @set INCLUDE=include;%INCLUDE%
  5. ::lib
  6. @set LIB=lib;%LIB%
  7. ::compile and link
  8. cl simplest_ffmpeg_audio_encoder.cpp /link avcodec.lib avformat.lib avutil.lib ^
  9. avdevice.lib avfilter.lib postproc.lib swresample.lib swscale.lib /OPT:NOREF

MinGW:MinGW命令行下运行compile_mingw.sh即可使用MinGW的g++进行编译。编译命令如下。

  1. g++ simplest_ffmpeg_audio_encoder.cpp -g -o simplest_ffmpeg_audio_encoder.exe \
  2. -I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

GCC:Linux或者MacOS命令行下运行compile_gcc.sh即可使用GCC进行编译。编译命令如下。

  1. gcc simplest_ffmpeg_audio_encoder.cpp -g -o simplest_ffmpeg_audio_encoder.out \
  2. -I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

PS:相关的编译命令已经保存到了工程文件夹中

CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/8445209

SourceForge上已经更新。

最简单的基于FFMPEG的音频编码器(PCM编码为AAC)的更多相关文章

  1. 最简单的基于FFMPEG的图像编码器(YUV编码为JPEG)

    伴随着毕业论文的完成,这两天终于腾出了空闲,又有时间搞搞FFMPEG的研究了.想着之前一直搞的都是FFMPEG解码方面的工作,很少涉及到FFMPEG编码方面的东西,于是打算研究一下FFMPEG的编码. ...

  2. 最简单的基于FFMPEG的图像编码器(YUV编码为JPEG)(转)

    原文转自 https://blog.csdn.net/leixiaohua1020/article/details/25346147/ 伴随着毕业论文的完成,这两天终于腾出了空闲,又有时间搞搞FFMP ...

  3. 最简单的基于FFMPEG的视频编码器(YUV编码为H.264)

    本文介绍一个最简单的基于FFMPEG的视频编码器.该编码器实现了YUV420P的像素数据编码为H.264的压缩编码数据.编码器代码十分简单,可是每一行代码都非常重要,适合好好研究一下.弄清楚了本代码也 ...

  4. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  5. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  6. 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)

    ===================================================== 最简单的基于FFmpeg的视频编码器文章列表: 最简单的基于FFMPEG的视频编码器(YUV ...

  7. 最简单的基于FFMPEG的转码程序

    本文介绍一个简单的基于FFmpeg的转码器.它可以将一种视频格式(包括封转格式和编码格式)转换为另一种视频格式.转码器在视音频编解码处理的程序中,属于一个比较复杂的东西.因为它结合了视频的解码和编码. ...

  8. 最简单的基于FFmpeg的视频编码器-更新版(YUV编码为HEVC(H.265))

    ===================================================== 最简单的基于FFmpeg的视频编码器文章列表: 最简单的基于FFMPEG的视频编码器(YUV ...

  9. 最简单的基于FFmpeg的内存读写的例子:内存转码器

    ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的 ...

随机推荐

  1. We7——很有意思的一个开源CMS

    目前做门户.做网站,基本上都需要用到一个系统,那就是CMS内容管理系统:现在开源产品有很多,笔者也是从事这个行业的,国内的各大CMS提供商基本上都试用过,今天向大家推荐一款很有意思的产品——We7CM ...

  2. 查看 usb info

    mount -t usbfs /proc/bus/usb /proc/bus/usb cat /proc/bus/usb/devices

  3. Python从list删除元素

    Paul同学刚来几天又要转走了,那么我们怎么把Paul 从现有的list中删除呢? 如果Paul同学排在最后一个,我们可以用list的pop()方法删除: >>> L = ['Ada ...

  4. 我的PHP之旅--数据库连接MySQL服务器,添加 删除 查询

    PHP连接MySQL服务器 连接MySQL的方法:mysql_connect(); 语法:resource $link = mysql_connect($hostname, $username, $p ...

  5. Python的字符串操作和Unicode

    字符串类型 str:Unicode字符串.采用''或者r''构造的字符串均为str,单引号可以用双引号或者三引号来代替.无论用哪种方式进行制定,在Python内部存储时没有区别. bytes:二进制字 ...

  6. top 10 js mvc

    http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-reviewed/ http://www.iteye.com/new ...

  7. 安装Ubuntu 14.04后要做的5件事情

    转自安装Ubuntu 14.04后要做的5件事情 Ubuntu目前是世界上最流行的Linux操作系统,它提供了桌面版本和服务器版本,其他流行的Linux发行版本如Linux Mint也是基于Ubunt ...

  8. 如何成为python高手(转)

    http://www.cnblogs.com/xupeizhi/p/3207976.html#2896469 如何成为python高手 本文是从 How to become a proficient ...

  9. ANDROID_MARS学习笔记_S01原始版_003_对话框

    1.AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest ...

  10. OpenSSH for Windows,CopSSH

    https://www.oschina.net/p/openssh+for+windows https://www.oschina.net/p/copssh