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. 用shell查找某个目录下最大文件

    网上资料学习: 1.查找当前目录下最大文件(包括子目录里文件): find . -type f -exec stat -c "%s %n" {} \; | sort -nr | h ...

  2. 4.MVC框架开发(母版页的应用、按钮导致的Action处理、从界面向控制器传数据和HtmlHelper控件的实现(注册的实现))

    1.在视图里如何引入母版页 1)在视图里母版页都是放在View目录下面的Shared文件夹下面 2)母版页里的RenderBody()类似于ASP.NET里面的ContentPalceHolder占位 ...

  3. javascript高级编程笔记01(基本概念)

    1.在html中使用JavaScript 1.  <script> 元素 <script>定义了下列6个属性: async:可选,异步下载外部脚本文件. charset:可选, ...

  4. Static File Middleware

    [ASP.NET Core] Static File Middleware   前言 本篇文章介绍ASP.NET Core里,用来处理静态档案的Middleware,为自己留个纪录也希望能帮助到有需要 ...

  5. 25个App免费资源网站

    不少非常优秀的设计师已经在网络分享了很多出色的图标.界面 PSD 文件,再加上其他一些相关资源,设计 iOS 应用更加方便了. 模板 & PSDs  Icon Template Michael ...

  6. 解析Android消息处理机制:Handler/Thread/Looper & MessageQueue

    解析Android消息处理机制 ——Handler/Thread/Looper & MessageQueue Keywords: Android Message HandlerThread L ...

  7. Decision Boundaries for Deep Learning and other Machine Learning classifiers

    Decision Boundaries for Deep Learning and other Machine Learning classifiers H2O, one of the leading ...

  8. hdu 4286

    splay 练手用: 杭电的oj要手动开栈: #include<cstdio> #pragma comment(linker, "/STACK:102400000,1024000 ...

  9. Design Tutorial: Inverse the Problem

    Codeforces Round #270 D:http://codeforces.com/contest/472/problem/D 题意:给以一张图,用邻接矩阵表示,现在问你这张图能不能够是一棵树 ...

  10. 介绍一个超好用的HICHARTS扩展插件

    因为需要,所以HIGHCHARTS了解一下是很有必要的. 但原始应用确实效率不行. 刚好,现在有个需求是从一系列的JSON里抽出表格数据,再显示图形. jquery.highchartsTable.j ...