AVFormatContext
AVFormatContext 是很重要的一个类,AVFormatContext是用于打开/写入文件或者网络视频流等视频码流文件时使用的结构体,结构体内部有非常多的参数,所以会挑几个常见的或者主要的讲。
从AVFormatContext结构体开始
在我们编写自己的编解码应用代码,使用ffmpeg打开一个文件或者网络流的时候,首先使用到的结构体就是AVFormatContext,其源代码在libavformat/avformat.h文件中。
在代码中一开始的注释介绍里就指出AVFormatContext是一个“Format I/O context",源代码结构体声明前的注释说明:
/**
* Format I/O context.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* sizeof(AVFormatContext) must not be used outside libav*, use
* avformat_alloc_context() to create an AVFormatContext.
*
* Fields can be accessed through AVOptions (av_opt*),
* the name string used matches the associated command line parameter name and
* can be found in libavformat/options_table.h.
* The AVOption/command line parameter names differ in some cases from the C
* structure field names for historic reasons or brevity.
*/
看一下,注释中告诉我们了,
1.首先,版本更新情况,不重要。
2.然后,sizeof(AVFormatContext)不可以用于libav*包含的的文件以外的地方,这一点在自己手动开发或者修改代码时要注意。
3.然后,请使用avformat_alloc_context()创建这个结构体对象。这个函数也是这篇文章需要讲解一下的,
4.我们可以用AVOption去访问结构体中一些字段。这个非常重要,也是开发代码时要用到的。
5.由于一些历史问题,所以字段名称可能会与C结构体中存在一些不同。这个fine,问题不大。
AVFormatContext 关键成员
const AVClass *av_class;
AVClass放第一个不是说它有多么重要(虽然确实挺重要的,非常重要),其实是FFmpeg规定了,在结构体中如果包含AVClass,出现的AVClass必须要放变量的第一个。其主要的功能是为了给AVFormatContext提供AVOption的支持,用AVClass来连接AVOption,AVClass中拥有一个.option数组,也就是说AVClass相当于一个桥梁的作用。在使用AVOption传参的时候,就可以使用该AVClass连接的AVOption来传各项设置参数到AVFormatContext或者其他使用了AVClass的结构体中。所以传参时,增加删除改动AVOption中的参数就可以实现了
//解复用的时候使用,only for 解复用,可以通过 avformat_open_input方法设置
/**
* The input container format.
* Demuxing only, set by avformat_open_input().
我们参考 avformat_open_input 函数可以知道,如果第三个参数不为nullptr,
第三个参数 代表的含义是 使用指定的AVInputFormat 来解析文件
int avformat_open_input(AVFormatContext **ps, const char *url,
const AVInputFormat *fmt, AVDictionary **options);
*/
ff_const59 struct AVInputFormat *iformat;
//复用相关,only for 复用,需要在 avformat_write_header方法之前设置
/**
* The output container format.
* Muxing only, must be set by the caller before avformat_write_header().
*/
ff_const59 struct AVOutputFormat *oformat;
/**
* Format private data. This is an AVOptions-enabled struct
* if and only if iformat/oformat.priv_class is not NULL.
*
* - muxing: set by avformat_write_header()
* - demuxing: set by avformat_open_input()
*/
void *priv_data;
void *priv_data;//格式私有数据,一个AVOptions的结构。 复用时通过 avformat_write_header方法设置,解复用时通过 avformat_open_input方法设置,
我们可以看到 avformat_open_input 方法的第四个参数就是 AVDictionary。
int avformat_open_input(AVFormatContext **ps, const char *url,
const AVInputFormat *fmt, AVDictionary **options);
我们可以可以看到 avformat_write_header方法的第二个参数也是 AVDictionary。
int avformat_write_header(AVFormatContext *s, AVDictionary **options);
这也就说明:这个priv_data的读写是通过上述的两个方法,通过 AVDictionary来实现。
/**
* I/O context.
* - demuxing: either set by the user before avformat_open_input() (then
* the user must close it manually) or set by avformat_open_input().
* - muxing: set by the user before avformat_write_header(). The caller must
* take care of closing / freeing the IO context.**/
AVIOContext *pb;
AVIOContext *pb;//格式的I/O上下文
pb则是用于数据缓存的结构体,在解复用的时候,用户手动设置的话需要在avformat_open_input()调用之前设置好,复用的时候则是需要在avformat_write_header()前进行手动设置。
在pb中有四个主要的成员变量,指向缓存地址的buffer,标明buffer长度的buffer_size,指向当前已经读取/已经写入地址位置的buf_ptr,以及指向buffer数据结尾的buf_end。其具体定义在avio.h中
/**
* Number of elements in AVFormatContext.streams.
*
* Set by avformat_new_stream(), must not be modified by any other code.
*/
unsigned int nb_streams;
/**
* A list of all streams in the file. New streams are created with
* avformat_new_stream().
*
* - demuxing: streams are created by libavformat in avformat_open_input().
* If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also
* appear in av_read_frame().
* - muxing: streams are created by the user before avformat_write_header().
*
* Freed by libavformat in avformat_free_context().
*/
AVStream **streams;
stream则是一个stream*的数组,存储着文件中存放的所有音、视频流的码流数据,音频流和视频流都以AVStream的方式存储在其中,而nb_streams则是说明该数组到底有多大,即文件中存储了几路音视频流。(所以才会有打开文件后在所有流中找视频或音频流的操作和对应函数)
/**
* input or output filename
*
* - demuxing: set by avformat_open_input()
* - muxing: may be set by the caller before avformat_write_header()
*/
char filename[1024];
/**
* input or output URL. Unlike the old filename field, this field has no
* length restriction.
/**
* input or output URL. Unlike the old filename field, this field has no
* length restriction.
*
* - demuxing: set by avformat_open_input(), initialized to an empty
* string if url parameter was NULL in avformat_open_input().
* - muxing: may be set by the caller before calling avformat_write_header()
* (or avformat_init_output() if that is called first) to a string
* which is freeable by av_free(). Set to an empty string if it
* was NULL in avformat_init_output().
*
* Freed by libavformat in avformat_free_context().
*/
*/
char *url;
char filename[1024];//输入或输出文件名
char *url是用来替换 filename的,不同之处在于,url没有长度限制,之前filename只能是1024个字节,
这个url 在解码时候通过avformat_open_input方法设置,如果avformat_open_input方法中 第二个参数设置为null,会将当前url设置为empty string--也就是"",这个通过查看源码也可以看到。
这个url 在编码时候设置,需要在 avformat_write_header 方法调用之前设置,通过av_free方法释放,如果通过avformat_init_output设置,当前url设置为empty string--也就是""
/**
* Duration of the stream, in AV_TIME_BASE fractional seconds. Only set this value if you know none of the individual stream durations and also do not set any of them. This is deduced from the
* AVStream values if not set.
* Demuxing only, set by libavformat.
*/
int64_t duration;
stream的时长,在解码时才会用到的数据,时长的单位量很小,1000000 duration才是一秒钟。
/**
* Total stream bitrate in bit/s, 0 if not available. Never set it directly if the file_size and the duration are known as FFmpeg can compute it automatically.
/**
* Duration of the stream, in AV_TIME_BASE fractional
* seconds. Only set this value if you know none of the individual stream
* durations and also do not set any of them. This is deduced from the
* AVStream values if not set.
*
* Demuxing only, set by libavformat.
*/
*流的持续时间,单位为AV_TIME_BASE分秒。
仅当您不知道单独的流持续时间,也不设置任何流持续时间时,才设置此值。
这是从AVStream值中推导出来的,如果没有设置的话。
*/
int64_t bit_rate;
比特率,可以被ffmpeg自己根据file_size以及duration计算出来的。
unsigned int packet_size;//数据包大小
int max_delay;//最大延迟
int flags;//标志位,指示各种格式相关的属性,如是否生成pts、是否忽略索引等。
#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_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_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)
#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Dont merge side data but keep it separate
unsigned int probesize;//数据探测大小
int max_analyze_duration;//最大分析时长
const uint8_t *key;//密钥
int keylen;//密钥长度
unsigned int nb_programs;//文件中程序的数量
AVProgram **programs;//指向AVProgram指针数组的指针,表示文件中的所有程序。
enum CodecID video_codec_id;//视频编码器ID
enum CodecID audio_codec_id;//音频编码器ID
enum CodecID subtitle_codec_id;//字幕编解码器ID
/**
* Forced video codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID video_codec_id;
/**
* Forced audio codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID audio_codec_id;
/**
* Forced subtitle codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID subtitle_codec_id;
/**
* Maximum amount of memory in bytes to use for the index of each stream.
* If the index exceeds this size, entries will be discarded as
* needed to maintain a smaller size. This can lead to slower or less
* accurate seeking (depends on demuxer).
* Demuxers for which a full in-memory index is mandatory will ignore
* this.
* - muxing: unused
* - demuxing: set by user
*用于每个流的索引的最大内存量(以字节为单位)。
*如果索引超过此大小,将根据需要丢弃条目以保持较小的大小。
这可能导致搜索速度较慢或精度较低(取决于解复用器)。
*强制使用完整内存索引的多路复用器将忽略这一点。
*/
unsigned int max_index_size;//最大索引大小
/**
* Maximum amount of memory in bytes to use for buffering frames
* obtained from realtime capture devices.
*/用于缓冲从实时捕获设备获得的帧的最大内存量(以字节为单位)。
unsigned int max_picture_buffer;//最大图像缓冲区大小
unsigned int nb_chapters;//文件中章节的数量
AVChapter **chapters;//指向AVChapter指针数组的指针,表示文件中的所有章节
/**
* Number of chapters in AVChapter array.
* When muxing, chapters are normally written in the file header,
* so nb_chapters should normally be initialized before write_header
* is called. Some muxers (e.g. mov and mkv) can also write chapters
* in the trailer. To write chapters in the trailer, nb_chapters
* must be zero when write_header is called and non-zero when
* write_trailer is called.
* - muxing: set by user
* - demuxing: set by libavformat
/**
*AVChapter数组中的章节数。
*当复用时,章节通常写在文件头中,
*因此nbchapter通常应该在调用writeheader之前初始化。
一些复用器(例如mov和mkv)也可以在预告片中编写章节。
若要在预告片中写入章节,当调用write_header时,nb_chappers必须为零,而当调用write_trailer时,则nb_chapters必须为非零。
*-muxing:由用户设置
*-demuxing:由libavformat设置
*/
unsigned int nb_chapters;
AVChapter **chapters;
AVDictionary *metadata;//元数据
/**
* Metadata that applies to the whole file.
*
* - demuxing: set by libavformat in avformat_open_input()
* - muxing: may be set by the caller before avformat_write_header()
*
* Freed by libavformat in avformat_free_context().
*/
AVDictionary *metadata;
/**
* Start time of the stream in real world time, in microseconds
* since the Unix epoch (00:00 1st January 1970). That is, pts=0 in the
* stream was captured at this real world time.
* - muxing: Set by the caller before avformat_write_header(). If set to
* either 0 or AV_NOPTS_VALUE, then the current wall-time will
* be used.
* - demuxing: Set by libavformat. AV_NOPTS_VALUE if unknown. Note that
* the value may become known after some number of frames
* have been received.
*/
int64_t start_time_realtime;//实际开始时间
/**
* The number of frames used for determining the framerate in
* avformat_find_stream_info().
* Demuxing only, set by the caller before avformat_find_stream_info().
*/
int fps_probe_size;//fps探测大小
int error_recognition;//错误识别
/**
* Error recognition; higher values will detect more errors but may
* misdetect some more or less valid parts as errors.
* Demuxing only, set by the caller before avformat_open_input().
*/
int error_recognition;
AVIOInterruptCB interrupt_callback;//I/O中断回调函数
/**
* Custom interrupt callbacks for the I/O layer.
*
* demuxing: set by the user before avformat_open_input().
* muxing: set by the user before avformat_write_header()
* (mainly useful for AVFMT_NOFILE formats). The callback
* should also be passed to avio_open2() if it's used to
* open the file.
*/
AVIOInterruptCB interrupt_callback;
int debug;//调试标志
/**
* Maximum buffering duration for interleaving.
*
* To ensure all the streams are interleaved correctly,
* av_interleaved_write_frame() will wait until it has at least one packet
* for each stream before actually writing any packets to the output file.
* When some streams are "sparse" (i.e. there are large gaps between
* successive packets), this can result in excessive buffering.
*
* This field specifies the maximum difference between the timestamps of the
* first and the last packet in the muxing queue, above which libavformat
* will output a packet regardless of whether it has queued a packet for all
* the streams.
*
* Muxing only, set by the caller before avformat_write_header().
*/
int64_t max_interleave_delta;
*交织的最大缓冲持续时间。
*
*为了确保所有流被正确地交织,
*av_interleaved_write_frame()将等待,直到它为每个流至少有一个数据包,然后才将任何数据包实际写入输出文件。
*当一些流是“稀疏的”(即连续数据包之间有很大的间隙)时,这可能会导致缓冲过度。
*
*该字段指定复用队列中第一个和最后一个分组的时间戳之间的最大差值,
超过该阈值,libavformat将输出数据包,而不管它是否已将数据包排队用于所有流。
*
*仅限Muxing,由调用方在avformat_write_header()之前设置。
/**
* Allow non-standard and experimental extension
* @see AVCodecContext.strict_std_compliance
*/
int strict_std_compliance;
/**
*允许非标准和实验性扩展
*@请参阅AVCodecContext。strict_std_compliance
*/
int strict_std_compliance;
/**
* Flags indicating events happening on the file, a combination of
* AVFMT_EVENT_FLAG_*.
*
* - demuxing: may be set by the demuxer in avformat_open_input(),
* avformat_find_stream_info() and av_read_frame(). Flags must be cleared
* by the user once the event has been handled.
* - muxing: may be set by the user after avformat_write_header() to
* indicate a user-triggered event. The muxer will clear the flags for
* events it has handled in av_[interleaved]_write_frame().
*/
int event_flags;
/**
*指示文件上发生的事件的标志
*AVFMT_EVENT_FLAG_*。
*
*-demuxing:可以由解复用器在avformat_open_input()、avformat_find_stream_info()和av_read_frame()中设置。处理完事件后,用户必须清除标志。
*-muxing:可以由用户在avformat_write_header()之后设置,以指示用户触发的事件。复用器将清除它在av_[interleaved]_write_frame()中处理的事件的标志。
*/
int event_flags;
/**
* - demuxing: the demuxer read new metadata from the file and updated
* AVFormatContext.metadata accordingly
* - muxing: the user updated AVFormatContext.metadata and wishes the muxer to
* write it into the file
*/
#define AVFMT_EVENT_FLAG_METADATA_UPDATED 0x0001
/**
* Maximum number of packets to read while waiting for the first timestamp.
* Decoding only.
*/
int max_ts_probe;
/**
*等待第一个时间戳时要读取的最大数据包数。
*仅解码
/**
* Avoid negative timestamps during muxing.
* Any value of the AVFMT_AVOID_NEG_TS_* constants.
* Note, this works better when using av_interleaved_write_frame().
* - muxing: Set by user
* - demuxing: unused
*/
int avoid_negative_ts;
#define AVFMT_AVOID_NEG_TS_AUTO -1 ///< Enabled when required by target format
#define AVFMT_AVOID_NEG_TS_DISABLED 0 ///< Do not shift timestamps even when they are negative.
#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
/**
*在复用期间避免出现负时间戳。
*AVFMT_AVOID_NEG_TS_*常量的任何值。
*注意,使用av_interleaved_write_frame()时效果更好。
*-muxing:由用户设置
*-去复用:未使用
*/
int avoid_negative_ts;
#定义AVFMT_AVOID_NEG_TS_AUTO-1///<目标格式要求时启用
#定义AVFMT_AVOID_NEG_TS_DISABLED 0///<即使时间戳为负数,也不要移动时间戳。
#定义AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE 1///<切换时间戳,使其为非负值
#定义AVFMT_AVOID_NEG_TS_MAKE_ZERO 2///<切换时间戳,使其从0开始
/**
* Transport stream id.
* This will be moved into demuxer private options. Thus no API/ABI compatibility
*/
int ts_id;//传输流ID
int audio_preload;//音频预加载
/**
* Audio preload in microseconds.
* Note, not all formats support this and unpredictable things may happen if it is used when not supported.
* - encoding: Set by user
* - decoding: unused
*/
int audio_preload;
/**
*音频预加载(以微秒为单位)。
*请注意,并非所有格式都支持这一点,如果在不支持的情况下使用它,可能会发生不可预测的事情。
*-encoding:由用户设置
*-解码:未使用
*/
int audio_preload;
/**
* Max chunk time in microseconds.
* Note, not all formats support this and unpredictable things may happen if it is used when not supported.
* - encoding: Set by user
* - decoding: unused
*/
int max_chunk_duration;int max_chunk_duration;//最大块时长
/**
*最大区块时间(以微秒为单位)。
*请注意,并非所有格式都支持这一点,如果在不支持的情况下使用它,可能会发生不可预测的事情。
*-encoding:由用户设置
*-解码:未使用
*/
int max_chunk_duration;
/**
* Max chunk size in bytes
* Note, not all formats support this and unpredictable things may happen if it is used when not supported.
* - encoding: Set by user
* - decoding: unused
*/
int max_chunk_size;
/**
*最大区块大小(字节)
*请注意,并非所有格式都支持这一点,如果在不支持的情况下使用它,可能会发生不可预测的事情。
*-encoding:由用户设置
*-解码:未使用
*/
int max_chunk_size;//最大块大小
/**
* forces the use of wallclock timestamps as pts/dts of packets
* This has undefined results in the presence of B frames.
* - encoding: unused
* - decoding: Set by user
*/
int use_wallclock_as_timestamps;
/**
*强制使用wallclock时间戳作为数据包的pts/dts
*这在存在B帧的情况下具有未定义的结果。
*-编码:未使用
*-解码:由用户设置
*/
int use_wallclock_as_timestamps;
/**
* avio flags, used to force AVIO_FLAG_DIRECT.
* - encoding: unused
* - decoding: Set by user
*/
int avio_flags;
/**
* The duration field can be estimated through various ways, and this field can be used
* to know how the duration was estimated.
* - encoding: unused
* - decoding: Read by user
*/
enum AVDurationEstimationMethod duration_estimation_method;
持续时间字段可以通过各种方式进行估计,并且该字段可以用于了解如何估计持续时间。
/**
* Skip initial bytes when opening stream
* - encoding: unused
* - decoding: Set by user
*/
int64_t