【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