简单的视频编码器(不使用libavformat)

这里仅仅说明的是将YUV数据编码为特定编码格式的压缩视频码流的一个过程。只使用libavcodec,不使用libavformat封装。
相关的流程可以参照下面的流程图

简单的视频编码器(不使用libavformat)
好了接下来就来看看具体的代码流程。(需要比较的话可以和纯净版的解码器代码流程进行比较)
编码器使用了两个模块:
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/imgutils.h"
libavutil模块包含一些公共的工具函数的使用库,包括算数运算字符操作,这里我们遇到了再说
在主函数中,首先就是定义各种变量和结构体。而其中主要的结构体就是AVCodec、AVCodecContextAVFrame和AVPacket
与解码器来比,缺少了一个AVCodecParserContext结构体的使用。
****************************************************************************************************************************************************
首先来看下流程的开始 avcodec_register_all() (大家一看就知道,和解码器没有什么太大的区别)
为了简洁,我们可以去查看一下解码器那的说明分析,这里就不再做过多的阐述。
****************************************************************************************************************************************************
流程相对于解码器还是很相似,紧接着就会调用avcodec_find_decoder()
这个函数之前也有介绍过,这边先调用了。这个调用的顺序其实还是比较灵活的,其实也可以说在调用avcodec_open2()之前调用就好。
而参数中的AVCodecID 这个就需要想办法获取到了,之前的那个播放器里边,应该是调用了avformat_find_stream_info()才获取到的。这个我没有去仔细去看代码,之后再来证实——————————需要证实
我们可以在libavformat目录下的utils.c 找到
AVCodec *avcodec_find_decoder(enum AVCodecID id)
{
    return find_encdec(id, 0);
}
****************************************************************************************************************************************************
之后就调用avcodec_alloc_context3
函数的定义位于libavcodec目录下的avcodec.h
/**
* Allocate an AVCodecContext and set its fields to default values. The
* resulting struct should be freed with avcodec_free_context().
* 分配avcodectext并将其字段设置为默认值。由此产生的结构应该用avcodec_free_text()释放。
*
* @param codec if non-NULL, allocate private data and initialize defaults
*              for the given codec. It is illegal to then call avcodec_open2()
*              with a different codec.
*              If NULL, then the codec-specific defaults won't be initialized,
*              which may result in suboptimal default settings (this is
*              important mainly for encoders, e.g. libx264).
*
* @return An AVCodecContext filled with default values or NULL on failure.
*/
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
函数的实现是在libavcodec目录下的options.c
AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
{
    AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));
    if (!avctx)
        return NULL;
    if (init_context_defaults(avctx, codec) < 0) {
        av_free(avctx);
        return NULL;
    }
    return avctx;
}
****************************************************************************************************************************************************
之后就直接调用avcodec_open2了
这个函数在之前也出现过,那就再温习一下
函数是在libavcodec目录下的avcodec.h里边定义的
/**
* Initialize the AVCodecContext to use the given AVCodec. Prior to using this
* function the context has to be allocated with avcodec_alloc_context3().
* 初始化avcodectext以使用给定的avcodece。在使用此函数之前,必须使用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.
* avcodec_find_declder_by_name()、avcodec_find_encoder_by_name()、avcodec_find_decoder() 和 avcodec_find_encoder()
* 函数为检索编解码器提供了一种简单的方法。
*
* @warning This function is not thread safe!这个函数不是线程安全的!
*
* @note Always call this function before using decoding routines (such as
* @ref avcodec_receive_frame()).
* 总是调用这个函数之前使用解码例程(如 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);
函数是在libavcodec目录下的utils.c实现的
代码有点长  就不贴上来了
avcodec_open2()中最关键的一步就是调用AVCodec的init()方法初始化具体的编码器。AVCodec的init()是一个函数指针,指向具体编解码器中的初始化函数。
avcodec_open2()所做的工作,如下所列:
(1)为各种结构体分配内存(通过各种av_malloc()实现)。
(2)将输入的AVDictionary形式的选项设置到AVCodecContext。
(3)其他一些零零碎碎的检查,比如说检查编解码器是否处于“实验”阶段。
(4)如果是编码器,检查输入参数是否符合编码器的要求
(5)调用AVCodec的init()初始化具体的解码器。
****************************************************************************************************************************************************
之后就是调用avcodec_encode_video2()函数了
这个函数现在也弃用了,但是他的定义和实现还是在这里说明一下。
函数的定义位于libavcodec目录下的avcodec.h
/**
* Encode a frame of video.
*
* Takes input raw video data from frame and writes the next output packet, if
* available, to avpkt. The output packet does not necessarily contain data for
* the most recent frame, as encoders can delay and reorder input frames
* internally as needed.
*
* @param avctx     codec context
* @param avpkt     output AVPacket.
*                  The user can supply an output buffer by setting
*                  avpkt->data and avpkt->size prior to calling the
*                  function, but if the size of the user-provided data is not
*                  large enough, encoding will fail. All other AVPacket fields
*                  will be reset by the encoder using av_init_packet(). If
*                  avpkt->data is NULL, the encoder will allocate it.
*                  The encoder will set avpkt->size to the size of the
*                  output packet. The returned data (if any) belongs to the
*                  caller, he is responsible for freeing it.
*
*                  If this function fails or produces no output, avpkt will be
*                  freed using av_packet_unref().
* @param[in] frame AVFrame containing the raw video data to be encoded.
*                  May be NULL when flushing an encoder that has the
*                  AV_CODEC_CAP_DELAY capability set.
* @param[out] got_packet_ptr This field is set to 1 by libavcodec if the
*                            output packet is non-empty, and to 0 if it is
*                            empty. If the function returns an error, the
*                            packet can be assumed to be invalid, and the
*                            value of got_packet_ptr is undefined and should
*                            not be used.
* @return          0 on success, negative error code on failure
*
* @deprecated use avcodec_send_frame()/avcodec_receive_packet() instead
*/
attribute_deprecated
int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt,
                          const AVFrame *frame, int *got_packet_ptr);
函数的实现位于 libavcodec目录下的encodec.c
代码有点长就不贴了
****************************************************************************************************************************************************
最后,还是那些资源释放函数的调用
可以参考一下之前的编解码器的资源释放函数代码分析
****************************************************************************************************************************************************


可以参考一下大神的博客: