FFmpeg: 常用结构体分析(更新中)

1,765 阅读19分钟

FFmpeg常用结构体分析

该分析结合源码翻译和《FFmpeg源码分析及实战》整理

1. AVFormatContext

/*** Format I/O context. * ... */

AVFormatContext可以说是贯穿全局的数据结构,很多函数都要用它作为参数。

此结构包含了一个视频流的格式内容。其中AVInputFormat(或者AVOutputFormat,但是同一时间AVFormatContext内只能存在其中一个),AVStream,AVPacket这几个重要的结构以及一些其他信息,比如title,author,copyright等,后还有一些可能在编解码中会用到的信息,比如 duration、file_size、 bit_rate等。

/** ... * sizeof(AVFormatContext) must not be used outside libav*, use * avformat_alloc_context() to create an AVFormatContext. ... */

AVFormatContext的一种初始化:

AVFormatContext * pFmCtx;
pFmCxt = avformat_alloc_context();//不赋初值的初始化,分配内存

函数体定义有:

typedef struct AVFormatContext {

	const AVClass *av_class;//与logging以及avoptions相关的class,由avformat_alloc_context()设置

	struct AVInputFormat *iformat;//输入容器格式,只用在解复用(demuxing only),由avformat_open_input()设置
	
	struct AVOutputFormat *oformat;//输出容器格式,只用在复用(muxing only),必须在调用 avformat_write_header()之前设置

	void *priv_data;//格式私有数据, 在复用的时候由avformat_write_header()设置; demuxing:由avformat_open_input() 设置

	 AVIOContext *pb;// I/O context. 在解复用时候,在avformat_open_input()调用之前设置,或者由avformat_open_input()设置;在复用时候,在avformat_write_header()之前由使用者设置
	
	/* 流信息 */
	int ctx_flags;
	
	unsigned int nb_streams;// 流的数目

	AVStream **streams;//文件所有流的list,如果要创建新的流,可以通过avformat_new_stream()创建
	
	char filename[1024];//输入或者输出的文件名,解复用时候由avformat_open_input()设置,复用时候可以在avformat_write_header()之前设置

	int64_t start_time;//开始帧的位置,不要直接设置。只在解复用时候用到(Demuxing only)
	
	int64_t duration;//流的时长

	int64_t bit_rate;//整个流的比特率 bit/s

	unsigned int packeet_size;
	int max_delay;
	int flags;//Demuxer/Muxer的状态
	//此处省略宏定义,在该段代码结束为止贴出

	int64_t probesize;//通过AVInputFormat从输入流中读到数据的最大size,在avformat_open_input()之前设置,只在解复用使用(Demuxing only)

	int64_t max_analyze_duration;//从来自avformat_find_stream_info()输入流中读到数据的最大size,在avformat_find_stream_info()前设置

	const uint8_t *key;
	int keylen;

	unsigned int nb_programs;
	AVProgram **programs;

	enum AVCodecID video_codec_id;//视频编解码器id,在解码的时候由user设置

	enum AVCodecID audio_codec_id;//音频编解码器id,在解码的时候由user设置

	enum AVCodecID subtitle_codec_id;//字母编解码器id,在解码的时候由user设置

	unsigned int max_index_size;//每条流的最大内存字节数

	unsigned int max_picture_buffer;//Buffering frames的最大内存字节数

	unsigned int nb_chapters;// AVChapters array的chapters的数量
	AVChapter **chapters;

	AVDictionary *metadata;//元数据

	int64_t start_time_realtime;//起始时间,从PTS=0开始

	int fps_probe_size;//用在avformat_find_stream_info()中,用于确定帧率,其值为帧数。只在解复用中。

	int error_recognition;//错误检测

	AVIOInterruptCB interrupt_callback;//自定义

	int debug;//flags to enable debugging
#define FF_FDEBUG_TS        0x0001

	int64_t max_interleave_delta;//最大交叉Buffering(缓冲数据)时长,在muxing(复用)时使用
	
	int strict_std_compliance;//允许非标准拓展

	int event_flags;// Flags for the user to detect events happening on the file.
	
	int max_ts_probe;//解码第一帧(第一个时间戳)时读取的最大Packet数目

	int avoid_negative_ts;//在复用(muxing)过程中避免无效的时间戳(timestamps)
#define AVFMT_AVOID_NEG_TS_AUTO             -1 ///< Enabled when required by target format
#define AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE 1 ///< Shift timestamps so they are non negative
#define AVFMT_AVOID_NEG_TS_MAKE_ZERO         2 ///< Shift timestamps so that they start at 0
	
	int ts_id;//ts(Transport)流的id

	int audio_preload;// 音频提前加载,不是所有格式都支持

	int max_chunk_duration;//最大chunk时长,不是所有格式都支持

	int max_chunk_size;//最大chunk以字节为单位。不是所有格式都支持
	
	int use_wallclock_as_timestamps;//强制使用wallclock时间戳作为数据包的pts/dts,如果有b帧存在会有未定义的结果出现
	
	int avio_flags;

	enum AVDurationEstimationMethod duration_estimation_method;//可以通过不同的方式估计持续时间字段
	
	int64_t skip_initial_bytes;//当打开流的时候,跳过初始字节

	unsigned int correct_ts_overflow;//纠正单个时间戳溢出

	int seek2any;//强制seek到任一帧
	
	int flush_packets;//在每个packet之后,刷新I/O Context

	int probe_score;//格式探测评分,最大评分是AVPROBE_SCORE_MAX
	
	int format_probesize;//读取最大的字节数来确定格式

	char *codec_whitelist;//由','分隔的所有可用的decoder(解码器)

	char *format_whitelist;//由‘,’分隔的所有可用的demuxers(解复用器)

	AVFormatInternal *internal;//libavformat内部私有成员

	int io_repositioned;//I/O 更改的标志

	AVCodec *video_codec;// Forced video codec,特殊解码器或者相同codec_id的视频Codec
	AVCodec *audio_codec;// Forced audio codec, 特殊解码器或者相同codec_id的音频Codec
	AVCodec *subtitle_codec;//Forced subtitle codec, 特殊解码器或者相同codec_id的字幕Codec
	AVCodec *data_codec;//Forced data codce,特殊解码器或者相同codec_id的数据Codec

	int metadata_header_padding;//在metadata(元数据)头设置padding值

	void *opaque;//用户私有数据
	
	av_format_control_message control_message_cb;//设备和应用通信用的Callback

	int64_t output_ts_offset;//输出时间戳偏移量
	
	uint8_t *dump_separator;//转储分隔格式 可以是“,”或者“\n”或者其他

	enum AVCodecId data_codec_id;//Forced Data codec_id
	
	int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options);//过时函数,用io_open_and_io_close代替

	char *protocol_whitelist;//协议白名单,用','分隔

	int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
                   int flags, AVDictionary **options);//当I/O流打开时候,解复用操作的回调函数

	void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);//AVFormatContext打开时候的回调函数

	char *protocol_blacklist;//协议黑名单

	int max_streams;//流的最大数量,在decodeing的时候设置

}AVFormatContext;

上述代码中

int flags;//Demuxer/Muxer的状态
//省略部分宏定义

省略的宏定义如下:

int flags;//Demuxer/Muxer的状态
#define AVFMT_FLAG_GENPTS       0x0001 ///< Generate missing pts even if it requires parsing future frames.
#define AVFMT_FLAG_IGNIDX       0x0002 ///< Ignore index.
#define AVFMT_FLAG_NONBLOCK     0x0004 ///< Do not block when reading packets from input.
#define AVFMT_FLAG_IGNDTS       0x0008 ///< Ignore DTS on frames that contain both DTS & PTS
#define AVFMT_FLAG_NOFILLIN     0x0010 ///< Do not infer any values from other values, just return what is stored in the container
#define AVFMT_FLAG_NOPARSE      0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled
#define AVFMT_FLAG_NOBUFFER     0x0040 ///< Do not buffer frames when possible
#define AVFMT_FLAG_CUSTOM_IO    0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it.
#define AVFMT_FLAG_DISCARD_CORRUPT  0x0100 ///< Discard frames marked corrupted
#define AVFMT_FLAG_FLUSH_PACKETS    0x0200 ///< Flush the AVIOContext every packet.
/**
 * When muxing, try to avoid writing any random/volatile data to the output.
 * This includes any random IDs, real-time timestamps/dates, muxer version, etc.
 *
 * This flag is mainly intended for testing.
 */
#define AVFMT_FLAG_BITEXACT         0x0400
#define AVFMT_FLAG_MP4A_LATM    0x8000 ///< Enable RTP MP4A-LATM payload
#define AVFMT_FLAG_SORT_DTS    0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down)
#define AVFMT_FLAG_PRIV_OPT    0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted)
#if FF_API_LAVF_KEEPSIDE_FLAG
#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. Deprecated, will be the default.
#endif
#define AVFMT_FLAG_FAST_SEEK   0x80000 ///< Enable fast, but inaccurate seeks for some formats
#define AVFMT_FLAG_SHORTEST   0x100000 ///< Stop muxing when the shortest stream stops.
#define AVFMT_FLAG_AUTO_BSF   0x200000 ///< Wait for packet data before writing a header, and add bitstream filters as requested by the muxer

2. AVInputFormat

AVInputFormat是FFmpeg的解复用器对象。

一种文件格式对应一个AVInputFormat结构,在程序运行时候有多个实例。

next变量用于把支持的所有输入文件容器格式连接成链表,便于遍历查找。

priv_data_size标识具体的文件容器格式对应的Context大小。

对应的结构体定义如下:

typedef struct AVInputFormat{

	const char *name;//类似列表形式的格式的短名称

	const char *long_name;//类似于列表形式的格式的长名称(人可读)

	int flags;

	const char *extensions;//如果拓展被定义了,那么不会进行格式探测,通常不适用拓展

	const struct AVCodecTag * const *codec_tag;//Codec的tag

	const AVClass *priv_class;//AVClass for private context
	
	const char *mime_type;//mime类型,比如video/avc,在probing(探测)时候需要检查

	//以下变量都不是public API,不能再libavformat之外使用,将来可能会被修改或者移除
	struct AVInputFormat *next;

	int raw_codec_id;//原始Demuxer存储的codec id
	
	int priv_data_size;//魔种格式文件的数据大小

	int (*read_pribe)(AVProbeData *);//读取probe数据,提供的probe数据必须保证AVPROBE_PADDING_SIZE足够大,使得你不需要为此做检查

	int (*read_header)(struct AVFormatContext *);//读取格式头部,并且初始化AVFormatContext结构,如果成功return 0。 'avformat_new_stream'应该被调用来创建新的流
	
	

]AVInputFormat;

3. AVStream

AVStream 是存储视频/音频流信息的结构体。

解复用器的目的就是从容器在分离(解析出来)不同的流。而FFmpeg中流对象是AVStream,它由解复用器的read_header()函数创建,保存着AVFormatContext的nb_streams(容器中流条数)和stream[]数组中

结构体定义:

typedef struct AVStream {
    int index;  //在 AVFormatContext中 streams[] 中AVStream对应的index
    int id; //Stream ID
    
    void *priv_data; //私有数据

    AVRational time_base;   //时间基数 分数形式

    int64_t start_time;//解复用时候的安图像排序的第一帧的pts
                    //注意ASF header没有包含一个正确的start_time, ASF Demuxer不要设置这个属性

    int64_t duration;// 解码时候:流的长度(以流的time_base为单位)
                    //编码时候:可以在avformat_write_header()之前由调用者设置来提供一个默认值

    int64_t nb_frames; // 流的帧数,如果不知道则为0

    int disposition; /**< AV_DISPOSITION_* bit field */

    enum AVDiscard discard; // 选择哪个Packet是废物的,不需要解复用(Demuxer)

    AVRational sample_aspect_ratio; //采样率

    AVDictionary *metadata; //元数据

    AVRational avg_frame_rate;  //平均帧率,在解复用时候在avformat_find_stream_info()中或者创建流时候设置

    AVPacket attached_pic; //对于有AV_DISPOSITION_ATTACHED_PIC的配置,packet将包含附加图像

    AVPacketSideData *side_data;//一整个流的附加信息的集合,由avformat_free_context()释放
    
    int nb_side_data; // AVStream.side_data(附加信息)集合中元素个数

    int event_flags;//检测流时的标识 <Flags for the user to detect events happening on the stream
    
    #define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata.

    /*****************************************************************
     * 以下部分不是公开API,他们将来可能会被修改或者删除
     * All fields below this line are not part of the public API. They
     * may not be used outside of libavformat and can be changed and
     * removed at will.
     * Internal note: be aware that physically removing these fields
     * will break ABI. Replace removed fields with dummy fields, and
     * add new fields to AVStreamInternal.
     *****************************************************************
     */

    
#define MAX_STD_TIMEBASES (30*12+30+3+6) // avformat_find_stream_info()需要用到的流信息
    struct {
        int64_t last_dts;
        int64_t duration_gcd;
        int duration_count;
        int64_t rfps_duration_sum;
        double (*duration_error)[2][MAX_STD_TIMEBASES];
        int64_t codec_info_duration;
        int64_t codec_info_duration_fields;

        int found_decoder; // 0 -> 没找到解码器
                        // >0 -> 找到解码器
                        // <0 -> 没找到解码器(通过codec_id,没找到found_decoder)

        int64_t last_duration;

        /**
         * 以下用于估计平均帧率
         */
        int64_t fps_first_dts;
        int     fps_first_dts_idx;
        int64_t fps_last_dts;
        int     fps_last_dts_idx;

    } *info;

    int pts_wrap_bits; /**用于装饰控制时表示PTS数目 */

    // 时间戳支持:
    /**
     * Timestamp corresponding to the last dts sync point.
      * 与最后一个dts同步点对应的时间戳
     */
    int64_t first_dts; //第一个DTS
    int64_t cur_dts; //当前DTS
    int64_t last_IP_pts;
    int last_IP_duration;

    int probe_packets;//Codec探测出用于Buffer的packet数

    int codec_info_nb_frames;//解复用(demux)后的帧数

    /* av_read_frame() support */
    enum AVStreamParseType need_parsing;
    struct AVCodecParserContext *parser;

    struct AVPacketList *last_in_packet_buffer;//packet_buffer中的上一个Packet
    AVProbeData probe_data;
#define MAX_REORDER_DELAY 16
    int64_t pts_buffer[MAX_REORDER_DELAY+1];

    AVIndexEntry *index_entries; /**< 只在当前各式不支持原生跳转(seek natively)使用 */
    int nb_index_entries;
    unsigned int index_entries_allocated_size;

    AVRational r_frame_rate;//流的真实帧率 (这是可以让流中所有时间戳得以表现的最低帧率,注意这个值是猜测得到的)
                            //比如 time_base = 1/90000 所有frames都有 3600或者1800 计时器单位,那么r_frame_rate=
                            50/1 (90000/3600 = 25, 90000/1800 = 50 -> upside down so lowest to max -> r_frame_rate = 50)

    int stream_identifier;// stream识别,0表示未知

    int64_t interleaver_chunk_size;
    int64_t interleaver_chunk_duration;

  
    int request_probe;//stream检测状态, -1 探测完成, 0 没有探测请求
   
    int skip_to_keyframe;//跳过下一个关键帧

    int skip_samples;//从下一个packet解码出来的帧的前skip_samples数的要跳过的样本

    int64_t start_skip_samples;//流开始部分要跳过的样本数(如果不是0)

    
    int64_t first_discard_sample;//第一个废弃的采样

    int64_t last_discard_sample;//上次废弃的采样,避免EOF

    int nb_decoded_frames;//编码后的帧数

    int64_t mux_ts_offset;//在muxing(复用)时,给时间戳添加偏移量

    int64_t pts_wrap_reference;//检查时间戳的包装

   
    int pts_wrap_behavior;//pts的拓展行为

    int update_initial_durations_done;//避免更新初始化时间两次

    //从PTS生成DTS
    int64_t pts_reorder_error[MAX_REORDER_DELAY+1];
    uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1];

    /**
     * Internal data to analyze DTS and detect faulty mpeg streams
     */
    int64_t last_dts_for_order_check;
    uint8_t dts_ordered;
    uint8_t dts_misordered;

    /**
     * Internal data to inject global side data
     内部数据注入全局side_data
     */
    int inject_global_side_data;

    /*****************************************************************
     * All fields above this line are not part of the public API.
     * Fields below are part of the public API and ABI again.
     * 以下部分属于公开API和ABI (可用,不修改)
     *****************************************************************
     */

    
    char *recommended_encoder_configuration;//推荐使用键值对形式的编码器配置项

    AVRational display_aspect_ratio;//显示率, 0 如果不知道

    struct FFFrac *priv_pts;

    AVStreamInternal *internal;//liavformat内部使用的成员

    AVCodecParameters *codecpar;//Codec参数,通过avformat_new_stream分配,通过avformat_free_context释放
} AVStream;

4. AVCodecContext

这是编码器上下文的数据结构,包含了解码器需要的参数信息。

如果是单纯使用libavcodec,这部分信息需要调用者进行初始化,如果是整个FFmpeg库,这部分信息在调用av_open_input_file()和 av_find_stream_info()的过程中会根据文件头部信息以及媒体流内的头部信息完成初始化。

结构体定义:

typedef struct AVCodecContext{
    const AVClass *av_class;//av_log使用的结构体,通过avcodec_alloc_context3设置
    int log_level_offset;//日志中的级别
    enum AVMediaType codec_type;//参见AVMEDIA_TYPE_xxx
    const struct AVCodec *codec;
    
    enum AVCodecId codec_id;//参见AV_CODEC_ID_xxx
    
    unsigned int codec_tag;//Codec的标记,用来解决一些编码bug
    
    void *priv_data;//私有数据
    
    struct AVCodecInternal *internal;//与priv_data不同,它与某个解码器没有特别关联,用在一般的libavcodec功能
    
    void *opaque;//user私有数据,在编解码时候由用户设置
    
    int64_t bit_rate;//平均比特率
    
    int bit_rate_tolerance;//比特流中允许偏离参考的比特数
    
    int global_quality;//全局Codec质量
    
    int compression_level;
    
    int flags;//参见 AV_CODEC_FLAG_*
    
    int flags2;//参见 AV_CODEC_FLAG2_*
    
    uint8_t *extradata;//一些编码器可用的额外数据,比如哈夫曼码表
                        //如果是通过bitstream reader读取来的,分配的内存是比extradata_size字节数更大的AV_INPUT_BUFFER_PADDING_SIZE来避免一些问题
   int extradata_size;
   
   AVRational time_base;//时间戳
   
   int ticks_per_frame;//默认设置为1,比如 H.264/MPEG-2 设置为2
   
   int delay;//对于视频,解码输出相对于编码输入将会延迟的帧数
                //对于音频,代表在解码器输出有效之前,解码器需要输出的样本数。当seek时候,你需要在你所seek的点之前许多样本数的地方开始解码。
  
   int width,height;//只对视频,图片的宽高。
   
   int coded_width,coded_height;//比特流的宽高
   
   int gop_size;//a group of pictrues中图片的数量
   
   enum AVPixelFormat pix_fmt;//像素格式,参见AV_PIX_FMT_xxx
   
   /**  如果不是NULL,则被调用来绘制一个水平带 */
    void (*draw_horiz_band)(struct AVCodecContext *s,
                            const AVFrame *src, int offset[AV_NUM_DATA_POINTERS],
                            int y, int type, int height);
   
    /** 回调协商pixelFormat */
    enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
    
    int max_b_frames;//在非B帧之间的最大B帧数,注意,输出将会相对于输入有max_b_frames+1的延迟
    
    float b_quant_factor;//IP和b帧之间的qscale因子
                        // >0 上一个P帧的quantizer(数字转换器)将会被使用(q = lastp_q * factor + offset)
                        // <0 进行正常的速率控制(q=-normal_q * factor + offset)
    
    float b_quant_offset;//IP和b帧间的qscale偏移
    
    int has_b_frames;//解码器中帧重排序缓冲区的大小
                        //对于MPEG-2为 1 IPB或者 0 低延迟IP
    
    float i_quant_factor;//p帧和(I帧)关键帧之间的qscale因子
                        // >0 上一个p帧的quantizer将被使用(q = lastp_q * factor + offset)
                        // <0 进行正常的速率控制( q = -normal_q * factor + offset)

    
    float i_quant_offset;//p帧和关键帧(I帧)之间的qscale偏移
    
    float lumi_masking;//照度掩蔽 (0->disabled)
    
    float temporal_cplx_masking;//临时复杂性掩蔽(0->disabled)
    
    float spatial_cplx_masking;//空间复杂性掩蔽(0->disabled)
    
    float p_masking;// p块掩蔽(0->disabled)
    
    float dark_masking;// 黑暗掩蔽(0->disabled)
    
    int slice_count;//slice(图像细分)总和
    
    int *slice_offset;//帧中的图像细分偏移量(以字节为单位)
    
    AVRational sample_aspect_ratio;//样本宽高比,像素宽度除以像素高度
    
    int me_cmp;//运动估计比较功能
    
    int me_sub_cmp;//亚像素运动估计比较功能
    
    int mb_cmp;//暂不支持
    
    int ildct_cmp;//交错DCT比较功能
    //省略宏定义
    
    int dia_size;// ME diamond 的大小和形状
    
    int last_predictor_count;//前期MV预测量(2a+1的平方)
    
    int me_pre_cmp;//运动估计比较功能
    
    int pre_dia_size;//ME 准备的diamond的大小和形状
    
    int me_subpel_quality;
    
    int slice_flags;//slice标识
    
    int mb_decision;//macroblock decision宏块类型选择
    //省略宏定义

    uint16_t *intra_matix;//自定义内部量化矩阵
    
    uint16_t *inter_matrix;//自定义内部量化矩阵
    
    int intra_dc_precision;//内部系数的精度- 8
    
    int skip_top;//顶部被跳过的宏块行数
    
    int skip_bottom;//底部被跳过的宏块行数
    
    int mb_lmin;
    int mb_lmax;
    
    int bidir_refine;
    
    int keyint_min;// GOP最小size
    
    int refs;//number of reference frames参考系数,参考帧的数目
    
    int mv0_threshold;
    
    enum AVColorPrimaries color_primaries;//色度坐标
    
    enum AVColorTransferCharacteristic color_trc;//颜色传输特性
    
    enum AVColorSpace colorspace;//YUV颜色空间类型
    
    enum AVColorRange color_range;//用于存储颜色范围MPEG vs JPEG YUV range
    
    enum AVChromaLocation chroma_sample_location;//色度样本的位置
    
    int slices;//图像细分数量,用于并行解码
    
    enum AVFieldOrder field_order;
    
    /** 以下用于音频相关操作 */
    
    int sample_rate; ///< samples per second
    int channels;    ///< number of audio channels
    
    enum AVSampleFormat sample_fmt;  ///< sample format
    
    int frame_size;//音频每个信道的采样数
    
    int frame_number;//帧计数器
    
    int block_align;//用在一些基于MAV的音频解码器,表示常量或者已知的每个包中的字节数
    
    int cutoff;//音频截止带宽 0表示自动
    
    uint64_t channel_layout;//信道布局
    
    uint64_t request_channel_layout;//如果可以,请求解码器使用此通道布局(默认为0)
    
    enum AVAudioServiceType audio_service_type;//音频流传递的服务类型
    
    enum AVSampleFormat request_sample_fmt;//所需的样本格式
    
    int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags);//获取Buffer的回调函数
    
    int refcounted_frames;//通过avcodec_decode_video2和avcodec_decod_audio4返回的解码后的帧数
    
    /** 编码参数 */
    float qcompress;  ///< amount of qscale change between easy & hard scenes (0.0-1.0)
    float qblur;      ///< amount of qscale smoothing over time (0.0-1.0)
    
    int qmin;//最小量化器
    int qmax;//最大量化器
    int max_qdiff;//帧之间的最大量化器差异
    
    int rc_buffer_size;//解码器比特流缓冲区大小
    
    int rc_override_count;
    RcOverride *rc_override;
    
    int64_t rc_max_rate;//最大比特率
    int64_t rc_min_rate;//最小比特率
    
    float rc_max_available_vbv_use;//Ratecontrol尝试在最大情况下使用,即可以在没有下溢的情况下使用的内容
    
    float rc_min_vbv_overflow_use;//Ratecontrol尝试在最大情况下使用,即可以在没有上溢的情况下使用的内容
    int rc_initial_buffer_occupancy;//译码开始前应装入rc缓冲区的位的数目。
    
    char *stats_out;//pass1编码统计输出缓冲区,编码时由libavcodec设置
    
    char *stats_in;//pass2编码统计输入缓冲区,应该将来自pass1的stats_out的连接内容放在这里,由user来分配内存、设置、释放
    
    int workaround_bugs;//解决编码器中有时无法自动检测到的bug
    //省略宏定义
    
    int strict_std_compliance;//严格遵循标准,比如MPEG-4等
    //省略宏定义
    
    int error_concealment;//错误隐藏的标识
    //省略宏定义

    int debug;
    //省略宏定义
    int debug_mv;
    
    int err_recognition;//错误认识;可能会将一些有效的部分错误地检测为错误
    
    int64_t reordered_opaque;//将在avframe . reordered_中重新排序和输出的不透明64位数字(通常为PTS)
    
    struct AVHWAccel *hwaccel;//硬件加速结构体
    
    void *hwaccel_context;//硬件加速Context上下文环境
    
    int thread_count;//线程个数,取决于有多少个独立任务在执行
    
    int thread_type;//使用哪些多线程方法
    
    int active_thread_type;//哪些多线程方法正在被使用
    
    int thread_safe_callbacks;//如果使用默认的get_buffer(),则忽略它。
    
    //编解码器可以调用它来执行几个独立的东西,它只会在完成所有任务后返回
    int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size);

    //编解码器可以调用它来执行几个独立的东西,它只会在完成所有任务后返回
    int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count);

    int nsse_weight;
    
    int profile;
    //省略宏定义
    
    int level;
    //省略宏定义
    
    enum AVDiscard skip_frame;//跳过选定帧的解码操作
    
    uint8_t *subtitle_header;//字幕头
    int subtitle_header_size;//字幕头的大小
    
    AVRational framerate;//压缩码流中存储的帧率
    
    AVRational pkt_timebase;//pkt_dts和pkt_pts的时间基数
    
    int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far
    int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
    int64_t pts_correction_last_pts;       /// PTS of the last frame
    int64_t pts_correction_last_dts;       /// DTS of the last frame
    
    
    char *codec_whitelist;//可用编解码器的白名单
    
    //省略了部分属性
   
}AVCodecContext;

5. AVPacket

FFmpeg用 AVPacket来存放编码后的视频帧数据,AVPacket保存了解复用之后、解码之前的数据(仍然是压缩有的数据)和关于这些数据的一些附加信息,比如显示时间戳(PTS)、解码时间戳(DTS)、数据时长、所在媒体流的索引等。

对于视频(Video)来说,AVPacket通常包含一个压缩的帧,而音频(Audio)则有可能包含多个压缩的帧。并且,一个Packet有可能是空的,不包含任何压缩数据,只含有附加数据 side data(side data 指的是容器提供的关于Packet 的一些附加信息,例如,在编码结束的时候更新一些流的参数)

AVPacket是公共的ABI的一部分,它可以被分配到栈空间上。

typedef struct AVPacket{
    AVBufferRef *buf;//AVBufferRef类型的指针,用来管理data指针引用的数据缓存
    int64_t pts;//显示时间戳
    int64_t dts;//解码时间戳
    uint8_t *data;//指向保存压缩数据的指针,这就是AVPacket实际的数据
    int size;
    int stream_index;//流索引
    int flags;//带有AV_PKT_FLAG属性的组合
    AVPacketSideData *side_data;//填充容器的一些附加数据
    int side_data_elems;
    int64_t duration;//Pacekt的时长
    int64_t pos;//Packet中的位置
}AVPacket;

AVPacket实际上可用作一个容器,它本身不包含压缩的媒体数据,而是通过data指针引用数据的缓存空间,所以当将一个Packet作为参数传递的时候,就要根据具体的需要,对data引用的这部分数据缓存空间进行特殊的处理。当从一个Packet创建另一个Packet的时候,有如下两种情况:

  • 两个Packet的data引用的是同一数据缓存空间,这时候要注意数据缓存空间的释放问题
  • 两个Packet的data引用的是不同的数据缓存空间,每个Packet都有数据缓存空间的副本

第二种情况下,数据空间管理比较简单,但是数据实际上有多个副本,这就造成了空间的浪费,所以要根据具体的需要,来选择到底是两个Packet共享一个数据缓存空间,还是每个Packet拥有自己独立的缓存空间。

对于多个Packet共享同一个缓存空间,FFmpeg使用了引用计数机制。当有新的Packet饮用共享的缓存空间时,引用计数+1,当释放了引用共享空间的Packet时,引用计数-1;当引用计数为0时候,释放引用的缓存空间。。

AVPacket中的AVBufferRef *部分就是用来管理这个引用计数的:

typedef struct AVBufferRef {
    AVBuffer *buffer;
    uint8_t *data;
    int size;
}AVBufferRef;

在AVPacket中使用AVBufferRef,可以通过两个函数av_packet_ref()和av_packet_unref()

  • av_packet_ref,函数声明如下
int av_packet_ref(AVPacket *dst, const AVPacket *src)

创建一个src->data的新的引用计数。

如果src已经设置了引用计数(src->buf不为空),直接将src的buf引用计数+1;

如果src没有设置引用计数(src->buf为空),为DST创建一个新的引用计数buf,并复制src->data到buf->buffer中。最后复制src其他字段到DST中。

  • av_packet_unref,函数声明如下
int av_packet_unref(AVPacket *pkt)

将缓存空间的引用计数-1,并将Packet中的其它字段设为初始值。如果引用计数为0,则自动释放缓存空间。所以,当两个Packet共享同一个数据缓存空间的时候,可以这么做。

AVPacket通常将Demuxer导出的数据包作为解码器的输入数据,或是受到来自编码器的数据包,通过Muxer进入输出数据。

FFmpeg复用与解复用的过程:

input file --demuxer--> encoded data packets --decoder--> decoded frames --encoder--> encoded data packets --muxer--> output file