FFmpeg——视频编码的流程

视频编码的流程:

流程中各个函数的含义:

1. av_register_all()

功能:

初始化所有组件,该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。

该接口内部的调用为:

(1).avcodec_register_all(),该接口内部执行步骤:

 - 注册硬件加速器:REGISTER_HWACCEL()
 - 注册音视频编码器:REGISTER_ENCODER()
 - 注册音视频解码器:REGISTER_DECODER()
 - 打包注册:REGISTER_ENCDEC()
 - 注册解析器:REGISTER_PARSER()

(2).执行复用器和解复用器的注册:

- 注册复用器:REGISTER_MUXER()
 - 注册解复用器:REGISTER_DEMUXER()
 - 既有解复用器又有复用器: REGISTER_MUXDEMUX(X,x));

2. avformat_alloc_output_context2()

功能

avformat_alloc_output_context2()函数可以初始化一个用于输出的AVFormatContext结构体。它的声明位于libavformat\avformat.h。

函数声明

/**
 * Allocate an AVFormatContext for an output format.
 * avformat_free_context() can be used to free the context and
 * everything allocated by the framework within it.
 *
 * @param *ctx is set to the created format context, or to NULL in
 * case of failure
 * @param oformat format to use for allocating the context, if NULL
 * format_name and filename are used instead
 * @param format_name the name of output format to use for allocating the
 * context, if NULL filename is used instead
 * @param filename the name of the filename to use for allocating the
 * context, may be NULL
 * @return >= 0 in case of success, a negative AVERROR code in case of
 * failure
 */
int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat,
                                   const char *format_name, const char *filename);

参数说明

ctx:函数调用成功之后创建的AVFormatContext结构体。

oformat:指定AVFormatContext中的AVOutputFormat,用于确定输出格式。如果指定为NULL,可以设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式。

PS:使用该参数需要自己手动获取AVOutputFormat,相对于使用后两个参数来说要麻烦一些。

format_name:指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,“mkv”等等。

返回值

函数执行成功的话,其返回值大于等于0。

调用关系

avformat_alloc_output_context2()的流程如要包含以下2步:

调用avformat_alloc_context()初始化一个默认的AVFormatContext。

如果指定了输入的AVOutputFormat,则直接将输入的AVOutputFormat赋值给AVOutputFormat的oformat。如果没有指定输入的AVOutputFormat,就需要根据文件格式名称或者文件名推测输出的AVOutputFormat。无论是通过文件格式名称还是文件名推测输出格式,都会调用一个函数av_guess_format()。

3. avio_open()

  1. 功能
    该函数用于打开FFmpeg的输入输出文件。avio_open2()的声明位于libavformat\avio.h文件中。
  2. 声明
/**
 * Create and initialize a AVIOContext for accessing the
 * resource indicated by url.
 * @note When the resource indicated by url has been opened in
 * read+write mode, the AVIOContext can be used only for writing.
 *
 * @param s Used to return the pointer to the created AVIOContext.
 * In case of failure the pointed to value is set to NULL.
 * @param url resource to access
 * @param flags flags which control how the resource indicated by url
 * is to be opened
 * @return >= 0 in case of success, a negative value corresponding to an
 * AVERROR code in case of failure
 */
int avio_open(AVIOContext **s, const char *url, int flags);

参数含义

s:函数调用成功之后创建的AVIOContext结构体。

url:输入输出协议的地址(文件也是一种“广义”的协议,对于文件来说就是文件的路径)。

flags:打开地址的方式。可以选择只读,只写,或者读写。取值如下。 AVIO_FLAG_READ:只读。 AVIO_FLAG_WRITE:只写。 AVIO_FLAG_READ_WRITE:读写。

有一个和avio_open()“长得很像”的函数avio_open2(),应该是avio_open()的后期版本。avio_open()比avio_open2()少了最后2个参数。而它前面几个参数的含义和avio_open2()是一样的。从源代码中可以看出,avio_open()内部调用了avio_open2(),并且把avio_open2()的后2个参数设置成了NULL,因此它的功能实际上和avio_open2()是一样的。avio_open()源代码如下所示。

4. avformat_new_stream()

  1. 功能
    avformat_new_stream 在 AVFormatContext 中创建 Stream 通道。
  2. 声明
/**
 * Add a new stream to a media file.
 *
 * When demuxing, it is called by the demuxer in read_header(). If the
 * flag AVFMTCTX_NOHEADER is set in s.ctx_flags, then it may also
 * be called in read_packet().
 *
 * When muxing, should be called by the user before avformat_write_header().
 *
 * User is required to call avcodec_close() and avformat_free_context() to
 * clean up the allocation by avformat_new_stream().
 *
 * @param s media file handle
 * @param c If non-NULL, the AVCodecContext corresponding to the new stream
 * will be initialized to use this codec. This is needed for e.g. codec-specific
 * defaults to be set, so codec should be provided if it is known.
 *
 * @return newly created stream or NULL on error.
 */
AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);

5. avcodec_find_encoder()

  1. 功能
    avcodec_find_encoder()用于查找FFmpeg的编码器
  2. 定义
	/**
	 * avcodec_find_encoder()的声明位于libavcodec\avcodec.h
	 * Find a registered encoder with a matching codec ID.
	 *
	 * @param id AVCodecID of the requested encoder
	 * @return An encoder if one was found, NULL otherwise.
	 */
	AVCodec *avcodec_find_encoder(enum AVCodecID id);
  1. 参数
    函数的参数是一个编码器的ID,返回查找到的编码器(没有找到就返回NULL)。
  2. 函数调用关系图

6. avcodec_open2()

  1. 功能
    该函数用于初始化一个视音频编解码器的AVCodecContext。avcodec_open2()的声明位于libavcodec\avcodec.h。
  2. 声明
/**
 * Initialize the AVCodecContext to use the given AVCodec. Prior to using this
 * function the context has to be allocated with avcodec_alloc_context3().
 *
 * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(),
 * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for
 * retrieving a codec.
 *
 * @warning This function is not thread safe!
 *
 * @note Always call this function before using decoding routines (such as
 * @ref avcodec_receive_frame()).
 *
 * @code
 * avcodec_register_all();
 * av_dict_set(&opts, "b", "2.5M", 0);
 * codec = avcodec_find_decoder(AV_CODEC_ID_H264);
 * if (!codec)
 *     exit(1);
 *
 * context = avcodec_alloc_context3(codec);
 *
 * if (avcodec_open2(context, codec, opts) < 0)
 *     exit(1);
 * @endcode
 *
 * @param avctx The context to initialize.
 * @param codec The codec to open this context for. If a non-NULL codec has been
 *              previously passed to avcodec_alloc_context3() or
 *              for this context, then this parameter MUST be either NULL or
 *              equal to the previously passed codec.
 * @param options A dictionary filled with AVCodecContext and codec-private options.
 *                On return this object will be filled with options that were not found.
 *
 * @return zero on success, a negative value on error
 * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(),
 *      av_dict_set(), av_opt_find().
 */
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
  1. 参数
    avctx:需要初始化的AVCodecContext。
    codec:输入的AVCodec
    options:一些选项。例如使用libx264编码的时候,“preset”,“tune”等都可以通过该参数设置。
  2. 调用关系

梳理一下avcodec_open2()所做的工作,如下所列:

(1)为各种结构体分配内存(通过各种av_malloc()实现)。

(2)将输入的AVDictionary形式的选项设置到AVCodecContext。

(3)其他一些零零碎碎的检查,比如说检查编解码器是否处于“实验”阶段。

(4)如果是编码器,检查输入参数是否符合编码器的要求

(5)调用AVCodec的init()初始化具体的解码器。

7. avformat_write_header()

功能

avformat_write_header()用于写视频文件头。

需要注意的是,尽管这3个函数功能是配套的,但是它们的前缀却不一样,写文件头Header的函数前缀是“avformat_”,其他两个函数前缀是“av_”。

声明

/**
 * Allocate the stream private data and write the stream header to
 * an output media file.
 *
 * @param s Media file handle, must be allocated with avformat_alloc_context().
 *          Its oformat field must be set to the desired output format;
 *          Its pb field must be set to an already opened AVIOContext.
 * @param options  An AVDictionary filled with AVFormatContext and muxer-private options.
 *                 On return this parameter will be destroyed and replaced with a dict containing
 *                 options that were not found. May be NULL.
 *
 * @return AVSTREAM_INIT_IN_WRITE_HEADER on success if the codec had not already been fully initialized in avformat_init,
 *         AVSTREAM_INIT_IN_INIT_OUTPUT  on success if the codec had already been fully initialized in avformat_init,
 *         negative AVERROR on failure.
 *
 * @see av_opt_find, av_dict_set, avio_open, av_oformat_next, avformat_init_output.
 */
函数正常执行后返回值等于0。
av_warn_unused_result
int avformat_write_header(AVFormatContext *s, AVDictionary **options);

参数的含义:
s:用于输出的AVFormatContext。
options:额外的选项,目前没有深入研究过,一般为NULL。

8. av_write_frame()

  1. 功能
    用于输出一帧视音频数据,它的声明位于libavformat\avformat.h。
  2. 声明
/**
 * Write a packet to an output media file.
 *
 * This function passes the packet directly to the muxer, without any buffering
 * or reordering. The caller is responsible for correctly interleaving the
 * packets if the format requires it. Callers that want libavformat to handle
 * the interleaving should call av_interleaved_write_frame() instead of this
 * function.
 *
 * @param s media file handle
 * @param pkt The packet containing the data to be written. Note that unlike
 *            av_interleaved_write_frame(), this function does not take
 *            ownership of the packet passed to it (though some muxers may make
 *            an internal reference to the input packet).
 *            <br>
 *            This parameter can be NULL (at any time, not just at the end), in
 *            order to immediately flush data buffered within the muxer, for
 *            muxers that buffer up data internally before writing it to the
 *            output.
 *            <br>
 *            Packet's @ref AVPacket.stream_index "stream_index" field must be
 *            set to the index of the corresponding stream in @ref
 *            AVFormatContext.streams "s->streams".
 *            <br>
 *            The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts")
 *            must be set to correct values in the stream's timebase (unless the
 *            output format is flagged with the AVFMT_NOTIMESTAMPS flag, then
 *            they can be set to AV_NOPTS_VALUE).
 *            The dts for subsequent packets passed to this function must be strictly
 *            increasing when compared in their respective timebases (unless the
 *            output format is flagged with the AVFMT_TS_NONSTRICT, then they
 *            merely have to be nondecreasing).  @ref AVPacket.duration
 *            "duration") should also be set if known.
 * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush
 *
 * @see av_interleaved_write_frame()
 */
int av_write_frame(AVFormatContext *s, AVPacket *pkt);

参数的含义:
s:用于输出的AVFormatContext。
pkt:等待输出的AVPacket。
函数正常执行后返回值等于0。

从源代码可以看出,av_write_frame()主要完成了以下几步工作:
(1)调用check_packet()做一些简单的检测
(2)调用compute_pkt_fields2()设置AVPacket的一些属性值
(3)调用write_packet()写入数据

9. av_write_trailer()

  1. 功能
    用于输出文件尾,它的声明位于libavformat\avformat.h。
    它只需要指定一个参数,即用于输出的AVFormatContext。
    函数正常执行后返回值等于0。
  2. 声明
/**
 * Write the stream trailer to an output media file and free the
 * file private data.
 *
 * May only be called after a successful call to avformat_write_header.
 *
 * @param s media file handle
 * @return 0 if OK, AVERROR_xxx on error
 */
int av_write_trailer(AVFormatContext *s);

从源代码可以看出av_write_trailer()主要完成了以下两步工作:

(1)循环调用interleave_packet()以及write_packet(),将还未输出的AVPacket输出出来。

(2)调用AVOutputFormat的write_trailer(),输出文件尾。

AVOutputFormat的write_trailer()是一个函数指针,指向特定的AVOutputFormat中的实现函数。

原文链接:FFmpeg--视频编码的流程_ffmepg format_name_WaitFoF的博客-CSDN博客

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

猜你喜欢

转载自blog.csdn.net/yinshipin007/article/details/131091683