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