【FFmpeg】AVCodec结构体

发布于:2024-06-22 ⋅ 阅读:(141) ⋅ 点赞:(0)

参考:
FFMPEG结构体分析:AVCodec

示例工程:
【FFmpeg】调用ffmpeg库实现264软编
【FFmpeg】调用ffmpeg库实现264软解
【FFmpeg】调用ffmpeg库进行RTMP推流和拉流
【FFmpeg】调用ffmpeg库进行SDL2解码后渲染

流程分析:
【FFmpeg】编码链路上主要函数的简单分析
【FFmpeg】解码链路上主要函数的简单分析

本文参考了雷博士的文章,但不同之处在于记录的FFmpeg版本为7.0,由于FFmpeg有些更新,所以部分内容有些不太一样

1. AVCodec的定义

AVCodec是FFmpeg中最重要的结构体之一,它记录了编解码器中的重要信息,其定义位于libavcodec\codec.h中,如下所示

/**
 * AVCodec.
 */
typedef struct AVCodec {
    /**
     * Name of the codec implementation.
     * The name is globally unique among encoders and among decoders (but an
     * encoder and a decoder can share the same name).
     * This is the primary way to find a codec from the user perspective.
     */
    const char *name;				// 编解码器的名称
    /**
     * Descriptive name for the codec, meant to be more human readable than name.
     * You should use the NULL_IF_CONFIG_SMALL() macro to define it.
     */
    const char *long_name;			// 编解码器的全称
    enum AVMediaType type;			// 类型,指明是视频、音频还是字幕(如AVMEDIA_TYPE_VIDEO)
    enum AVCodecID id;				// Codec的ID(如AV_CODEC_ID_H264)
    /**
     * Codec capabilities.
     * see AV_CODEC_CAP_*
     */
    // capabilities表示了codec的能力,例如配置为AV_CODEC_CAP_ENCODER_RECON_FRAME
    // 编码器能够输出重构的帧数据,即通过解码编码的比特流产生的原始帧。重构帧输出由AV_CODEC_FLAG_RECON_FRAME标志启用
    int capabilities;						
	// 解码器支持的最大的低分辨率
    uint8_t max_lowres;                     ///< maximum value for lowres supported by the decoder
    // 【视频】支持的帧率,有多个支持的帧率,则为数组 AVRational = {int num, int den}
    const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0}
    // 【视频】支持的像素格式,有多个支持的格式,则为数组(如AV_PIX_FMT_YUV420P)
    const enum AVPixelFormat *pix_fmts;     ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
    // 【音频】支持的采样率,有多个支持的采样率,则为数组
    const int *supported_samplerates;       ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
    // 【音频】支持的采样格式,有多个支持的采样格式,则为数组
    const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
    // 描述AVClass上下文结构的类。这是一个任意结构体,其第一个字段是指向AVClass结构体的指针(例如AVCodecContext, AVFormatContext等)
    // 这里应该是替代了早期的priv_data_size
    const AVClass *priv_class;              ///< AVClass for the private context
    // 被识别的配置文件数组,如果未知则为NULL,数组以{AV_PROFILE_UNKNOWN}终止
    const AVProfile *profiles;              ///< array of recognized profiles, or NULL if unknown, array is terminated by {AV_PROFILE_UNKNOWN}

    /**
     * Group name of the codec implementation.
     * This is a short symbolic name of the wrapper backing this codec. A
     * wrapper uses some kind of external implementation for the codec, such
     * as an external library, or a codec implementation provided by the OS or
     * the hardware.
     * If this field is NULL, this is a builtin, libavcodec native codec.
     * If non-NULL, this will be the suffix in AVCodec.name in most cases
     * (usually AVCodec.name will be of the form "<codec_name>_<wrapper_name>").
     */
    // 编解码器实现的组名称
	// 这是支持此编解码器的包装器的简短符号名称。包装器为编解码器使用某种外部实现,
	// 例如外部库,或者由操作系统或硬件提供的编解码器实现。如果该字段为NULL,
	// 则这是一个内置的libavcodec本机编解码器。如果非null,在大多数情况下,
	// 这将是AVCodec.name中的后缀(通常AVCodec.name将具有“<codec_name>_<wrapper_name>”的形式)
    const char *wrapper_name;

    /**
     * Array of supported channel layouts, terminated with a zeroed layout.
     */
    // 【音频】支持的声道数,如果有多个,则维数组
    const AVChannelLayout *ch_layouts;
} AVCodec;

2. AVCodec内结构体嵌套

2.1 enum AVMediaType type

AVMediaType的声明位于libavutil/avutil.h,定义了媒体的类型,例如视频、音频,其余的不太理解,如下所示

/**
 * @addtogroup lavu_media Media Type
 * @brief Media Type
 */

enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATA
    AVMEDIA_TYPE_VIDEO,
    AVMEDIA_TYPE_AUDIO,
    AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuous
    AVMEDIA_TYPE_SUBTITLE,
    AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparse
    AVMEDIA_TYPE_NB
};

2.2 enum AVCodecID id

AVCodecID的声明位于libavcodec\codec_id.h,标识了codec使用的类型

/**
 * Identify the syntax and semantics of the bitstream.
 * The principle is roughly:
 * Two decoders with the same ID can decode the same streams.
 * Two encoders with the same ID can encode compatible streams.
 * There may be slight deviations from the principle due to implementation
 * details.
 *
 * If you add a codec ID to this list, add it so that
 * 1. no value of an existing codec ID changes (that would break ABI),
 * 2. it is as close as possible to similar codecs
 *
 * After adding new codec IDs, do not forget to add an entry to the codec
 * descriptor list and bump libavcodec minor version.
 */
// 确定位流的语法和语义
// 原则大致为:
// (1)两个具有相同ID的解码器能够解码出来相同的码流
// (2)两个具有相同ID的编码器能够编码出来兼容的码流
// 由于实现细节的原因,可能会与原则有轻微的偏差
// 如果将编解码器ID添加到此列表中,则添加它以便
// (1)现有编解码器ID的值不会改变(这会破坏ABI),
// (2)它尽可能接近类似的编解码器
// 在添加新的编解码器id之后,不要忘记在编解码器描述符列表中添加一个条目,并将libavcodec的次要版本升级
enum AVCodecID {
    AV_CODEC_ID_NONE,

    /* video codecs */
    AV_CODEC_ID_MPEG1VIDEO,
    AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
    AV_CODEC_ID_H261,
    AV_CODEC_ID_H263,
    AV_CODEC_ID_RV10,
    AV_CODEC_ID_RV20,
    AV_CODEC_ID_MJPEG,
    AV_CODEC_ID_MJPEGB,
    AV_CODEC_ID_LJPEG,
    AV_CODEC_ID_SP5X,
    AV_CODEC_ID_JPEGLS,
    AV_CODEC_ID_MPEG4,
    AV_CODEC_ID_RAWVIDEO,
    AV_CODEC_ID_MSMPEG4V1,
    AV_CODEC_ID_MSMPEG4V2,
    AV_CODEC_ID_MSMPEG4V3,
    AV_CODEC_ID_WMV1,
    AV_CODEC_ID_WMV2,
    AV_CODEC_ID_H263P,
    AV_CODEC_ID_H263I,
    AV_CODEC_ID_FLV1,
    AV_CODEC_ID_SVQ1,
    AV_CODEC_ID_SVQ3,
    AV_CODEC_ID_DVVIDEO,
    AV_CODEC_ID_HUFFYUV,
    AV_CODEC_ID_CYUV,
    AV_CODEC_ID_H264,	// H264标准
    // ...

2.3 const AVRational *supported_framerates

AVRational的声明位于libavutil\avutil.c中,常用于表示一些计数

/**
 * Rational number (pair of numerator and denominator).
 */
typedef struct AVRational{
	// 分子
    int num; ///< Numerator
    // 分母
    int den; ///< Denominator
} AVRational;

2.4 const enum AVPixelFormat *pix_fmts

AVPixelFormat的定义位于libavutil\pixfmt.h中,描述了pixel的格式,其中最为常见的应该是YUV420P

/**
 * Pixel format.
 *
 * @note
 * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA
 * color is put together as:
 *  (A << 24) | (R << 16) | (G << 8) | B
 * This is stored as BGRA on little-endian CPU architectures and ARGB on
 * big-endian CPUs.
 *
 * @note
 * If the resolution is not a multiple of the chroma subsampling factor
 * then the chroma plane resolution must be rounded up.
 *
 * @par
 * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized
 * image data is stored in AVFrame.data[0]. The palette is transported in
 * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is
 * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is
 * also endian-specific). Note also that the individual RGB32 palette
 * components stored in AVFrame.data[1] should be in the range 0..255.
 * This is important as many custom PAL8 video codecs that were designed
 * to run on the IBM VGA graphics adapter use 6-bit palette components.
 *
 * @par
 * For all the 8 bits per pixel formats, an RGB32 palette is in data[1] like
 * for pal8. This palette is filled in automatically by the function
 * allocating the picture.
 */
enum AVPixelFormat {
    AV_PIX_FMT_NONE = -1,
    AV_PIX_FMT_YUV420P,   ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
    AV_PIX_FMT_YUYV422,   ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
    AV_PIX_FMT_RGB24,     ///< packed RGB 8:8:8, 24bpp, RGBRGB...
    AV_PIX_FMT_BGR24,     ///< packed RGB 8:8:8, 24bpp, BGRBGR...
    AV_PIX_FMT_YUV422P,   ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
    AV_PIX_FMT_YUV444P,   ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
    AV_PIX_FMT_YUV410P,   ///< planar YUV 4:1:0,  9bpp, (1 Cr & Cb sample per 4x4 Y samples)
    AV_PIX_FMT_YUV411P,   ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
    AV_PIX_FMT_GRAY8,     ///<        Y        ,  8bpp
    AV_PIX_FMT_MONOWHITE, ///<        Y        ,  1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb
    AV_PIX_FMT_MONOBLACK, ///<        Y        ,  1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb
    AV_PIX_FMT_PAL8,      ///< 8 bits with AV_PIX_FMT_RGB32 palette
    // ...

2.5 const AVClass *priv_class

结构体的定义位于libavutil\log.h

/**
 * Describe the class of an AVClass context structure. That is an
 * arbitrary struct of which the first field is a pointer to an
 * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.).
 */
// 描述AVClass上下文结构的类。这是一个任意结构体,
// 其第一个字段是指向AVClass结构体的指针(例如AVCodecContext, AVFormatContext等)
typedef struct AVClass {
    /**
     * The name of the class; usually it is the same name as the
     * context structure type to which the AVClass is associated.
     */
    // 类的名称;通常它与AVClass所关联的上下文结构类型相同
    const char* class_name;

    /**
     * A pointer to a function which returns the name of a context
     * instance ctx associated with the class.
     */
    // 指向一个函数的指针,该函数返回与类关联的上下文实例ctx的名称
    const char* (*item_name)(void* ctx);

    /**
     * a pointer to the first option specified in the class if any or NULL
     *
     * @see av_set_default_options()
     */
    // 指向类中指定的第一个选项的指针(如果有的话)或NULL
    const struct AVOption *option;

    /**
     * LIBAVUTIL_VERSION with which this structure was created.
     * This is used to allow fields to be added without requiring major
     * version bumps everywhere.
     */
	// LIBAVUTIL_VERSION,用来创建这个结构
	// 这是为了允许添加字段,而不需要到处出现重大版本颠簸。
    int version;

    /**
     * Offset in the structure where log_level_offset is stored.
     * 0 means there is no such variable
     */
    // 存储log_level_offset的结构中的偏移量
    // 0表示没有这样的变量
    int log_level_offset_offset;

    /**
     * Offset in the structure where a pointer to the parent context for
     * logging is stored. For example a decoder could pass its AVCodecContext
     * to eval as such a parent context, which an av_log() implementation
     * could then leverage to display the parent context.
     * The offset can be NULL.
     */
    // 结构中的偏移量,其中存储指向用于日志记录的父上下文的指针
    // 例如,解码器可以将其AVCodecContext作为父上下文传递给eval,然后av_log()实现可以利用它来显示父上下文
    // 偏移量可以为NULL
    int parent_log_context_offset;

    /**
     * Category used for visualization (like color)
     * This is only set if the category is equal for all objects using this class.
     * available since version (51 << 16 | 56 << 8 | 100)
     */
    // 用于可视化的类别(如颜色)
    // 只有当使用该类的所有对象的类别相等时,才会设置此属性。版本(51 << 16 | 56 << 8 | 100)
    AVClassCategory category;

    /**
     * Callback to return the category.
     * available since version (51 << 16 | 59 << 8 | 100)
     */
    // 回调返回类别。版本(51 << 16 | 59 << 8 | 100)
    AVClassCategory (*get_category)(void* ctx);

    /**
     * Callback to return the supported/allowed ranges.
     * available since version (52.12)
     */
    // 回调返回支持/允许的范围。从版本(52.12)开始可用
    int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags);

    /**
     * Return next AVOptions-enabled child or NULL
     */
    // 返回下一个启用avoptions的子节点或NULL
    void* (*child_next)(void *obj, void *prev);

    /**
     * Iterate over the AVClasses corresponding to potential AVOptions-enabled
     * children.
     *
     * @param iter pointer to opaque iteration state. The caller must initialize
     *             *iter to NULL before the first call.
     * @return AVClass for the next AVOptions-enabled child or NULL if there are
     *         no more such children.
     *
     * @note The difference between child_next and this is that child_next
     *       iterates over _already existing_ objects, while child_class_iterate
     *       iterates over _all possible_ children.
     */
    // 迭代AVClasses对应于潜在的avoptions启用子类
    // @param Iter指针指向不透明的迭代状态。调用者必须在第一次调用之前将*iter初始化为NULL
    // @return AVClass用于下一个AVOptions-enabled的子节点,如果没有这样的子节点,则为NULL
    // @note child_next和this的区别在于,child_next迭代的是已经存在的对象,而child_class_iterate迭代的是所有可能的子对象
    const struct AVClass* (*child_class_iterate)(void **iter);
} AVClass;

2.6 const AVProfile *profiles

profile表示了视频编码的复杂度与压缩效率的等级,例如Baseline、Main Profile、High Profile等,不同的profile会使用不同的编码工具

/**
 * AVProfile.
 */
typedef struct AVProfile {
	// profile level
    int profile;
    // profile name
    const char *name; ///< short name for the profile
} AVProfile;

CSDN : https://blog.csdn.net/weixin_42877471
Github : https://github.com/DoFulangChen


网站公告

今日签到

点亮在社区的每一天
去签到