ffmpeg的复习、学习、总结

本文从ffmpeg的例程入手,记录下ffmpeg能做什么


点击(此处)折叠或打开

  1. //avio_reading.c
  2. #include <libavcodec/avcodec.h>
  3. #include <libavformat/avformat.h>
  4. #include <libavformat/avio.h>
  5. #include <libavutil/file.h>

  6. struct buffer_data {
  7.     uint8_t *ptr;
  8.     size_t size; ///< size left in the buffer
  9. };
  10. //读回调函数opaque=调用者传递的参数,buf=目的地址(要把数据保存到哪里)
  11. //buf_size=目的地址的长度,返回值表示读取多少字节的数据到目的地址
  12. static int read_packet(void *opaque, uint8_t *buf, int buf_size)
  13. {
  14.     struct buffer_data *bd = (struct buffer_data *)opaque;
  15.     buf_size = FFMIN(buf_size, bd->size);

  16.     printf("ptr:%p size:%zu\n", bd->ptr, bd->size);

  17.     /* copy internal buffer data to buf */
  18.     memcpy(buf, bd->ptr, buf_size);
  19.     bd->ptr += buf_size;
  20.     bd->size -= buf_size;

  21.     return buf_size;
  22. }

  23. int main(int argc, char *argv[])
  24. {
  25.     //格式上下文
  26.     AVFormatContext *fmt_ctx = NULL;
  27.     //io上下文
  28.     AVIOContext *avio_ctx = NULL;
  29.     uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
  30.     size_t buffer_size, avio_ctx_buffer_size = 4096;
  31.     char *input_filename = NULL;
  32.     int ret = 0;
  33.     struct buffer_data bd = { 0 };

  34.     if (argc != 2) {
  35.         fprintf(stderr, "usage: %s input_file\n"
  36.                 "API example program to show how to read from a custom buffer "
  37.                 "accessed through AVIOContext.\n", argv[0]);
  38.         return 1;
  39.     }
  40.     input_filename = argv[1];

  41.     /* register codecs and formats and other lavf/lavc components*/
  42.     av_register_all();

  43.     /* slurp file content into buffer */
  44.     //映射文件到内存中,不常用的函数
  45.     ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
  46.     if (ret < 0)
  47.         goto end;

  48.     /* fill opaque structure used by the AVIOContext read callback */
  49.     bd.ptr = buffer;
  50.     bd.size = buffer_size;
  51.     
  52.     //申请格式上下文,如果没有申请,那么avformat_open_input会帮助申请(此时第二个参数不能为NULL)
  53.     //自己申请格式上下文还有个好处,就是可以指定这个格式上下文的io上下文(意味着我们可以使用自己的方式对文件进行读写,否则使用ffmpeg提供的方法)
  54.     if (!(fmt_ctx = avformat_alloc_context())) {
  55.         ret = AVERROR(ENOMEM);
  56.         goto end;
  57.     }

  58.     avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
  59.     if (!avio_ctx_buffer) {
  60.         ret = AVERROR(ENOMEM);
  61.         goto end;
  62.     }
  63.     //申请io上下文,avio_ctx_buffer=文件内容的内存首地址,avio_ctx_buffer_size=文件内容的长度
  64.     //0=写标志(1表示可写) bd=传给回调函数的参数 read_packet=读回调函数 NULL=写回调函数 NULL=跳到一个文件的特殊位置的函数
  65.     avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
  66.                                   0, &bd, &read_packet, NULL, NULL);
  67.     if (!avio_ctx) {
  68.         ret = AVERROR(ENOMEM);
  69.         goto end;
  70.     }
  71.     //格式上下文的pd变量指向io上下文(如果没有指定的话在avformat_open_input函数会指定默认的)
  72.     fmt_ctx->pb = avio_ctx;
  73.     //打开输入文件,填充格式上下文,&fmt_ctx=格式上下文的地址,NULL=文件名(如果文件名是空的话,必须自己指定格式上下文的io上下文)
  74.     //NULL=指定以某种方式打开文件(AVInputFormat *),NULL=参数(可以传递一些自己的参数进去,我没用过)(AVDictionary**)
  75.     ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
  76.     if (ret < 0) {
  77.         fprintf(stderr, "Could not open input\n");
  78.         goto end;
  79.     }
  80.     //查找流的信息fmt_ctx=格式上下文,NULL=参数(AVDictionary**
  81.     ret = avformat_find_stream_info(fmt_ctx, NULL);
  82.     if (ret < 0) {
  83.         fprintf(stderr, "Could not find stream information\n");
  84.         goto end;
  85.     }
  86.     //dump文件信息 fmt_ctx=格式上下文 0=流的序号(填0就行),input_filename=文件名,也可以是一个连接
  87.     //0=Select whether the specified context is an input(0) or output(1)
  88.     av_dump_format(fmt_ctx, 0, input_filename, 0);

  89. end:
  90.     //关闭格式上下文,必须要关闭,不关闭可能会内存泄露&fmt_ctx = 格式上下文的地址
  91.     avformat_close_input(&fmt_ctx);
  92.     /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
  93.     if (avio_ctx) {
  94.         av_freep(&avio_ctx->buffer);
  95.         av_freep(&avio_ctx);
  96.     }
  97.     //解除文件映射
  98.     av_file_unmap(buffer, buffer_size);

  99.     if (ret < 0) {
  100. // fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
  101.         return 1;
  102.     }

  103.     return 0;
  104. }
运行结果

这个例程像我们展示如何获取一个媒体文件的元信息,值得多看一眼的地方是,我们可以指定io上下文,这意味着我们可以从内存中把数据传给ffmpeg,不论数据时从网络,摄像头,或者是本地文件


点击(此处)折叠或打开

  1. //metadata.c
  2. #include <stdio.h>

  3. #include <libavformat/avformat.h>
  4. #include <libavutil/dict.h>

  5. int main (int argc, char **argv)
  6. {
  7.     AVFormatContext *fmt_ctx = NULL;
  8.     //“字典入口”,用来保存AVDictionary变量里面的每一个“字”
  9.     AVDictionaryEntry *tag = NULL;
  10.     int ret;

  11.     if (argc != 2) {
  12.         printf("usage: %s \n"
  13.                "example program to demonstrate the use of the libavformat metadata API.\n"
  14.                "\n", argv[0]);
  15.         return 1;
  16.     }

  17.     av_register_all();
  18.     if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL)))
  19.         return ret;
  20.     //遍历“字典”中的每一个“字”,每一个字有一个键值对
  21.     while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
  22.         printf("%s=%s\n", tag->key, tag->value);

  23.     avformat_close_input(&fmt_ctx);
  24.     return 0;
  25. }
这个没什么好说的,只需要注意一下格式上下文的metadata中保存了媒体文件的元信息,保存的格式是“字典”( AVDictionary )类型


点击(此处)折叠或打开

  1. //resampling_audio.c
  2. #include <libavutil/opt.h>
  3. #include <libavutil/channel_layout.h>
  4. #include <libavutil/samplefmt.h>
  5. #include <libswresample/swresample.h>

  6. static int get_format_from_sample_fmt(const char **fmt,
  7.                                       enum AVSampleFormat sample_fmt)
  8. {
  9.     int i;
  10.     struct sample_fmt_entry {
  11.         enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
  12.     } sample_fmt_entries[] = {
  13.         { AV_SAMPLE_FMT_U8, "u8", "u8" },
  14.         { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
  15.         { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
  16.         { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
  17.         { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
  18.     };
  19.     *fmt = NULL;

  20.     for (= 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
  21.         struct sample_fmt_entry *entry = &sample_fmt_entries[i];
  22.         if (sample_fmt == entry->sample_fmt) {
  23.             *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
  24.             return 0;
  25.         }
  26.     }

  27.     fprintf(stderr,
  28.             "Sample format %s not supported as output format\n",
  29.             av_get_sample_fmt_name(sample_fmt));
  30.     return AVERROR(EINVAL);
  31. }

  32. /**
  33.  * Fill dst buffer with nb_samples, generated starting from t.
  34.  */
  35. static void fill_samples(double *dst, int nb_samples, int nb_channels, int sample_rate, double *t)
  36. {
  37.     int i, j;
  38.     double tincr = 1./ sample_rate, *dstp = dst;
  39.     const double c = 2 * M_PI * 440.0;

  40.     /* generate sin tone with 440Hz frequency and duplicated channels */
  41.     for (= 0; i < nb_samples; i++) {
  42.         *dstp = sin(* *t);
  43.         for (= 1; j < nb_channels; j++)
  44.             dstp[j] = dstp[0];
  45.         dstp += nb_channels;
  46.         *+= tincr;
  47.     }
  48. }

  49. int main(int argc, char **argv)
  50. {
  51.     //AV_CH_LAYOUT_STEREO=3 左右 AV_CH_LAYOUT_SURROUND=7 左右中 理解成声道的一种格式就行
  52.     int64_t src_ch_layout = AV_CH_LAYOUT_STEREO, dst_ch_layout = AV_CH_LAYOUT_SURROUND;
  53.     //采样率定义44100比较常用
  54.     int src_rate = 48000, dst_rate = 44100;
  55.     //
  56.     uint8_t **src_data = NULL, **dst_data = NULL;
  57.     //声道数
  58.     int src_nb_channels = 0, dst_nb_channels = 0;
  59.     int src_linesize, dst_linesize;
  60.     //这东西我叫他采样数,但是问别人好像不这么叫
  61.     int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples;
  62.     //采样格式 double 和 signed 16bit,现在好像都流行平面的(声道的数据分开存放)
  63.     enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL, dst_sample_fmt = AV_SAMPLE_FMT_S16;
  64.     const char *dst_filename = NULL;
  65.     FILE *dst_file;
  66.     int dst_bufsize;
  67.     const char *fmt;
  68.     //本段代码嘴主要的结构 重采样上下文
  69.     struct SwrContext *swr_ctx;
  70.     double t;
  71.     int ret;

  72.     if (argc != 2) {
  73.         fprintf(stderr, "Usage: %s output_file\n"
  74.                 "API example program to show how to resample an audio stream with libswresample.\n"
  75.                 "This program generates a series of audio frames, resamples them to a specified "
  76.                 "output format and rate and saves them to an output file named output_file.\n",
  77.             argv[0]);
  78.         exit(1);
  79.     }
  80.     dst_filename = argv[1];

  81.     dst_file = fopen(dst_filename, "wb");
  82.     if (!dst_file) {
  83.         fprintf(stderr, "Could not open destination file %s\n", dst_filename);
  84.         exit(1);
  85.     }

  86.     /* create resampler context */
  87.     //创建重采样上下文
  88.     swr_ctx = swr_alloc();
  89.     if (!swr_ctx) {
  90.         fprintf(stderr, "Could not allocate resampler context\n");
  91.         ret = AVERROR(ENOMEM);
  92.         goto end;
  93.     }

  94.     /* set options */
  95.     //设置重采样上下文的输入属性
  96.     av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
  97.     av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);
  98.     av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0);
  99.     //设置重采样上下文的输出属性
  100.     av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
  101.     av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);
  102.     av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);

  103.     /* initialize the resampling context */
  104.     //初始化重采样上下文
  105.     if ((ret = swr_init(swr_ctx)) < 0) {
  106.         fprintf(stderr, "Failed to initialize the resampling context\n");
  107.         goto end;
  108.     }

  109.     /* allocate source and destination samples buffers */
  110.     //通过声道格式获取声道数
  111.     src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);
  112.     //计算并申请一块内存,用于保存源数据 src_linesize=采样数*采样格式的字节数(double类型=8字节)*声道数
  113.     ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels,
  114.                                              src_nb_samples, src_sample_fmt, 0);
  115.     if (ret < 0) {
  116.         fprintf(stderr, "Could not allocate source samples\n");
  117.         goto end;
  118.     }

  119.     /* compute the number of converted samples: buffering is avoided
  120.      * ensuring that the output buffer will contain at least all the
  121.      * converted input samples */
  122.     //计算目标采样数,如果重新采样的话,采样率S肯定不等于采样率D,比如48000采样率单位时间采样数为1024的话,那么44100采样率在同等时间的采样数x=1024*44100    // /48000 需要理解 采样率和采样数之间的关系 这地方可能我说的不对,暂时我就这样理解,有人知道的话希望指点
  123.     max_dst_nb_samples = dst_nb_samples =
  124.         av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);

  125.     /* buffer is going to be directly written to a rawaudio file, no alignment */
  126.     dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
  127.     ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
  128.                                              dst_nb_samples, dst_sample_fmt, 0);
  129.     if (ret < 0) {
  130.         fprintf(stderr, "Could not allocate destination samples\n");
  131.         goto end;
  132.     }

  133.     t = 0;
  134.     do {
  135.         /* generate synthetic audio */
  136.         fill_samples((double *)src_data[0], src_nb_samples, src_nb_channels, src_rate, &t);

  137.         /* compute destination number of samples */
  138.         //重新采样必须有这一步,如果是转格式采样率不变的话,可以不计算这一步
  139.         dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) +
  140.                                         src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
  141.         if (dst_nb_samples > max_dst_nb_samples) {
  142.             av_freep(&dst_data[0]);
  143.             //重新申请dst_data(不然装不下,越界)
  144.             ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
  145.                                    dst_nb_samples, dst_sample_fmt, 1);
  146.             if (ret < 0)
  147.                 break;
  148.             max_dst_nb_samples = dst_nb_samples;
  149.         }

  150.         /* convert to destination format */
  151.         //转换格式
  152.         ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples);
  153.         if (ret < 0) {
  154.             fprintf(stderr, "Error while converting\n");
  155.             goto end;
  156.         }
  157.         //计算转换之后音频帧的长度
  158.         dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
  159.                                                  ret, dst_sample_fmt, 1);
  160.         if (dst_bufsize < 0) {
  161.             fprintf(stderr, "Could not get sample buffer size\n");
  162.             goto end;
  163.         }
  164.         printf("t:%f in:%d out:%d\n", t, src_nb_samples, ret);
  165.         //没有经过容器封装的原始音频数据
  166.         fwrite(dst_data[0], 1, dst_bufsize, dst_file);
  167.     } while (< 10);

  168.     if ((ret = get_format_from_sample_fmt(&fmt, dst_sample_fmt)) < 0)
  169.         goto end;
  170. //PRId64 = 64
  171. //32位os中使用lld代替
  172.     fprintf(stderr, "Resampling succeeded. Play the output file with the command:\n"
  173.             "ffplay -f %s -channel_layout %lld -channels %d -ar %d %s\n",
  174.             fmt, dst_ch_layout, dst_nb_channels, dst_rate, dst_filename);

  175. end:
  176.     fclose(dst_file);

  177.     if (src_data)
  178.         av_freep(&src_data[0]);
  179.     av_freep(&src_data);

  180.     if (dst_data)
  181.         av_freep(&dst_data[0]);
  182.     av_freep(&dst_data);

  183.     swr_free(&swr_ctx);
  184.     return ret < 0;
  185. }
重采样的例程比较简单,只要理解几个名词就行了
1、声道数
2、声道格式(可以用来计算声道数)
3、采样率 常用的22500 44100 48000...
4、采样格式 每个样本需要用多少位来表示,是否带符号,是否平面
5、采样数 这个一般都是1024,mp3格式的好像是1152
如果想做一个重新采样的程序的话,从哪获取上面这些信息呢

声道格式,采样率,采样格式都保存在codec_ctx(AVCodecContext*编解码器上下文)中
//frame是解码文件获取的一帧音频,data中音频数据(此处需要注意,如果是平面格式的话,是否data【0】data【1】呢?),nb_samples中保存采样数
src_data = frame->data;
src_nb_samples = frame->nb_samples;


点击(此处)折叠或打开

  1. /*
  2.  * This file is part of FFmpeg.
  3.  *
  4.  * FFmpeg is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU Lesser General Public
  6.  * License as published by the Free Software Foundation; either
  7.  * version 2.1 of the License, or (at your option) any later version.
  8.  *
  9.  * FFmpeg is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12.  * Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with FFmpeg; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17.  */

  18. /**
  19.  * @file
  20.  * simple audio converter
  21.  *
  22.  * @example transcode_aac.c
  23.  * Convert an input audio file to AAC in an MP4 container using FFmpeg.
  24.  * @author Andreas Unterweger (dustsigns@gmail.com)
  25.  */

  26. #include <stdio.h>

  27. #include "libavformat/avformat.h"
  28. #include "libavformat/avio.h"

  29. #include "libavcodec/avcodec.h"

  30. #include "libavutil/audio_fifo.h"
  31. #include "libavutil/avassert.h"
  32. #include "libavutil/avstring.h"
  33. #include "libavutil/frame.h"
  34. #include "libavutil/opt.h"

  35. #include "libswresample/swresample.h"

  36. /** The output bit rate in kbit/*/
  37. #define OUTPUT_BIT_RATE 96000
  38. /** The number of output channels */
  39. #define OUTPUT_CHANNELS 2

  40. /**
  41.  * Convert an error code into a text message.
  42.  * @param error Error code to be converted
  43.  * @return Corresponding error text (not thread-safe)
  44.  */
  45. static const char *get_error_text(const int error)
  46. {
  47.     static char error_buffer[255];
  48.     av_strerror(error, error_buffer, sizeof(error_buffer));
  49.     return error_buffer;
  50. }

  51. /** Open an input file and the required decoder. */
  52. static int open_input_file(const char *filename,
  53.                            AVFormatContext **input_format_context,
  54.                            AVCodecContext **input_codec_context)
  55. {
  56.     AVCodec *input_codec;
  57.     int error;

  58.     /** Open the input file to read from it. */
  59.     //打开输入文件
  60.     if ((error = avformat_open_input(input_format_context, filename, NULL,
  61.                                      NULL)) < 0) {
  62.         fprintf(stderr, "Could not open input file '%s' (error '%s')\n",
  63.                 filename, get_error_text(error));
  64.         *input_format_context = NULL;
  65.         return error;
  66.     }

  67.     /** Get information on the input file (number of streams etc.). */
  68.     //查找流信息
  69.     if ((error = avformat_find_stream_info(*input_format_context, NULL)) < 0) {
  70.         fprintf(stderr, "Could not open find stream info (error '%s')\n",
  71.                 get_error_text(error));
  72.         avformat_close_input(input_format_context);
  73.         return error;
  74.     }
  75.     //这个地方只检测了流的数量,而且并没有确定流的类型
  76.     //(*input_format_context)->streams[0]->codec->codec_type AVMEDIA_TYPE_AUDIO AVMEDIA_TYPE_VIDEO
  77.     //所以做测试的时候输入文件必须是一个纯的音频文件,没有的话可以使用ffmpeg转换一个
  78.     /** Make sure that there is only one stream in the input file. */
  79.     if ((*input_format_context)->nb_streams != 1) {
  80.         fprintf(stderr, "Expected one audio input stream, but found %d\n",
  81.                 (*input_format_context)->nb_streams);
  82.         avformat_close_input(input_format_context);
  83.         return AVERROR_EXIT;
  84.     }

  85.     /** Find a decoder for the audio stream. */
  86.     //查找解码器 参数是解码器ID 解码时解码器的ID保存在 格式上下文->流->编解码器上下文->codec->codec_id
  87.     if (!(input_codec = avcodec_find_decoder((*input_format_context)->streams[0]->codec->codec_id))) {
  88.         fprintf(stderr, "Could not find input codec\n");
  89.         avformat_close_input(input_format_context);
  90.         return AVERROR_EXIT;
  91.     }

  92.     /** Open the decoder for the audio stream to use it later. */
  93.     //打开解码器 参数是编解码器上下文,编解码器,NULL=参数
  94.     if ((error = avcodec_open2((*input_format_context)->streams[0]->codec,
  95.                                input_codec, NULL)) < 0) {
  96.         fprintf(stderr, "Could not open input codec (error '%s')\n",
  97.                 get_error_text(error));
  98.         avformat_close_input(input_format_context);
  99.         return error;
  100.     }

  101.     /** Save the decoder context for easier access later. */
  102.     *input_codec_context = (*input_format_context)->streams[0]->codec;

  103.     return 0;
  104. }

  105. /**
  106.  * Open an output file and the required encoder.
  107.  * Also set some basic encoder parameters.
  108.  * Some of these parameters are based on the input file's parameters.
  109.  */
  110. static int open_output_file(const char *filename,
  111.                             AVCodecContext *input_codec_context,
  112.                             AVFormatContext **output_format_context,
  113.                             AVCodecContext **output_codec_context)
  114. {
  115.     AVIOContext *output_io_context = NULL;
  116.     AVStream *stream = NULL;
  117.     AVCodec *output_codec = NULL;
  118.     int error;

  119.     /** Open the output file to write to it. */
  120.     //对比例1中的avio_alloc_context,本次是打开文件,并且填充io上下文,而在例1中是直接指定io上下文的读回调函数
  121.     //如果此时不想把通过ffmpeg的方式把数据写入到文件中的话,也可以使用avio_alloc_context去指定写回调函数,就可以随心所欲的处理音频数据了
  122.     //对于输出格式上下文,其成员 io上下文和 输出格式oformat都有写文件函数,他们有什么关系呢?
  123.     //当调用av_write_frame的时候,会先调用oformat里面的写函数,oformat里面的写函数在去调用io上下文的写函数,
  124.     //总结来看io上下文的写 是和文件url有关的(网络,或者本地文件)
  125.     //oformat则是和媒体容器相关的,比如是mp4,flv,或者aac,mp3
  126.     //此处是我自己的理解,不一定正确
  127.     if ((error = avio_open(&output_io_context, filename,
  128.                            AVIO_FLAG_WRITE)) < 0) {
  129.         fprintf(stderr, "Could not open output file '%s' (error '%s')\n",
  130.                 filename, get_error_text(error));
  131.         return error;
  132.     }

  133.     /** Create a new format context for the output container format. */
  134.     //创建输出格式上下文
  135.     if (!(*output_format_context = avformat_alloc_context())) {
  136.         fprintf(stderr, "Could not allocate output format context\n");
  137.         return AVERROR(ENOMEM);
  138.     }

  139.     /** Associate the output file (pointer) with the container format context. */
  140.     //指定格式上下文的io上下文
  141.     (*output_format_context)->pb = output_io_context;

  142.     /** Guess the desired container format based on the file extension. */
  143.     //猜测输出格式的上下文,作用,我猜测是在写入文件的时候,写入相应的文件格式的头或者类似的信息,
  144.     //比如mp4的话,就需要写一个个的box,flv则是tag,其他的容器也有自己的数据格式
  145.     if (!((*output_format_context)->oformat = av_guess_format(NULL, filename,
  146.                                                               NULL))) {
  147.         fprintf(stderr, "Could not find output file format\n");
  148.         goto cleanup;
  149.     }

  150.     av_strlcpy((*output_format_context)->filename, filename,
  151.                sizeof((*output_format_context)->filename));

  152.     /** Find the encoder to be used by its name. */
  153.     //查找编码器
  154.     if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC))) {
  155.         fprintf(stderr, "Could not find an AAC encoder.\n");
  156.         goto cleanup;
  157.     }

  158.     /** Create a new audio stream in the output file container. */
  159.     //新建一个流
  160.     if (!(stream = avformat_new_stream(*output_format_context, output_codec))) {
  161.         fprintf(stderr, "Could not create new stream\n");
  162.         error = AVERROR(ENOMEM);
  163.         goto cleanup;
  164.     }

  165.     /** Save the encoder context for easier access later. */
  166.     *output_codec_context = stream->codec;

  167.     /**
  168.      * Set the basic encoder parameters.
  169.      * The input file's sample rate is used to avoid a sample rate conversion.
  170.      */
  171.     //编码器初始化
  172.     (*output_codec_context)->channels = OUTPUT_CHANNELS;//声道数
  173.     (*output_codec_context)->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS);//声道格式
  174.     (*output_codec_context)->sample_rate = input_codec_context->sample_rate;//采样率
  175.     (*output_codec_context)->sample_fmt = output_codec->sample_fmts[0];//采样格式
  176.     (*output_codec_context)->bit_rate = OUTPUT_BIT_RATE;//码率

  177.     /** Allow the use of the experimental AAC encoder */
  178.     (*output_codec_context)->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;

  179.     /** Set the sample rate for the container. */
  180.     stream->time_base.den = input_codec_context->sample_rate;
  181.     stream->time_base.num = 1;

  182.     /**
  183.      * Some container formats (like MP4) require global headers to be present
  184.      * Mark the encoder so that it behaves accordingly.
  185.      */
  186.     if ((*output_format_context)->oformat->flags & AVFMT_GLOBALHEADER)
  187.         (*output_codec_context)->flags |= CODEC_FLAG_GLOBAL_HEADER;

  188.     /** Open the encoder for the audio stream to use it later. */
  189.     //打开编码器
  190.     if ((error = avcodec_open2(*output_codec_context, output_codec, NULL)) < 0) {
  191.         fprintf(stderr, "Could not open output codec (error '%s')\n",
  192.                 get_error_text(error));
  193.         goto cleanup;
  194.     }

  195.     return 0;

  196. cleanup:
  197.     avio_closep(&(*output_format_context)->pb);
  198.     avformat_free_context(*output_format_context);
  199.     *output_format_context = NULL;
  200.     return error < 0 ? error : AVERROR_EXIT;
  201. }

  202. /** Initialize one data packet for reading or writing. */
  203. static void init_packet(AVPacket *packet)
  204. {
  205.     av_init_packet(packet);
  206.     /** Set the packet data and size so that it is recognized as being empty. */
  207.     packet->data = NULL;
  208.     packet->size = 0;
  209. }

  210. /** Initialize one audio frame for reading from the input file */
  211. static int init_input_frame(AVFrame **frame)
  212. {
  213.     if (!(*frame = av_frame_alloc())) {
  214.         fprintf(stderr, "Could not allocate input frame\n");
  215.         return AVERROR(ENOMEM);
  216.     }
  217.     return 0;
  218. }

  219. /**
  220.  * Initialize the audio resampler based on the input and output codec settings.
  221.  * If the input and output sample formats differ, a conversion is required
  222.  * libswresample takes care of this, but requires initialization.
  223.  */
  224. static int init_resampler(AVCodecContext *input_codec_context,
  225.                           AVCodecContext *output_codec_context,
  226.                           SwrContext **resample_context)
  227. {
  228.         int error;

  229.         /**
  230.          * Create a resampler context for the conversion.
  231.          * Set the conversion parameters.
  232.          * Default channel layouts based on the number of channels
  233.          * are assumed for simplicity (they are sometimes not detected
  234.          * properly by the demuxer and/or decoder).
  235.          */
  236.         //区别于例三,一个函数搞定重采样上下文的初始化
  237.         *resample_context = swr_alloc_set_opts(NULL,
  238.                                               av_get_default_channel_layout(output_codec_context->channels),
  239.                                               output_codec_context->sample_fmt,
  240.                                               output_codec_context->sample_rate,
  241.                                               av_get_default_channel_layout(input_codec_context->channels),
  242.                                               input_codec_context->sample_fmt,
  243.                                               input_codec_context->sample_rate,
  244.                                               0, NULL);
  245.         if (!*resample_context) {
  246.             fprintf(stderr, "Could not allocate resample context\n");
  247.             return AVERROR(ENOMEM);
  248.         }
  249.         /**
  250.         * Perform a sanity check so that the number of converted samples is
  251.         * not greater than the number of samples to be converted.
  252.         * If the sample rates differ, this case has to be handled differently
  253.         */
  254.         //确保输入输出采样率相等,猜测:如果采样率不相等的话,采样数就需要重新计算,但是此段代码中并没有重新计算采样数
  255.         av_assert0(output_codec_context->sample_rate == input_codec_context->sample_rate);

  256.         /** Open the resampler with the specified parameters. */
  257.         if ((error = swr_init(*resample_context)) < 0) {
  258.             fprintf(stderr, "Could not open resample context\n");
  259.             swr_free(resample_context);
  260.             return error;
  261.         }
  262.     return 0;
  263. }

  264. /** Initialize a FIFO buffer for the audio samples to be encoded. */
  265. static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context)
  266. {
  267.     /** Create the FIFO buffer based on the specified output sample format. */
  268.     if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt,
  269.                                       output_codec_context->channels, 1))) {
  270.         fprintf(stderr, "Could not allocate FIFO\n");
  271.         return AVERROR(ENOMEM);
  272.     }
  273.     return 0;
  274. }

  275. /** Write the header of the output file container. */
  276. static int write_output_file_header(AVFormatContext *output_format_context)
  277. {
  278.     int error;
  279.     //写文件头
  280.     if ((error = avformat_write_header(output_format_context, NULL)) < 0) {
  281.         fprintf(stderr, "Could not write output file header (error '%s')\n",
  282.                 get_error_text(error));
  283.         return error;
  284.     }
  285.     return 0;
  286. }

  287. /** Decode one audio frame from the input file. */
  288. static int decode_audio_frame(AVFrame *frame,
  289.                               AVFormatContext *input_format_context,
  290.                               AVCodecContext *input_codec_context,
  291.                               int *data_present, int *finished)
  292. {
  293.     /** Packet used for temporary storage. */
  294.     AVPacket input_packet;
  295.     int error;
  296.     init_packet(&input_packet);

  297.     /** Read one audio frame from the input file into a temporary packet. */
  298.     if ((error = av_read_frame(input_format_context, &input_packet)) < 0) {
  299.         /** If we are at the end of the file, flush the decoder below. */
  300.         if (error == AVERROR_EOF)
  301.             *finished = 1;
  302.         else {
  303.             fprintf(stderr, "Could not read frame (error '%s')\n",
  304.                     get_error_text(error));
  305.             return error;
  306.         }
  307.     }

  308.     /**
  309.      * Decode the audio frame stored in the temporary packet.
  310.      * The input audio stream decoder is used to do this.
  311.      * If we are at the end of the file, pass an empty packet to the decoder
  312.      * to flush it.
  313.      */
  314.     if ((error = avcodec_decode_audio4(input_codec_context, frame,
  315.                                        data_present, &input_packet)) < 0) {
  316.         fprintf(stderr, "Could not decode frame (error '%s')\n",
  317.                 get_error_text(error));
  318.         av_free_packet(&input_packet);
  319.         return error;
  320.     }

  321.     /**
  322.      * If the decoder has not been flushed completely, we are not finished,
  323.      * so that this function has to be called again.
  324.      */
  325.     if (*finished && *data_present)
  326.         *finished = 0;
  327.     av_free_packet(&input_packet);
  328.     return 0;
  329. }

  330. /**
  331.  * Initialize a temporary storage for the specified number of audio samples.
  332.  * The conversion requires temporary storage due to the different format.
  333.  * The number of audio samples to be allocated is specified in frame_size.
  334.  */
  335. static int init_converted_samples(uint8_t ***converted_input_samples,
  336.                                   AVCodecContext *output_codec_context,
  337.                                   int frame_size)
  338. {
  339.     int error;

  340.     /**
  341.      * Allocate as many pointers as there are audio channels.
  342.      * Each pointer will later point to the audio samples of the corresponding
  343.      * channels (although it may be NULL for interleaved formats).
  344.      */
  345.     if (!(*converted_input_samples = calloc(output_codec_context->channels,
  346.                                             sizeof(**converted_input_samples)))) {
  347.         fprintf(stderr, "Could not allocate converted input sample pointers\n");
  348.         return AVERROR(ENOMEM);
  349.     }

  350.     /**
  351.      * Allocate memory for the samples of all channels in one consecutive
  352.      * block for convenience.
  353.      */
  354.     if ((error = av_samples_alloc(*converted_input_samples, NULL,
  355.                                   output_codec_context->channels,
  356.                                   frame_size,
  357.                                   output_codec_context->sample_fmt, 0)) < 0) {
  358.         fprintf(stderr,
  359.                 "Could not allocate converted input samples (error '%s')\n",
  360.                 get_error_text(error));
  361.         av_freep(&(*converted_input_samples)[0]);
  362.         free(*converted_input_samples);
  363.         return error;
  364.     }
  365.     return 0;
  366. }

  367. /**
  368.  * Convert the input audio samples into the output sample format.
  369.  * The conversion happens on a per-frame basis, the size of which is specified
  370.  * by frame_size.
  371.  */
  372. static int convert_samples(const uint8_t **input_data,
  373.                            uint8_t **converted_data, const int frame_size,
  374.                            SwrContext *resample_context)
  375. {
  376.     int error;

  377.     /** Convert the samples using the resampler. */
  378.     if ((error = swr_convert(resample_context,
  379.                              converted_data, frame_size,
  380.                              input_data , frame_size)) < 0) {
  381.         fprintf(stderr, "Could not convert input samples (error '%s')\n",
  382.                 get_error_text(error));
  383.         return error;
  384.     }

  385.     return 0;
  386. }

  387. /** Add converted input audio samples to the FIFO buffer for later processing. */
  388. static int add_samples_to_fifo(AVAudioFifo *fifo,
  389.                                uint8_t **converted_input_samples,
  390.                                const int frame_size)
  391. {
  392.     int error;

  393.     /**
  394.      * Make the FIFO as large as it needs to be to hold both,
  395.      * the old and the new samples.
  396.      */
  397.     if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) {
  398.         fprintf(stderr, "Could not reallocate FIFO\n");
  399.         return error;
  400.     }

  401.     /** Store the new samples in the FIFO buffer. */
  402.     if (av_audio_fifo_write(fifo, (void **)converted_input_samples,
  403.                             frame_size) < frame_size) {
  404.         fprintf(stderr, "Could not write data to FIFO\n");
  405.         return AVERROR_EXIT;
  406.     }
  407.     return 0;
  408. }

  409. /**
  410.  * Read one audio frame from the input file, decodes, converts and stores
  411.  * it in the FIFO buffer.
  412.  */
  413. static int read_decode_convert_and_store(AVAudioFifo *fifo,
  414.                                          AVFormatContext *input_format_context,
  415.                                          AVCodecContext *input_codec_context,
  416.                                          AVCodecContext *output_codec_context,
  417.                                          SwrContext *resampler_context,
  418.                                          int *finished)
  419. {
  420.     /** Temporary storage of the input samples of the frame read from the file. */
  421.     AVFrame *input_frame = NULL;
  422.     /** Temporary storage for the converted input samples. */
  423.     uint8_t **converted_input_samples = NULL;
  424.     int data_present;
  425.     int ret = AVERROR_EXIT;

  426.     /** Initialize temporary storage for one input frame. */
  427.     if (init_input_frame(&input_frame))
  428.         goto cleanup;
  429.     /** Decode one frame worth of audio samples. */
  430.     if (decode_audio_frame(input_frame, input_format_context,
  431.                            input_codec_context, &data_present, finished))
  432.         goto cleanup;
  433.     /**
  434.      * If we are at the end of the file and there are no more samples
  435.      * in the decoder which are delayed, we are actually finished.
  436.      * This must not be treated as an error.
  437.      */
  438.     if (*finished && !data_present) {
  439.         ret = 0;
  440.         goto cleanup;
  441.     }
  442.     /** If there is decoded data, convert and store it */
  443.     //input_frame->nb_samples表示当前帧内数据的长度 MP3一般是1152 aac=1024
  444.     //区别于编解码器上下文中的frame_size是帧最大长度
  445.     if (data_present) {
  446.         /** Initialize the temporary storage for the converted input samples. */
  447.         if (init_converted_samples(&converted_input_samples, output_codec_context,
  448.                                    input_frame->nb_samples))
  449.             goto cleanup;

  450.         /**
  451.          * Convert the input samples to the desired output sample format.
  452.          * This requires a temporary storage provided by converted_input_samples.
  453.          */
  454.         if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples,
  455.                             input_frame->nb_samples, resampler_context))
  456.             goto cleanup;

  457.         /** Add the converted input samples to the FIFO buffer for later processing. */
  458.         if (add_samples_to_fifo(fifo, converted_input_samples,
  459.                                 input_frame->nb_samples))
  460.             goto cleanup;
  461.         ret = 0;
  462.     }
  463.     ret = 0;

  464. cleanup:
  465.     if (converted_input_samples) {
  466.         av_freep(&converted_input_samples[0]);
  467.         free(converted_input_samples);
  468.     }
  469.     av_frame_free(&input_frame);

  470.     return ret;
  471. }

  472. /**
  473.  * Initialize one input frame for writing to the output file.
  474.  * The frame will be exactly frame_size samples large.
  475.  */
  476. static int init_output_frame(AVFrame **frame,
  477.                              AVCodecContext *output_codec_context,
  478.                              int frame_size)
  479. {
  480.     int error;

  481.     /** Create a new frame to store the audio samples. */
  482.     if (!(*frame = av_frame_alloc())) {
  483.         fprintf(stderr, "Could not allocate output frame\n");
  484.         return AVERROR_EXIT;
  485.     }

  486.     /**
  487.      * Set the frame's parameters, especially its size and format.
  488.      * av_frame_get_buffer needs this to allocate memory for the
  489.      * audio samples of the frame.
  490.      * Default channel layouts based on the number of channels
  491.      * are assumed for simplicity.
  492.      */
  493.     (*frame)->nb_samples = frame_size;
  494.     (*frame)->channel_layout = output_codec_context->channel_layout;
  495.     (*frame)->format = output_codec_context->sample_fmt;
  496.     (*frame)->sample_rate = output_codec_context->sample_rate;

  497.     /**
  498.      * Allocate the samples of the created frame. This call will make
  499.      * sure that the audio frame can hold as many samples as specified.
  500.      */
  501.     if ((error = av_frame_get_buffer(*frame, 0)) < 0) {
  502.         fprintf(stderr, "Could allocate output frame samples (error '%s')\n",
  503.                 get_error_text(error));
  504.         av_frame_free(frame);
  505.         return error;
  506.     }

  507.     return 0;
  508. }

  509. /** Global timestamp for the audio frames */
  510. static int64_t pts = 0;

  511. /** Encode one frame worth of audio to the output file. */
  512. static int encode_audio_frame(AVFrame *frame,
  513.                               AVFormatContext *output_format_context,
  514.                               AVCodecContext *output_codec_context,
  515.                               int *data_present)
  516. {
  517.     /** Packet used for temporary storage. */
  518.     AVPacket output_packet;
  519.     int error;
  520.     init_packet(&output_packet);

  521.     /** Set a timestamp based on the sample rate for the container. */
  522.     if (frame) {
  523.         frame->pts = pts;
  524.         pts += frame->nb_samples;
  525.     }

  526.     /**
  527.      * Encode the audio frame and store it in the temporary packet.
  528.      * The output audio stream encoder is used to do this.
  529.      */
  530.     if ((error = avcodec_encode_audio2(output_codec_context, &output_packet,
  531.                                        frame, data_present)) < 0) {
  532.         fprintf(stderr, "Could not encode frame (error '%s')\n",
  533.                 get_error_text(error));
  534.         av_free_packet(&output_packet);
  535.         return error;
  536.     }

  537.     /** Write one audio frame from the temporary packet to the output file. */
  538.     if (*data_present) {
  539.         if ((error = av_write_frame(output_format_context, &output_packet)) < 0) {
  540.             fprintf(stderr, "Could not write frame (error '%s')\n",
  541.                     get_error_text(error));
  542.             av_free_packet(&output_packet);
  543.             return error;
  544.         }

  545.         av_free_packet(&output_packet);
  546.     }

  547.     return 0;
  548. }

  549. /**
  550.  * Load one audio frame from the FIFO buffer, encode and write it to the
  551.  * output file.
  552.  */
  553. static int load_encode_and_write(AVAudioFifo *fifo,
  554.                                  AVFormatContext *output_format_context,
  555.                                  AVCodecContext *output_codec_context)
  556. {
  557.     /** Temporary storage of the output samples of the frame written to the file. */
  558.     AVFrame *output_frame;
  559.     /**
  560.      * Use the maximum number of possible samples per frame.
  561.      * If there is less than the maximum possible frame size in the FIFO
  562.      * buffer use this number. Otherwise, use the maximum possible frame size
  563.      */
  564.     const int frame_size = FFMIN(av_audio_fifo_size(fifo),
  565.                                  output_codec_context->frame_size);
  566.     int data_written;

  567.     /** Initialize temporary storage for one output frame. */
  568.     if (init_output_frame(&output_frame, output_codec_context, frame_size))
  569.         return AVERROR_EXIT;

  570.     /**
  571.      * Read as many samples from the FIFO buffer as required to fill the frame.
  572.      * The samples are stored in the frame temporarily.
  573.      */
  574.     if (av_audio_fifo_read(fifo, (void **)output_frame->data, frame_size) < frame_size) {
  575.         fprintf(stderr, "Could not read data from FIFO\n");
  576.         av_frame_free(&output_frame);
  577.         return AVERROR_EXIT;
  578.     }

  579.     /** Encode one frame worth of audio samples. */
  580.     if (encode_audio_frame(output_frame, output_format_context,
  581.                            output_codec_context, &data_written)) {
  582.         av_frame_free(&output_frame);
  583.         return AVERROR_EXIT;
  584.     }
  585.     av_frame_free(&output_frame);
  586.     return 0;
  587. }

  588. /** Write the trailer of the output file container. */
  589. static int write_output_file_trailer(AVFormatContext *output_format_context)
  590. {
  591.     int error;
  592.     if ((error = av_write_trailer(output_format_context)) < 0) {
  593.         fprintf(stderr, "Could not write output file trailer (error '%s')\n",
  594.                 get_error_text(error));
  595.         return error;
  596.     }
  597.     return 0;
  598. }

  599. /** Convert an audio file to an AAC file in an MP4 container. */
  600. int main(int argc, char **argv)
  601. {
  602.     //输入输出格式上下文
  603.     AVFormatContext *input_format_context = NULL, *output_format_context = NULL;
  604.     //解码器上下文、编码器上下文
  605.     AVCodecContext *input_codec_context = NULL, *output_codec_context = NULL;
  606.     //重采样上下文
  607.     SwrContext *resample_context = NULL;
  608.     //音频fifo
  609.     AVAudioFifo *fifo = NULL;
  610.     int ret = AVERROR_EXIT;

  611.     if (argc < 3) {
  612.         fprintf(stderr, "Usage: %s  \n", argv[0]);
  613.         exit(1);
  614.     }

  615.     /** Register all codecs and formats so that they can be used. */
  616.     av_register_all();
  617.     /** Open the input file for reading. */
  618.     //填充了输入格式上下文,并且打开了相对应的解码器
  619.     if (open_input_file(argv[1], &input_format_context,
  620.                         &input_codec_context))
  621.         goto cleanup;
  622.     /** Open the output file for writing. */
  623.     //填充输出格式上下文,打开io上下文,流的初始化,编码器的初始化
  624.     if (open_output_file(argv[2], input_codec_context,
  625.                          &output_format_context, &output_codec_context))
  626.         goto cleanup;
  627.     /** Initialize the resampler to be able to convert audio sample formats. */
  628.     //初始化重采样上下文
  629.     if (init_resampler(input_codec_context, output_codec_context,
  630.                        &resample_context))
  631.         goto cleanup;
  632.     /** Initialize the FIFO buffer to store audio samples to be encoded. */
  633.     //初始化音频fifo
  634.     if (init_fifo(&fifo, output_codec_context))
  635.         goto cleanup;
  636.     /** Write the header of the output file container. */
  637.     /
  638.     if (write_output_file_header(output_format_context))
  639.         goto cleanup;

  640.     /**
  641.      * Loop as long as we have input samples to read or output samples
  642.      * to write; abort as soon as we have neither.
  643.      */
  644.     while (1) {
  645.         /** Use the encoder's desired frame size for processing. */
  646.         const int output_frame_size = output_codec_context->frame_size;
  647.         int finished = 0;

  648.         /**
  649.          * Make sure that there is one frame worth of samples in the FIFO
  650.          * buffer so that the encoder can do its work.
  651.          * Since the decoder'and the encoder's frame size may differ, we
  652.          * need to FIFO buffer to store as many frames worth of input samples
  653.          * that they make up at least one frame worth of output samples.
  654.          */
  655.         //检查fifo里面的数据是否大于要输出的帧的大小,如果不大于,那么将解码转换的数据存放的fifo中
  656.         while (av_audio_fifo_size(fifo) < output_frame_size) {
  657.             /**
  658.              * Decode one frame worth of audio samples, convert it to the
  659.              * output sample format and put it into the FIFO buffer.
  660.              */
  661.             if (read_decode_convert_and_store(fifo, input_format_context,
  662.                                               input_codec_context,
  663.                                               output_codec_context,
  664.                                               resample_context, &finished))
  665.                 goto cleanup;

  666.             /**
  667.              * If we are at the end of the input file, we continue
  668.              * encoding the remaining audio samples to the output file.
  669.              */
  670.             if (finished)
  671.                 break;
  672.         }
  673.         
  674.         /**
  675.          * If we have enough samples for the encoder, we encode them.
  676.          * At the end of the file, we pass the remaining samples to
  677.          * the encoder.
  678.          */
  679.         //检查fifo数据是否大于输出帧的大小,或者(到文件末尾并且fifo数据长度大于0)
  680.         while (av_audio_fifo_size(fifo) >= output_frame_size ||
  681.                (finished && av_audio_fifo_size(fifo) > 0))
  682.             /**
  683.              * Take one frame worth of audio samples from the FIFO buffer,
  684.              * encode it and write it to the output file.
  685.              */
  686.             //读fifo,编码,写入文件
  687.             if (load_encode_and_write(fifo, output_format_context,
  688.                                       output_codec_context))
  689.                 goto cleanup;

  690.         /**
  691.          * If we are at the end of the input file and have encoded
  692.          * all remaining samples, we can exit this loop and finish.
  693.          */
  694.         if (finished) {
  695.             int data_written;
  696.             /** Flush the encoder as it may have delayed frames. */
  697.             //刷新编码器中可能存在的延时帧
  698.             do {
  699.                 if (encode_audio_frame(NULL, output_format_context,
  700.                                        output_codec_context, &data_written))
  701.                     goto cleanup;
  702.             } while (data_written);
  703.             break;
  704.         }
  705.     }

  706.     /** Write the trailer of the output file container. */
  707.     //写文件尾
  708.     if (write_output_file_trailer(output_format_context))
  709.         goto cleanup;
  710.     ret = 0;

  711. cleanup:
  712.     if (fifo)
  713.         av_audio_fifo_free(fifo);
  714.     swr_free(&resample_context);
  715.     if (output_codec_context)
  716.         avcodec_close(output_codec_context);
  717.     if (output_format_context) {
  718.         avio_closep(&output_format_context->pb);
  719.         avformat_free_context(output_format_context);
  720.     }
  721.     if (input_codec_context)
  722.         avcodec_close(input_codec_context);
  723.     if (input_format_context)
  724.         avformat_close_input(&input_format_context);

  725.     return ret;
  726. }
基本的流程:从输入文件中解码出一帧音频(音频数据保存在input_frame->extended_data),把音频数据进行格式转换并且保存到fifo中
从音频fifo中读音频数据(output_frame->data),进行编码,写入文件
1、从输入文件解码出一帧
avformat_open_input->avformat_find_stream_info->avcodec_find_decoder->avcodec_open2->av_frame_alloc->av_init_packet->av_read_frame->avcodec_decode_audio4(至此获得一帧音频数据)->av_free_packet->av_frame_free->avcodec_close->avformat_close_input
至此,已经获取了一帧数据
2、重采样
swr_alloc_set_opts->swr_init->av_samples_alloc->swr_convert->swr_free
3、音频fifo
av_audio_fifo_alloc->av_audio_fifo_realloc->av_audio_fifo_write->av_audio_fifo_read->av_audio_fifo_free
4、编码写入文件
avio_open->avformat_alloc_context->av_guess_format->avcodec_find_encoder->avformat_new_stream->avcodec_open2->avformat_write_header->av_frame_alloc->av_init_packet->avcodec_encode_audio2->av_write_frame->av_free_packet->av_frame_free->av_write_trailer

总结:音频fifo是比较重要的,fifo在处理音频的时候几乎是必须的, 也可以自己实现一个fifo,不过ffmpeg既然实现了,自己写也一样,没啥必要
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值