文章目录
- 一、概述
- 二、解封装流程
- 三、重要结构体
- 四、重要函数分析
- 五、实例
团队博客: 汽车电子社区
一、概述
avformat中实现了目前多媒体领域中的几乎所有封装格式,可以封装,可以解封装(也叫解复用),根据需求不同,所支持的也有所不同,ffmpeg能否支持一种封装格式的视频的封装与解封装,完全取决于这个库,例如mp4、flv、mkv等容器的封装与解封装;又或者RTMP、RTSP、TCP、UDP等协议的封装与解封装;关于封装与解封装的操作,对CPU的消耗不会特别严重,因为封装与解封装不涉及到复杂的计算,更多的是I/O,如果希望增加自己定制的封装格式的话,需要在libavformat中增加自己的对应的format模块。通过代码的文件结构可以看得出来。
二、解封装流程
1、avformat_alloc_context():负责申请一个AVFormatContext结构的内存,并进行简单初始化。
2、avformat_open_input():打开输入音/视频文件。
3、avformat_find_stream_info():获取音视频文件信息。
4、av_read_frame():读取音视频包。
5、avformat_seek_file():定位文件。
6、av_seek_frame():定位文件。
7、avformat_free_context():释放该结构里的所有东西以及该结构本身。
8、avformat_close_input():关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放。
三、重要结构体
3.1、AVFormatContext
AVFormatContext是FFmpeg中一个非常重要的结构体,它包含了一个完整的媒体文件或媒体流的所有信息。在FFmpeg中,每一个AVFormatContext结构体都对应着一个媒体文件或媒体流。当我们使用FFmpe对媒体文件或者媒体流的解码、编码或者转换时,都是基于AVFormatContext结构体进行操作的。
AVFormatContext结构体包含的信息很多,其中最重要的时AVInputFormat和AVOutputFormat,它们分表代表输入和输出的格式,包含了所有支持的编解码器、封装格式、容器格式等信息。在使用FFmpeg进行媒体文件或者媒体流的解码、编码或者转换时,我们需要根据不同的输入和输出格式来选择合适的VInputFormat和AVOutputFormat。
除了AVInputFormat和AVOutputFormat以外,AVFormatContext还包含了一些其它的信息,比如AVStream,它表示一个媒体流的所有信息,包括媒体流的类型、编码方式、采样率、帧率等;AVCodecContext表示一个编解码器的所有信息,包括编解码器的类型、编解码方式、采样率、帧率等等;AVDictionary它是一个字典类型的结构体,用于存储一些额外的元数据信息,比如媒体文件的标题、作者、描述等等。
cpp
typedef struct AVFormatContext {
/**
* A class for logging and @ref avoptions. Set by avformat_alloc_context().
* Exports (de)muxer private options if they exist.
*/
const AVClass *av_class;
/**
* The input container format.
*
* Demuxing only, set by avformat_open_input().
*/
const struct AVInputFormat *iformat;
/**
* The output container format.
*
* Muxing only, must be set by the caller before avformat_write_header().
*/
const 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;
/**
* 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.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
/* stream info */
/**
* Flags signalling stream properties. A combination of AVFMTCTX_*.
* Set by libavformat.
*/
int ctx_flags;
/**
* 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;
/**
* 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;
/**
* Position of the first frame of the component, in
* AV_TIME_BASE fractional seconds. NEVER set this value directly:
* It is deduced from the AVStream values.
*
* Demuxing only, set by libavformat.
*/
int64_t start_time;
/**
* 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;
/**
* 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.
*/
int64_t bit_rate;
unsigned int packet_size;
int max_delay;
/**
* Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*.
* Set by the user before avformat_open_input() / avformat_write_header().
*/
int flags;
#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_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down)
#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats
#if FF_API_LAVF_SHORTEST
#define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops.
#endif
#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer
/**
* Maximum number of bytes read from input in order to determine stream
* properties. Used when reading the global header and in
* avformat_find_stream_info().
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @note this is \e not used for determining the \ref AVInputFormat
* "input format"
* @sa format_probesize
*/
int64_t probesize;
/**
* Maximum duration (in AV_TIME_BASE units) of the data read
* from input in avformat_find_stream_info().
* Demuxing only, set by the caller before avformat_find_stream_info().
* Can be set to 0 to let avformat choose using a heuristic.
*/
int64_t max_analyze_duration;
const uint8_t *key;
int keylen;
unsigned int nb_programs;
AVProgram **programs;
/**
* 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;
/**
* 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
*/
unsigned int nb_chapters;
AVChapter **chapters;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* Flags to enable debugging.
*/
int debug;
#define FF_FDEBUG_TS 0x0001
/**
* 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;
/**
* Allow non-standard and experimental extension
* @see 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;
/**
* - 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
/**
* Transport stream id.
* This will be moved into demuxer private options. Thus no API/ABI compatibility
*/
int ts_id;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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 skip_initial_bytes;
/**
* Correct single timestamp overflows
* - encoding: unused
* - decoding: Set by user
*/
unsigned int correct_ts_overflow;
/**
* Force seeking to any (also non key) frames.
* - encoding: unused
* - decoding: Set by user
*/
int seek2any;
/**
* Flush the I/O context after each packet.
* - encoding: Set by user
* - decoding: unused
*/
int flush_packets;
/**
* format probing score.
* The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes
* the format.
* - encoding: unused
* - decoding: set by avformat, read by user
*/
int probe_score;
/**
* Maximum number of bytes read from input in order to identify the
* \ref AVInputFormat "input format". Only used when the format is not set
* explicitly by the caller.
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @sa probesize
*/
int format_probesize;
/**
* ',' separated list of allowed decoders.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *codec_whitelist;
/**
* ',' separated list of allowed demuxers.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *format_whitelist;
/**
* IO repositioned flag.
* This is set by avformat when the underlaying IO context read pointer
* is repositioned, for example when doing byte based seeking.
* Demuxers can use the flag to detect such changes.
*/
int io_repositioned;
/**
* Forced video codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *video_codec;
/**
* Forced audio codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *audio_codec;
/**
* Forced subtitle codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *subtitle_codec;
/**
* Forced data codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *data_codec;
/**
* Number of bytes to be written as padding in a metadata header.
* Demuxing: Unused.
* Muxing: Set by user via av_format_set_metadata_header_padding.
*/
int metadata_header_padding;
/**
* User data.
* This is a place for some private data of the user.
*/
void *opaque;
/**
* Callback used by devices to communicate with application.
*/
av_format_control_message control_message_cb;
/**
* Output timestamp offset, in microseconds.
* Muxing: set by user
*/
int64_t output_ts_offset;
/**
* dump format separator.
* can be ", " or "\n " or anything else
* - muxing: Set by user.
* - demuxing: Set by user.
*/
uint8_t *dump_separator;
/**
* Forced Data codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID data_codec_id;
/**
* ',' separated list of allowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_whitelist;
/**
* A callback for opening new IO streams.
*
* Whenever a muxer or a demuxer needs to open an IO stream (typically from
* avformat_open_input() for demuxers, but for certain formats can happen at
* other times as well), it will call this callback to obtain an IO context.
*
* @param s the format context
* @param pb on success, the newly opened IO context should be returned here
* @param url the url to open
* @param flags a combination of AVIO_FLAG_*
* @param options a dictionary of additional options, with the same
* semantics as in avio_open2()
* @return 0 on success, a negative AVERROR code on failure
*
* @note Certain muxers and demuxers do nesting, i.e. they open one or more
* additional internal format contexts. Thus the AVFormatContext pointer
* passed to this callback may be different from the one facing the caller.
* It will, however, have the same 'opaque' field.
*/
int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
int flags, AVDictionary **options);
#if FF_API_AVFORMAT_IO_CLOSE
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* @deprecated use io_close2
*/
attribute_deprecated
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
#endif
/**
* ',' separated list of disallowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protoctypedef struct AVFormatContext {
/**
* A class for logging and @ref avoptions. Set by avformat_alloc_context().
* Exports (de)muxer private options if they exist.
*/
const AVClass *av_class;
/**
* The input container format.
*
* Demuxing only, set by avformat_open_input().
*/
const struct AVInputFormat *iformat;
/**
* The output container format.
*
* Muxing only, must be set by the caller before avformat_write_header().
*/
const 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;
/**
* 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.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
/* stream info */
/**
* Flags signalling stream properties. A combination of AVFMTCTX_*.
* Set by libavformat.
*/
int ctx_flags;
/**
* 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;
/**
* 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;
/**
* Position of the first frame of the component, in
* AV_TIME_BASE fractional seconds. NEVER set this value directly:
* It is deduced from the AVStream values.
*
* Demuxing only, set by libavformat.
*/
int64_t start_time;
/**
* 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;
/**
* 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.
*/
int64_t bit_rate;
unsigned int packet_size;
int max_delay;
/**
* Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*.
* Set by the user before avformat_open_input() / avformat_write_header().
*/
int flags;
#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_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down)
#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats
#if FF_API_LAVF_SHORTEST
#define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops.
#endif
#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer
/**
* Maximum number of bytes read from input in order to determine stream
* properties. Used when reading the global header and in
* avformat_find_stream_info().
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @note this is \e not used for determining the \ref AVInputFormat
* "input format"
* @sa format_probesize
*/
int64_t probesize;
/**
* Maximum duration (in AV_TIME_BASE units) of the data read
* from input in avformat_find_stream_info().
* Demuxing only, set by the caller before avformat_find_stream_info().
* Can be set to 0 to let avformat choose using a heuristic.
*/
int64_t max_analyze_duration;
const uint8_t *key;
int keylen;
unsigned int nb_programs;
AVProgram **programs;
/**
* 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;
/**
* 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
*/
unsigned int nb_chapters;
AVChapter **chapters;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* Flags to enable debugging.
*/
int debug;
#define FF_FDEBUG_TS 0x0001
/**
* 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;
/**
* Allow non-standard and experimental extension
* @see 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;
/**
* - 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
/**
* Transport stream id.
* This will be moved into demuxer private options. Thus no API/ABI compatibility
*/
int ts_id;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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 skip_initial_bytes;
/**
* Correct single timestamp overflows
* - encoding: unused
* - decoding: Set by user
*/
unsigned int correct_ts_overflow;
/**
* Force seeking to any (also non key) frames.
* - encoding: unused
* - decoding: Set by user
*/
int seek2any;
/**
* Flush the I/O context after each packet.
* - encoding: Set by user
* - decoding: unused
*/
int flush_packets;
/**
* format probing score.
* The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes
* the format.
* - encoding: unused
* - decoding: set by avformat, read by user
*/
int probe_score;
/**
* Maximum number of bytes read from input in order to identify the
* \ref AVInputFormat "input format". Only used when the format is not set
* explicitly by the caller.
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @sa probesize
*/
int format_probesize;
/**
* ',' separated list of allowed decoders.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *codec_whitelist;
/**
* ',' separated list of allowed demuxers.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *format_whitelist;
/**
* IO repositioned flag.
* This is set by avformat when the underlaying IO context read pointer
* is repositioned, for example when doing byte based seeking.
* Demuxers can use the flag to detect such changes.
*/
int io_repositioned;
/**
* Forced video codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *video_codec;
/**
* Forced audio codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *audio_codec;
/**
* Forced subtitle codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *subtitle_codec;
/**
* Forced data codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *data_codec;
/**
* Number of bytes to be written as padding in a metadata header.
* Demuxing: Unused.
* Muxing: Set by user via av_format_set_metadata_header_padding.
*/
int metadata_header_padding;
/**
* User data.
* This is a place for some private data of the user.
*/
void *opaque;
/**
* Callback used by devices to communicate with application.
*/
av_format_control_message control_message_cb;
/**
* Output timestamp offset, in microseconds.
* Muxing: set by user
*/
int64_t output_ts_offset;
/**
* dump format separator.
* can be ", " or "\n " or anything else
* - muxing: Set by user.
* - demuxing: Set by user.
*/
uint8_t *dump_separator;
/**
* Forced Data codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID data_codec_id;
/**
* ',' separated list of allowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_whitelist;
/**
* A callback for opening new IO streams.
*
* Whenever a muxer or a demuxer needs to open an IO stream (typically from
* avformat_open_input() for demuxers, but for certain formats can happen at
* other times as well), it will call this callback to obtain an IO context.
*
* @param s the format context
* @param pb on success, the newly opened IO context should be returned here
* @param url the url to open
* @param flags a combination of AVIO_FLAG_*
* @param options a dictionary of additional options, with the same
* semantics as in avio_open2()
* @return 0 on success, a negative AVERROR code on failure
*
* @note Certain muxers and demuxers do nesting, i.e. they open one or more
* additional internal format contexts. Thus the AVFormatContext pointer
* passed to this callback may be different from the one facing the caller.
* It will, however, have the same 'opaque' field.
*/
int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
int flags, AVDictionary **options);
#if FF_API_AVFORMAT_IO_CLOSE
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* @deprecated use io_close2
*/
attribute_deprecated
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
#endif
/**
* ',' separated list of disallowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_blacklist;
/**
* The maximum number of streams.
* - encoding: unused
* - decoding: set by user
*/
int max_streams;
/**
* Skip duration calcuation in estimate_timings_from_pts.
* - encoding: unused
* - decoding: set by user
*/
int skip_estimate_duration_from_pts;
/**
* Maximum number of packets that can be probed
* - encoding: unused
* - decoding: set by user
*/
int max_probe_packets;
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* Using this is preferred over io_close, because this can return an error.
* Therefore this callback is used instead of io_close by the generic
* libavformat code if io_close is NULL or the default.
*
* @param s the format context
* @param pb IO context to be closed and freed
* @return 0 on success, a negative AVERROR code on failure
*/
int (*io_close2)(struct AVFormatContext *s, AVIOContext *pb);
} AVFormatContext;typedef struct AVFormatContext {
/**
* A class for logging and @ref avoptions. Set by avformat_alloc_context().
* Exports (de)muxer private options if they exist.
*/
const AVClass *av_class;
/**
* The input container format.
*
* Demuxing only, set by avformat_open_input().
*/
const struct AVInputFormat *iformat;
/**
* The output container format.
*
* Muxing only, must be set by the caller before avformat_write_header().
*/
const 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;
/**
* 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.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
/* stream info */
/**
* Flags signalling stream properties. A combination of AVFMTCTX_*.
* Set by libavformat.
*/
int ctx_flags;
/**
* 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;
/**
* 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;
/**
* Position of the first frame of the component, in
* AV_TIME_BASE fractional seconds. NEVER set this value directly:
* It is deduced from the AVStream values.
*
* Demuxing only, set by libavformat.
*/
int64_t start_time;
/**
* 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;
/**
* 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.
*/
int64_t bit_rate;
unsigned int packet_size;
int max_delay;
/**
* Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*.
* Set by the user before avformat_open_input() / avformat_write_header().
*/
int flags;
#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_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down)
#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats
#if FF_API_LAVF_SHORTEST
#define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops.
#endif
#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer
/**
* Maximum number of bytes read from input in order to determine stream
* properties. Used when reading the global header and in
* avformat_find_stream_info().
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @note this is \e not used for determining the \ref AVInputFormat
* "input format"
* @sa format_probesize
*/
int64_t probesize;
/**
* Maximum duration (in AV_TIME_BASE units) of the data read
* from input in avformat_find_stream_info().
* Demuxing only, set by the caller before avformat_find_stream_info().
* Can be set to 0 to let avformat choose using a heuristic.
*/
int64_t max_analyze_duration;
const uint8_t *key;
int keylen;
unsigned int nb_programs;
AVProgram **programs;
/**
* 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;
/**
* 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
*/
unsigned int nb_chapters;
AVChapter **chapters;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* Flags to enable debugging.
*/
int debug;
#define FF_FDEBUG_TS 0x0001
/**
* 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;
/**
* Allow non-standard and experimental extension
* @see 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;
/**
* - 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
/**
* Transport stream id.
* This will be moved into demuxer private options. Thus no API/ABI compatibility
*/
int ts_id;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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 skip_initial_bytes;
/**
* Correct single timestamp overflows
* - encoding: unused
* - decoding: Set by user
*/
unsigned int correct_ts_overflow;
/**
* Force seeking to any (also non key) frames.
* - encoding: unused
* - decoding: Set by user
*/
int seek2any;
/**
* Flush the I/O context after each packet.
* - encoding: Set by user
* - decoding: unused
*/
int flush_packets;
/**
* format probing score.
* The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes
* the format.
* - encoding: unused
* - decoding: set by avformat, read by user
*/
int probe_score;
/**
* Maximum number of bytes read from input in order to identify the
* \ref AVInputFormat "input format". Only used when the format is not set
* explicitly by the caller.
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @sa probesize
*/
int format_probesize;
/**
* ',' separated list of allowed decoders.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *codec_whitelist;
/**
* ',' separated list of allowed demuxers.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *format_whitelist;
/**
* IO repositioned flag.
* This is set by avformat when the underlaying IO context read pointer
* is repositioned, for example when doing byte based seeking.
* Demuxers can use the flag to detect such changes.
*/
int io_repositioned;
/**
* Forced video codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *video_codec;
/**
* Forced audio codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *audio_codec;
/**
* Forced subtitle codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *subtitle_codec;
/**
* Forced data codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *data_codec;
/**
* Number of bytes to be written as padding in a metadata header.
* Demuxing: Unused.
* Muxing: Set by user via av_format_set_metadata_header_padding.
*/
int metadata_header_padding;
/**
* User data.
* This is a place for some private data of the user.
*/
void *opaque;
/**
* Callback used by devices to communicate with application.
*/
av_format_control_message control_message_cb;
/**
* Output timestamp offset, in microseconds.
* Muxing: set by user
*/
int64_t output_ts_offset;
/**
* dump format separator.
* can be ", " or "\n " or anything else
* - muxing: Set by user.
* - demuxing: Set by user.
*/
uint8_t *dump_separator;
/**
* Forced Data codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID data_codec_id;
/**
* ',' separated list of allowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_whitelist;
/**
* A callback for opening new IO streams.
*
* Whenever a muxer or a demuxer needs to open an IO stream (typically from
* avformat_open_input() for demuxers, but for certain formats can happen at
* other times as well), it will call this callback to obtain an IO context.
*
* @param s the format context
* @param pb on success, the newly opened IO context should be returned here
* @param url the url to open
* @param flags a combination of AVIO_FLAG_*
* @param options a dictionary of additional options, with the same
* semantics as in avio_open2()
* @return 0 on success, a negative AVERROR code on failure
*
* @note Certain muxers and demuxers do nesting, i.e. they open one or more
* additional internal format contexts. Thus the AVFormatContext pointer
* passed to this callback may be different from the one facing the caller.
* It will, however, have the same 'opaque' field.
*/
int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
int flags, AVDictionary **options);
#if FF_API_AVFORMAT_IO_CLOSE
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* @deprecated use io_close2
*/
attribute_deprecated
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
#endif
/**
* ',' separated list of disallowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_blacklist;
/**
* The maximum number of streams.
* - encoding: unused
* - decoding: set by user
*/
int max_streams;
/**
* Skip duration calcuation in estimate_timings_from_pts.
* - encoding: unused
* - decoding: set by user
*/
int skip_estimate_duration_from_pts;
/**
* Maximum number of packets that can be probed
* - encoding: unused
* - decoding: set by user
*/
int max_probe_packets;
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* Using this is preferred over io_close, because this can return an error.
* Therefore this callback is used instead of io_close by the generic
* libavformat code if io_close is NULL or the default.
*
* @param s the format context
* @param pb IO context to be closed and freed
* @return 0 on success, a negative AVERROR code on failure
*/
int (*io_close2)(struct AVFormatContext *s, AVIOContext *pb);
} AVFormatContext;typedef struct AVFormatContext {
/**
* A class for logging and @ref avoptions. Set by avformat_alloc_context().
* Exports (de)muxer private options if they exist.
*/
const AVClass *av_class;
/**
* The input container format.
*
* Demuxing only, set by avformat_open_input().
*/
const struct AVInputFormat *iformat;
/**
* The output container format.
*
* Muxing only, must be set by the caller before avformat_write_header().
*/
const 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;
/**
* 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.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
/* stream info */
/**
* Flags signalling stream properties. A combination of AVFMTCTX_*.
* Set by libavformat.
*/
int ctx_flags;
/**
* 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;
/**
* 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;
/**
* Position of the first frame of the component, in
* AV_TIME_BASE fractional seconds. NEVER set this value directly:
* It is deduced from the AVStream values.
*
* Demuxing only, set by libavformat.
*/
int64_t start_time;
/**
* 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;
/**
* 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.
*/
int64_t bit_rate;
unsigned int packet_size;
int max_delay;
/**
* Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*.
* Set by the user before avformat_open_input() / avformat_write_header().
*/
int flags;
#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_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down)
#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats
#if FF_API_LAVF_SHORTEST
#define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops.
#endif
#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer
/**
* Maximum number of bytes read from input in order to determine stream
* properties. Used when reading the global header and in
* avformat_find_stream_info().
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @note this is \e not used for determining the \ref AVInputFormat
* "input format"
* @sa format_probesize
*/
int64_t probesize;
/**
* Maximum duration (in AV_TIME_BASE units) of the data read
* from input in avformat_find_stream_info().
* Demuxing only, set by the caller before avformat_find_stream_info().
* Can be set to 0 to let avformat choose using a heuristic.
*/
int64_t max_analyze_duration;
const uint8_t *key;
int keylen;
unsigned int nb_programs;
AVProgram **programs;
/**
* 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;
/**
* 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
*/
unsigned int nb_chapters;
AVChapter **chapters;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* Flags to enable debugging.
*/
int debug;
#define FF_FDEBUG_TS 0x0001
/**
* 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;
/**
* Allow non-standard and experimental extension
* @see 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;
/**
* - 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
/**
* Transport stream id.
* This will be moved into demuxer private options. Thus no API/ABI compatibility
*/
int ts_id;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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 skip_initial_bytes;
/**
* Correct single timestamp overflows
* - encoding: unused
* - decoding: Set by user
*/
unsigned int correct_ts_overflow;
/**
* Force seeking to any (also non key) frames.
* - encoding: unused
* - decoding: Set by user
*/
int seek2any;
/**
* Flush the I/O context after each packet.
* - encoding: Set by user
* - decoding: unused
*/
int flush_packets;
/**
* format probing score.
* The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes
* the format.
* - encoding: unused
* - decoding: set by avformat, read by user
*/
int probe_score;
/**
* Maximum number of bytes read from input in order to identify the
* \ref AVInputFormat "input format". Only used when the format is not set
* explicitly by the caller.
*
* Demuxing only, set by the caller before avformat_open_input().
*
* @sa probesize
*/
int format_probesize;
/**
* ',' separated list of allowed decoders.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *codec_whitelist;
/**
* ',' separated list of allowed demuxers.
* If NULL then all are allowed
* - encoding: unused
* - decoding: set by user
*/
char *format_whitelist;
/**
* IO repositioned flag.
* This is set by avformat when the underlaying IO context read pointer
* is repositioned, for example when doing byte based seeking.
* Demuxers can use the flag to detect such changes.
*/
int io_repositioned;
/**
* Forced video codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *video_codec;
/**
* Forced audio codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *audio_codec;
/**
* Forced subtitle codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *subtitle_codec;
/**
* Forced data codec.
* This allows forcing a specific decoder, even when there are multiple with
* the same codec_id.
* Demuxing: Set by user
*/
const struct AVCodec *data_codec;
/**
* Number of bytes to be written as padding in a metadata header.
* Demuxing: Unused.
* Muxing: Set by user via av_format_set_metadata_header_padding.
*/
int metadata_header_padding;
/**
* User data.
* This is a place for some private data of the user.
*/
void *opaque;
/**
* Callback used by devices to communicate with application.
*/
av_format_control_message control_message_cb;
/**
* Output timestamp offset, in microseconds.
* Muxing: set by user
*/
int64_t output_ts_offset;
/**
* dump format separator.
* can be ", " or "\n " or anything else
* - muxing: Set by user.
* - demuxing: Set by user.
*/
uint8_t *dump_separator;
/**
* Forced Data codec_id.
* Demuxing: Set by user.
*/
enum AVCodecID data_codec_id;
/**
* ',' separated list of allowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_whitelist;
/**
* A callback for opening new IO streams.
*
* Whenever a muxer or a demuxer needs to open an IO stream (typically from
* avformat_open_input() for demuxers, but for certain formats can happen at
* other times as well), it will call this callback to obtain an IO context.
*
* @param s the format context
* @param pb on success, the newly opened IO context should be returned here
* @param url the url to open
* @param flags a combination of AVIO_FLAG_*
* @param options a dictionary of additional options, with the same
* semantics as in avio_open2()
* @return 0 on success, a negative AVERROR code on failure
*
* @note Certain muxers and demuxers do nesting, i.e. they open one or more
* additional internal format contexts. Thus the AVFormatContext pointer
* passed to this callback may be different from the one facing the caller.
* It will, however, have the same 'opaque' field.
*/
int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url,
int flags, AVDictionary **options);
#if FF_API_AVFORMAT_IO_CLOSE
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* @deprecated use io_close2
*/
attribute_deprecated
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
#endif
/**
* ',' separated list of disallowed protocols.
* - encoding: unused
* - decoding: set by user
*/
char *protocol_blacklist;
/**
* The maximum number of streams.
* - encoding: unused
* - decoding: set by user
*/
int max_streams;
/**
* Skip duration calcuation in estimate_timings_from_pts.
* - encoding: unused
* - decoding: set by user
*/
int skip_estimate_duration_from_pts;
/**
* Maximum number of packets that can be probed
* - encoding: unused
* - decoding: set by user
*/
int max_probe_packets;
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* Using this is preferred over io_close, because this can return an error.
* Therefore this callback is used instead of io_close by the generic
* libavformat code if io_close is NULL or the default.
*
* @param s the format context
* @param pb IO context to be closed and freed
* @return 0 on success, a negative AVERROR code on failure
*/
int (*io_close2)(struct AVFormatContext *s, AVIOContext *pb);
} AVFormatContext;ol_blacklist;
/**
* The maximum number of streams.
* - encoding: unused
* - decoding: set by user
*/
int max_streams;
/**
* Skip duration calcuation in estimate_timings_from_pts.
* - encoding: unused
* - decoding: set by user
*/
int skip_estimate_duration_from_pts;
/**
* Maximum number of packets that can be probed
* - encoding: unused
* - decoding: set by user
*/
int max_probe_packets;
/**
* A callback for closing the streams opened with AVFormatContext.io_open().
*
* Using this is preferred over io_close, because this can return an error.
* Therefore this callback is used instead of io_close by the generic
* libavformat code if io_close is NULL or the default.
*
* @param s the format context
* @param pb IO context to be closed and freed
* @return 0 on success, a negative AVERROR code on failure
*/
int (*io_close2)(struct AVFormatContext *s, AVIOContext *pb);
} AVFormatContext;
1. nb_streams :表示容器中流的数量。
2. streams :AVStream类型指针数组,每个元素代表一个流。每个AVStream结构体包含有该流的相信信息。
3. duration :表示该容器的总时长,单位为微妙(可用的话)。
4. iformat/oformat :分别表示输入格式和输出格式的AVInputFormat/AVOutFormat结构体指针。
5. flags :包含有关容器选项的标志。常用标志包括AVFMT_NOFILE(不需要打开文件),AVFMT_FLOBALHEADER(向输出流写入全局标题),AVFMT------NOBINEARCH(禁用二进制搜索等)。
6. pb :AVIOContest结构体类型,代表文件输入/输出流。它与AVFormatContext跟踪同一个文件,并提供对该文件的读写操作。pb由avion_open2()打开。
7. metadata :包含元数据信息的AVDictionary类型指针,其中包含有关容器的任何其他信息,例如标题、作家、发行商等。
8. filename:表示输入/输出文件名的字符串、通常只给调试和打印统计信息使用。
3.2、AVInputFormat
AVInputFormat 是类似COM 接口的数据结构,表示输入文件容器格式,是解复用器(解封装)作用时读取媒体文件并将其拆分为数据块(数据包)。每个数据包,包含一个或者多个编码帧。着重于功能函数,一种文件容器格式对应一个AVInputFormat 结构,在程序运行时有多个实例,位于avoformat.h文件中。
cpp
typedef struct AVInputFormat {
/**
* A comma separated list of short names for the format. New names
* may be appended with a minor bump.
*/
const char *name;
/**
* Descriptive name for the format, meant to be more human-readable
* than name. You should use the NULL_IF_CONFIG_SMALL() macro
* to define it.
*/
const char *long_name;
/**
* Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,
* AVFMT_NOTIMESTAMPS, AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,
* AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS.
*/
int flags;
/**
* If extensions are defined, then no probe is done. You should
* usually not use extension format guessing because it is not
* reliable enough
*/
const char *extensions;
const struct AVCodecTag * const *codec_tag;
const AVClass *priv_class; ///< AVClass for the private context
/**
* Comma-separated list of mime types.
* It is used check for matching mime types while probing.
* @see av_probe_input_format2
*/
const char *mime_type;
/*****************************************************************
* No fields below this line are part of the public API. They
* may not be used outside of libavformat and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
/**
* Raw demuxers store their codec ID here.
*/
int raw_codec_id;
/**
* Size of private data so that it can be allocated in the wrapper.
*/
int priv_data_size;
/**
* Internal flags. See FF_FMT_FLAG_* in internal.h.
*/
int flags_internal;
/**
* Tell if a given file has a chance of being parsed as this format.
* The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes
* big so you do not have to check for that unless you need more.
*/
int (*read_probe)(const AVProbeData *);
/**
* Read the format header and initialize the AVFormatContext
* structure. Return 0 if OK. 'avformat_new_stream' should be
* called to create new streams.
*/
int (*read_header)(struct AVFormatContext *);
/**
* Read one packet and put it in 'pkt'. pts and flags are also
* set. 'avformat_new_stream' can be called only if the flag
* AVFMTCTX_NOHEADER is used and only in the calling thread (not in a
* background thread).
* @return 0 on success, < 0 on error.
* Upon returning an error, pkt must be unreferenced by the caller.
*/
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
/**
* Close the stream. The AVFormatContext and AVStreams are not
* freed by this function
*/
int (*read_close)(struct AVFormatContext *);
/**
* Seek to a given timestamp relative to the frames in
* stream component stream_index.
* @param stream_index Must not be -1.
* @param flags Selects which direction should be preferred if no exact
* match is available.
* @return >= 0 on success (but not necessarily the new offset)
*/
int (*read_seek)(struct AVFormatContext *,
int stream_index, int64_t timestamp, int flags);
/**
* Get the next timestamp in stream[stream_index].time_base units.
* @return the timestamp or AV_NOPTS_VALUE if an error occurred
*/
int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,
int64_t *pos, int64_t pos_limit);
/**
* Start/resume playing - only meaningful if using a network-based format
* (RTSP).
*/
int (*read_play)(struct AVFormatContext *);
/**
* Pause playing - only meaningful if using a network-based format
* (RTSP).
*/
int (*read_pause)(struct AVFormatContext *);
/**
* Seek to timestamp ts.
* Seeking will be done so that the point from which all active streams
* can be presented successfully will be closest to ts and within min/max_ts.
* Active streams are all streams that have AVStream.discard < AVDISCARD_ALL.
*/
int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
/**
* Returns device list with it properties.
* @see avdevice_list_devices() for more details.
*/
int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
} AVInputFormat;
1. const char *name :格式名列表.也可以分配一个新名字。
2. const char *long_name :格式的描述性名称,意味着比名称更易于阅读。
3. int flags :可用的flag有: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS。
4. const char *extensions :文件扩展名。
5. const AVClass *priv_class :一个模拟类型列表.用来在probe的时候check匹配的类型。
6. struct AVInputFormat *next :用于把所有支持的输入文件容器格式连接成链表,便于遍历查找。
7. int priv_data_size :标示具体的文件容器格式对应的Context 的大小。
8. int (*read_probe)(AVProbeData *) :判断一个给定的文件是否有可能被解析为这种格式。 给定的buf足够大,所以你没有必要去检查它,除非你需要更多 。
9. int (*read_header)(struct AVFormatContext *) :读取format头并初始化AVFormatContext结构体,如果成功,返回0。创建新的流需要调用avformat_new_stream。
10. int (*read_header2)(struct AVFormatContext *, AVDictionary **options) :新加的函数指针,用于打开进一步嵌套输入的格式。
11. int (*read_packet)(struct AVFormatContext *, AVPacket *pkt) :读取一个数据包并将其放在"pkt"中。 pts和flag也被设置。
12. int (*read_close)(struct AVFormatContext *) :关闭流。AVFormatContext和Streams不会被此函数释放。
13. int (*read_seek)(struct AVFormatContext *, int stream_index, int64_t timestamp, int flags)
14. int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, int64_t *pos, int64_t pos_limit) :获取stream [stream_index] .time_base单位中的下一个时间戳。
15. int (*read_play)(struct AVFormatContext *) :开始/继续播放 - 仅当使用基于网络的(RTSP)格式时才有意义。
16. int (*read_pause)(struct AVFormatContext *) :暂停播放 - 仅当使用基于网络的(RTSP)格式时才有意义。
17. int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags) :寻求时间戳ts。
18. int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list) :返回设备列表及其属性。
19. int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps) :初始化设备能力子模块。
20. int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps):释放设备能力子模块
3.3、AVOutputFormat
AVOutpufFormat与AVInputFormat类似,是类似COM 接口的数据结构,表示输出文件容器格式,着重于功能函数,位于Avoformat.h文件中。
cpp
typedef struct AVOutputFormat {
const char *name;
/**
* Descriptive name for the format, meant to be more human-readable
* than name. You should use the NULL_IF_CONFIG_SMALL() macro
* to define it.
*/
const char *long_name;
const char *mime_type;
const char *extensions; /**< comma-separated filename extensions */
/* output support */
enum AVCodecID audio_codec; /**< default audio codec */
enum AVCodecID video_codec; /**< default video codec */
enum AVCodecID subtitle_codec; /**< default subtitle codec */
/**
* can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER,
* AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS,
* AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS,
* AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE
*/
int flags;
/**
* List of supported codec_id-codec_tag pairs, ordered by "better
* choice first". The arrays are all terminated by AV_CODEC_ID_NONE.
*/
const struct AVCodecTag * const *codec_tag;
const AVClass *priv_class; ///< AVClass for the private context
} AVOutputFormat;
3.4、AVStream
AVStream是存储每一个视频/音频流信息的结构体。本文分析一下该结构体里重要变量的含义和作用。该结构体位于avformat.h中,首先看一下结构体的定义:
cpp
typedef struct AVStream {
/**
* A class for @ref avoptions. Set on stream creation.
*/
const AVClass *av_class;
int index; /**< stream index in AVFormatContext */
/**
* Format-specific stream ID.
* decoding: set by libavformat
* encoding: set by the user, replaced by libavformat if left unset
*/
int id;
/**
* Codec parameters associated with this stream. Allocated and freed by
* libavformat in avformat_new_stream() and avformat_free_context()
* respectively.
*
* - demuxing: filled by libavformat on stream creation or in
* avformat_find_stream_info()
* - muxing: filled by the caller before avformat_write_header()
*/
AVCodecParameters *codecpar;
void *priv_data;
/**
* This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented.
*
* decoding: set by libavformat
* encoding: May be set by the caller before avformat_write_header() to
* provide a hint to the muxer about the desired timebase. In
* avformat_write_header(), the muxer will overwrite this field
* with the timebase that will actually be used for the timestamps
* written into the file (which may or may not be related to the
* user-provided one, depending on the format).
*/
AVRational time_base;
/**
* Decoding: pts of the first frame of the stream in presentation order, in stream time base.
* Only set this if you are absolutely 100% sure that the value you set
* it to really is the pts of the first frame.
* This may be undefined (AV_NOPTS_VALUE).
* @note The ASF header does NOT contain a correct start_time the ASF
* demuxer must NOT set this.
*/
int64_t start_time;
/**
* Decoding: duration of the stream, in stream time base.
* If a source file does not specify a duration, but does specify
* a bitrate, this value will be estimated from bitrate and file size.
*
* Encoding: May be set by the caller before avformat_write_header() to
* provide a hint to the muxer about the estimated duration.
*/
int64_t duration;
int64_t nb_frames; ///< number of frames in this stream if known or 0
/**
* Stream disposition - a combination of AV_DISPOSITION_* flags.
* - demuxing: set by libavformat when creating the stream or in
* avformat_find_stream_info().
* - muxing: may be set by the caller before avformat_write_header().
*/
int disposition;
enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed.
/**
* sample aspect ratio (0 if unknown)
* - encoding: Set by user.
* - decoding: Set by libavformat.
*/
AVRational sample_aspect_ratio;
AVDictionary *metadata;
/**
* Average framerate
*
* - demuxing: May be set by libavformat when creating the stream or in
* avformat_find_stream_info().
* - muxing: May be set by the caller before avformat_write_header().
*/
AVRational avg_frame_rate;
/**
* For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet
* will contain the attached picture.
*
* decoding: set by libavformat, must not be modified by the caller.
* encoding: unused
*/
AVPacket attached_pic;
#if FF_API_AVSTREAM_SIDE_DATA
/**
* An array of side data that applies to the whole stream (i.e. the
* container does not allow it to change between packets).
*
* There may be no overlap between the side data in this array and side data
* in the packets. I.e. a given side data is either exported by the muxer
* (demuxing) / set by the caller (muxing) in this array, then it never
* appears in the packets, or the side data is exported / sent through
* the packets (always in the first packet where the value becomes known or
* changes), then it does not appear in this array.
*
* - demuxing: Set by libavformat when the stream is created.
* - muxing: May be set by the caller before avformat_write_header().
*
* Freed by libavformat in avformat_free_context().
*
* @deprecated use AVStream's @ref AVCodecParameters.coded_side_data
* "codecpar side data".
*/
attribute_deprecated
AVPacketSideData *side_data;
/**
* The number of elements in the AVStream.side_data array.
*
* @deprecated use AVStream's @ref AVCodecParameters.nb_coded_side_data
* "codecpar side data".
*/
attribute_deprecated
int nb_side_data;
#endif
/**
* Flags indicating events happening on the stream, a combination of
* AVSTREAM_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;
/**
* - demuxing: the demuxer read new metadata from the file and updated
* AVStream.metadata accordingly
* - muxing: the user updated AVStream.metadata and wishes the muxer to write
* it into the file
*/
#define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001
/**
* - demuxing: new packets for this stream were read from the file. This
* event is informational only and does not guarantee that new packets
* for this stream will necessarily be returned from av_read_frame().
*/
#define AVSTREAM_EVENT_FLAG_NEW_PACKETS (1 << 1)
/**
* Real base framerate of the stream.
* This is the lowest framerate with which all timestamps can be
* represented accurately (it is the least common multiple of all
* framerates in the stream). Note, this value is just a guess!
* For example, if the time base is 1/90000 and all frames have either
* approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
*/
AVRational r_frame_rate;
/**
* Number of bits in timestamps. Used for wrapping control.
*
* - demuxing: set by libavformat
* - muxing: set by libavformat
*
*/
int pts_wrap_bits;
} AVStream;
分析:
1. int index :在AVFormatContext中的流索引。
2. int id :流id,例如音频流id 视频流id等,解封装的时候,由libavformat模块来赋值;加封装的时候,由用户设置,如果未设置,则用libavformat替换。、
3. AVRational time_base :这是表示帧时间戳的基本时间单位(以秒为单位) 。
4. int64_t duration :解码时:流的持续时间,以流的时间为基数。如果源文件没有指定持续时间,但指定了比特率,则该值将根据比特率和文件大小进行估计。使用该数值得出视频流的持续时间,计算方式 duration *(time_base.num/time_base.den) 秒。duration的数值有可能为空,所以一般情况下使用AVFormatContext的duration来计算时长。
5. int64_t nb_frames :帧数。
6. AVRational sample_aspect_ratio :样本比特率。
7. AVRational avg_frame_rate :平均帧速率。
8. AVCodecParameters *codecpar:与此流相关的编解码器参数。分别在avformat_new_stream()和avformat_free_context()中由libavformat分配和释放。
四、重要函数分析
4.1、avformat_alloc_context
源码位于:libavformat/options.c
函数用来申请AVFormatContext类型变量并初始化默认参数。
该函数用于分配空间创建一个AVFormatContext对象,并且强调使用 avformat_free_context方法来清理并释放该对象的空间。
cpp
static const AVClass av_format_context_class = {
/**
* 类的名字,通常它与 AVClass 关联的上下文结构体类型的名字相同。
* 这里类名为"AVFormatContext",说明该 AVClass 关联的上下文结构体为
* AVFormatContext.
*/
.class_name = "AVFormatContext",
/**
* 这里这个函数返回的是 AVFormatContext 中 iformat->name
* 或者 oformat->name 字符串.
*/
.item_name = format_to_name,
/**
* avformat_options 是一个 AVOption 结构体类的数组,
* 该数组中的元素为 AVFormatContext 中的一个个字段,
* 以后可以通过 av_opt_* 系列函数对 AVFormatContext
* 中的字段进行操作。
*/
.option = avformat_options,
.version = LIBAVUTIL_VERSION_INT,
/**
* 返回下一个启用 AVOption 的子项
*/
.child_next = format_child_next,
.child_class_iterate = format_child_class_iterate,
.category = AV_CLASS_CATEGORY_MUXER,
.get_category = get_category,
};
static int io_open_default(AVFormatContext *s, AVIOContext **pb,
const char *url, int flags, AVDictionary **options)
{
int loglevel;
if (!strcmp(url, s->url) ||
s->iformat && !strcmp(s->iformat->name, "image2") ||
s->oformat && !strcmp(s->oformat->name, "image2")
) {
loglevel = AV_LOG_DEBUG;
} else
loglevel = AV_LOG_INFO;
av_log(s, loglevel, "Opening \'%s\' for %s\n", url, flags & AVIO_FLAG_WRITE ? "writing" : "reading");
return ffio_open_whitelist(pb, url, flags, &s->interrupt_callback, options, s->protocol_whitelist, s->protocol_blacklist);
}
#if FF_API_AVFORMAT_IO_CLOSE
void ff_format_io_close_default(AVFormatContext *s, AVIOContext *pb)
{
avio_close(pb);
}
#endif
static int io_close2_default(AVFormatContext *s, AVIOContext *pb)
{
return avio_close(pb);
}
AVFormatContext *avformat_alloc_context(void)
{
FFFormatContext *const si = av_mallocz(sizeof(*si)); //使用av_malloc分配空间,分配空间的作用是存储数据
AVFormatContext *s; //创建一个AVFormatContext对象为s
if (!si)
return NULL; //判断si是否为NILL,为空返回NULL
s = &si->pub;
s->av_class = &av_format_context_class;
s->io_open = io_open_default;
#if FF_API_AVFORMAT_IO_CLOSE
FF_DISABLE_DEPRECATION_WARNINGS
s->io_close = ff_format_io_close_default;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
s->io_close2= io_close2_default;
av_opt_set_defaults(s);
si->pkt = av_packet_alloc();
si->parse_pkt = av_packet_alloc();
if (!si->pkt || !si->parse_pkt) {
avformat_free_context(s);
return NULL;
}
#if FF_API_LAVF_SHORTEST
/* shortest_end:
* 最短的流结束的时间戳 */
si->shortest_end = AV_NOPTS_VALUE;
#endif
return s;
}
1. 创建AVFormatContext,他可用于由框架分配的在上下文和所有内容 ,即分配解复用器上下文。
2. 初始化io_open等函数指针,为init_input做准备。
3. 并初始化option相关参数给s。
4.2、avformat_open_input
cpp
int avformat_open_input(AVFormatContext **ps, const char *filename,
const AVInputFormat *fmt, AVDictionary **options)
{
AVFormatContext *s = *ps;
FFFormatContext *si;
AVDictionary *tmp = NULL;
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
int ret = 0;
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
si = ffformatcontext(s);
if (!s->av_class) {
av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
return AVERROR(EINVAL);
}
if (fmt)
s->iformat = fmt;
if (options)
av_dict_copy(&tmp, *options, 0);
if (s->pb) // must be before any goto fail
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if ((ret = av_opt_set_dict(s, &tmp)) < 0)
goto fail;
if (!(s->url = av_strdup(filename ? filename : ""))) {
ret = AVERROR(ENOMEM);
goto fail;
}
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
s->probe_score = ret;
if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {
s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);
if (!s->protocol_whitelist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
if (!s->protocol_blacklist && s->pb && s->pb->protocol_blacklist) {
s->protocol_blacklist = av_strdup(s->pb->protocol_blacklist);
if (!s->protocol_blacklist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);
ret = AVERROR(EINVAL);
goto fail;
}
avio_skip(s->pb, s->skip_initial_bytes);
/* Check filename in case an image number is expected. */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
if (!av_filename_number_test(filename)) {
ret = AVERROR(EINVAL);
goto fail;
}
}
s->duration = s->start_time = AV_NOPTS_VALUE;
/* Allocate private data. */
if (s->iformat->priv_data_size > 0) {
if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
ret = AVERROR(ENOMEM);
goto fail;
}
if (s->iformat->priv_class) {
*(const AVClass **) s->priv_data = s->iformat->priv_class;
av_opt_set_defaults(s->priv_data);
if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
goto fail;
}
}
/* e.g. AVFMT_NOFILE formats will not have an AVIOContext */
if (s->pb)
ff_id3v2_read_dict(s->pb, &si->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0) {
if (s->iformat->flags_internal & FF_FMT_INIT_CLEANUP)
goto close;
goto fail;
}
if (!s->metadata) {
s->metadata = si->id3v2_meta;
si->id3v2_meta = NULL;
} else if (si->id3v2_meta) {
av_log(s, AV_LOG_WARNING, "Discarding ID3 tags because more suitable tags were found.\n");
av_dict_free(&si->id3v2_meta);
}
if (id3v2_extra_meta) {
if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") ||
!strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) {
if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0)
goto close;
if ((ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0)
goto close;
if ((ret = ff_id3v2_parse_priv(s, id3v2_extra_meta)) < 0)
goto close;
} else
av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
}
if ((ret = avformat_queue_attached_pictures(s)) < 0)
goto close;
if (s->pb && !si->data_offset)
si->data_offset = avio_tell(s->pb);
si->raw_packet_buffer_size = 0;
update_stream_avctx(s);
if (options) {
av_dict_free(options);
*options = tmp;
}
*ps = s;
return 0;
close:
if (s->iformat->read_close)
s->iformat->read_close(s);
fail:
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
av_dict_free(&tmp);
if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
avio_closep(&s->pb);
avformat_free_context(s);
*ps = NULL;
return ret;
}
函数的形参:
ps :函数调用成功之后处理过的AVFormatContext结构体。
file :打开的视音频流的URL。
fmt :强制指定AVFormatContext中AVInputFormat的。这个参数一般情况下可以设置为NULL,这样FFmpeg可以自动检测AVInputFormat。
options :附加的一些选项,一般情况下可以设置为NULL。
在该函数中,FFMPEG完成了:
1. 输入输出结构体AVIOContext的初始化;
2. 输入数据的协议(例如RTMP,或者file)的识别(通过一套评分机制):
1. 判断文件名的后缀。
2. 读取文件头的数据进行比对。
3. 使用获得最高分的文件协议对应的URLProtocol,通过函数指针的方式,与FFMPEG连接(非专业用词)。
4. 剩下的就是调用该URLProtocol的函数进行open,read等操作了 没看到相关的代码。
4.2.1、init_input
cpp
static int init_input(AVFormatContext *s, const char *filename,
AVDictionary **options)
{
int ret;
AVProbeData pd = { filename, NULL, 0 };
int score = AVPROBE_SCORE_RETRY;
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if (!s->iformat)
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
s, 0, s->format_probesize);
else if (s->iformat->flags & AVFMT_NOFILE)
av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
"will be ignored with AVFMT_NOFILE format.\n");
return 0;
}
if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
return score;
if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
return ret;
if (s->iformat)
return 0;
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
s, 0, s->format_probesize);
}
这个函数在短短的几行代码中包含了好几个return,因此逻辑还是有点复杂的,我们可以梳理一下:在函数的开头的score变量是一个判决AVInputFormat的分数的门限值,如果最后得到的AVInputFormat的分数低于该门限值,就认为没有找到合适的AVInputFormat。
FFmpeg内部判断封装格式的原理实际上是对每种AVInputFormat给出一个分数,满分是100分,越有可能正确的AVInputFormat给出的分数就越高。最后选择分数最高的AVInputFormat作为推测结果。
score的值是一个宏定义AVPROBE_SCORE_RETRY,我们可以看一下它的定义:
cpp
#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4)
其中AVPROBE_SCORE_MAX是score的最大值,取值是100:
cpp
#define AVPROBE_SCORE_MAX 100 ///< maximum score
由此我们可以得出score取值是25,即如果推测后得到的最佳AVInputFormat的分值低于25,就认为没有找到合适的AVInputFormat。
整个函数的逻辑大体如下:
1. 当使用了自定义的AVIOContext的时候(AVFormatContext中的AVIOContext不为空,即s->pb!=NULL),如果指定了AVInputFormat就直接返回,如果没有指定就调用av_probe_input_buffer2()推测AVInputFormat。这一情况出现的不算很多,但是当我们从内存中读取数据的时候(需要初始化自定义的AVIOContext),就会执行这一步骤。
2. 在更一般的情况下,如果已经指定了AVInputFormat,就直接返回;如果没有指定AVInputFormat,就调用av_probe_input_format(NULL,...)根据文件路径判断文件格式。这里特意把av_probe_input_format()的第1个参数写成"NULL",是为了强调这个时候实际上并没有给函数提供输入数据,此时仅仅通过文件路径推测AVInputFormat。
3. 如果发现通过文件路径判断不出来文件格式,那么就需要打开文件探测文件格式了,这个时候会首先调用io_open()打开文件,然后调用av_probe_input_buffer2()推测AVInputFormat。
4.2.2、av_probe_input_format2
cpp
const AVInputFormat *av_probe_input_format2(const AVProbeData *pd,
int is_opened, int *score_max)
{
int score_ret;
const AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret);
if (score_ret > *score_max) {
*score_max = score_ret;
return fmt;
} else
return NULL;
}
该函数用于根据输入数据查找合适的AVInputFormat。参数含义如下所示:
pd :存储输入数据信息的AVProbeData结构体。
is_opened :文件是否打开。
score_max :判决AVInputFormat的门限值。只有某格式判决分数大于该门限值的时候,函数才会返回该封装格式,否则返回NULL。
从函数中可以看出,av_probe_input_format2()调用了av_probe_input_format3(),并且增加了一个判断,当av_probe_input_format3()返回的分数大于score_max的时候,才会返回AVInputFormat,否则返回NULL。
下面我们看一下av_probe_input_format3()
从函数声明中可以看出,av_probe_input_format3()和av_probe_input_format2()的区别是函数的第3个参数不同:av_probe_input_format2()是一个分数的门限值,而av_probe_input_format3()是一个探测后的最匹配的格式的分数值。
av_probe_input_format3函数最主要的部分是循环。该循环调用av_iformat_next()遍历(av_demuxer_iterate函数替代了av_iformat_next)FFmpeg中所有的AVInputFormat,并根据以下规则确定AVInputFormat和输入媒体数据的匹配分数(score,反应匹配程度):
1. 如果AVInputFormat中包含read_probe(),就调用read_probe()函数获取匹配分数(这一方法如果结果匹配的话,一般会获得AVPROBE_SCORE_MAX的分值,即100分)。如果不包含该函数,就使用av_match_ext()函数比较输入媒体的扩展名和AVInputFormat的扩展名是否匹配,如果匹配的话,设定匹配分数为AVPROBE_SCORE_EXTENSION(AVPROBE_SCORE_EXTENSION取值为50,即50分)。
2. 使用av_match_name()比较输入媒体的mime_type和AVInputFormat的mime_type,如果匹配的话,设定匹配分数为AVPROBE_SCORE_MIME(AVPROBE_SCORE_MIME取值为75,即75分)。
3. 如果该AVInputFormat的匹配分数大于此前的最大匹配分数,则记录当前的匹配分数为最大匹配分数,并且记录当前的AVInputFormat为最佳匹配的AVInputFormat。
4.3、avformat_find_stream_info
cpp
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
FFFormatContext *const si = ffformatcontext(ic);
int count = 0, ret = 0;
int64_t read_size;
AVPacket *pkt1 = si->pkt;
int64_t old_offset = avio_tell(ic->pb);
// new streams might appear, no options for those
int orig_nb_streams = ic->nb_streams;
int flush_codecs;
int64_t max_analyze_duration = ic->max_analyze_duration;
int64_t max_stream_analyze_duration;
int64_t max_subtitle_analyze_duration;
int64_t probesize = ic->probesize;
int eof_reached = 0;
int *missing_streams = av_opt_ptr(ic->iformat->priv_class, ic->priv_data, "missing_streams");
flush_codecs = probesize > 0;
av_opt_set_int(ic, "skip_clear", 1, AV_OPT_SEARCH_CHILDREN);
max_stream_analyze_duration = max_analyze_duration;
max_subtitle_analyze_duration = max_analyze_duration;
if (!max_analyze_duration) {
max_stream_analyze_duration =
max_analyze_duration = 5*AV_TIME_BASE;
max_subtitle_analyze_duration = 30*AV_TIME_BASE;
if (!strcmp(ic->iformat->name, "flv"))
max_stream_analyze_duration = 90*AV_TIME_BASE;
if (!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts"))
max_stream_analyze_duration = 7*AV_TIME_BASE;
}
if (ic->pb) {
FFIOContext *const ctx = ffiocontext(ic->pb);
av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d nb_streams:%d\n",
avio_tell(ic->pb), ctx->bytes_read, ctx->seek_count, ic->nb_streams);
}
for (unsigned i = 0; i < ic->nb_streams; i++) {
const AVCodec *codec;
AVDictionary *thread_opt = NULL;
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
AVCodecContext *const avctx = sti->avctx;
/* check if the caller has overridden the codec id */
// only for the split stuff
if (!sti->parser && !(ic->flags & AVFMT_FLAG_NOPARSE) && sti->request_probe <= 0) {
sti->parser = av_parser_init(st->codecpar->codec_id);
if (sti->parser) {
if (sti->need_parsing == AVSTREAM_PARSE_HEADERS) {
sti->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
} else if (sti->need_parsing == AVSTREAM_PARSE_FULL_RAW) {
sti->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
}
} else if (sti->need_parsing) {
av_log(ic, AV_LOG_VERBOSE, "parser not found for codec "
"%s, packets or times may be invalid.\n",
avcodec_get_name(st->codecpar->codec_id));
}
}
ret = avcodec_parameters_to_context(avctx, st->codecpar);
if (ret < 0)
goto find_stream_info_err;
if (sti->request_probe <= 0)
sti->avctx_inited = 1;
codec = find_probe_decoder(ic, st, st->codecpar->codec_id);
/* Force thread count to 1 since the H.264 decoder will not extract
* SPS and PPS to extradata during multi-threaded decoding. */
av_dict_set(options ? &options[i] : &thread_opt, "threads", "1", 0);
/* Force lowres to 0. The decoder might reduce the video size by the
* lowres factor, and we don't want that propagated to the stream's
* codecpar */
av_dict_set(options ? &options[i] : &thread_opt, "lowres", "0", 0);
if (ic->codec_whitelist)
av_dict_set(options ? &options[i] : &thread_opt, "codec_whitelist", ic->codec_whitelist, 0);
// Try to just open decoders, in case this is enough to get parameters.
// Also ensure that subtitle_header is properly set.
if (!has_codec_parameters(st, NULL) && sti->request_probe <= 0 ||
st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (codec && !avctx->codec)
if (avcodec_open2(avctx, codec, options ? &options[i] : &thread_opt) < 0)
av_log(ic, AV_LOG_WARNING,
"Failed to open codec in %s\n", __func__);
}
if (!options)
av_dict_free(&thread_opt);
}
read_size = 0;
for (;;) {
const AVPacket *pkt;
AVStream *st;
FFStream *sti;
AVCodecContext *avctx;
int analyzed_all_streams;
unsigned i;
if (ff_check_interrupt(&ic->interrupt_callback)) {
ret = AVERROR_EXIT;
av_log(ic, AV_LOG_DEBUG, "interrupted\n");
break;
}
/* check if one codec still needs to be handled */
for (i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
int fps_analyze_framecount = 20;
int count;
if (!has_codec_parameters(st, NULL))
break;
/* If the timebase is coarse (like the usual millisecond precision
* of mkv), we need to analyze more frames to reliably arrive at
* the correct fps. */
if (av_q2d(st->time_base) > 0.0005)
fps_analyze_framecount *= 2;
if (!tb_unreliable(ic, st))
fps_analyze_framecount = 0;
if (ic->fps_probe_size >= 0)
fps_analyze_framecount = ic->fps_probe_size;
if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
fps_analyze_framecount = 0;
/* variable fps and no guess at the real fps */
count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ?
sti->info->codec_info_duration_fields/2 :
sti->info->duration_count;
if (!(st->r_frame_rate.num && st->avg_frame_rate.num) &&
st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
if (count < fps_analyze_framecount)
break;
}
// Look at the first 3 frames if there is evidence of frame delay
// but the decoder delay is not set.
if (sti->info->frame_delay_evidence && count < 2 && sti->avctx->has_b_frames == 0)
break;
if (!sti->avctx->extradata &&
(!sti->extract_extradata.inited || sti->extract_extradata.bsf) &&
extract_extradata_check(st))
break;
if (sti->first_dts == AV_NOPTS_VALUE &&
(!(ic->iformat->flags & AVFMT_NOTIMESTAMPS) || sti->need_parsing == AVSTREAM_PARSE_FULL_RAW) &&
sti->codec_info_nb_frames < ((st->disposition & AV_DISPOSITION_ATTACHED_PIC) ? 1 : ic->max_ts_probe) &&
(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO))
break;
}
analyzed_all_streams = 0;
if (!missing_streams || !*missing_streams)
if (i == ic->nb_streams) {
analyzed_all_streams = 1;
/* NOTE: If the format has no header, then we need to read some
* packets to get most of the streams, so we cannot stop here. */
if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) {
/* If we found the info for all the codecs, we can stop. */
ret = count;
av_log(ic, AV_LOG_DEBUG, "All info found\n");
flush_codecs = 0;
break;
}
}
/* We did not get all the codec info, but we read too much data. */
if (read_size >= probesize) {
ret = count;
av_log(ic, AV_LOG_DEBUG,
"Probe buffer size limit of %"PRId64" bytes reached\n", probesize);
for (unsigned i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
if (!st->r_frame_rate.num &&
sti->info->duration_count <= 1 &&
st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
strcmp(ic->iformat->name, "image2"))
av_log(ic, AV_LOG_WARNING,
"Stream #%d: not enough frames to estimate rate; "
"consider increasing probesize\n", i);
}
break;
}
/* NOTE: A new stream can be added there if no header in file
* (AVFMTCTX_NOHEADER). */
ret = read_frame_internal(ic, pkt1);
if (ret == AVERROR(EAGAIN))
continue;
if (ret < 0) {
/* EOF or error*/
eof_reached = 1;
break;
}
if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) {
ret = avpriv_packet_list_put(&si->packet_buffer,
pkt1, NULL, 0);
if (ret < 0)
goto unref_then_goto_end;
pkt = &si->packet_buffer.tail->pkt;
} else {
pkt = pkt1;
}
st = ic->streams[pkt->stream_index];
sti = ffstream(st);
if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
read_size += pkt->size;
avctx = sti->avctx;
if (!sti->avctx_inited) {
ret = avcodec_parameters_to_context(avctx, st->codecpar);
if (ret < 0)
goto unref_then_goto_end;
sti->avctx_inited = 1;
}
if (pkt->dts != AV_NOPTS_VALUE && sti->codec_info_nb_frames > 1) {
/* check for non-increasing dts */
if (sti->info->fps_last_dts != AV_NOPTS_VALUE &&
sti->info->fps_last_dts >= pkt->dts) {
av_log(ic, AV_LOG_DEBUG,
"Non-increasing DTS in stream %d: packet %d with DTS "
"%"PRId64", packet %d with DTS %"PRId64"\n",
st->index, sti->info->fps_last_dts_idx,
sti->info->fps_last_dts, sti->codec_info_nb_frames,
pkt->dts);
sti->info->fps_first_dts =
sti->info->fps_last_dts = AV_NOPTS_VALUE;
}
/* Check for a discontinuity in dts. If the difference in dts
* is more than 1000 times the average packet duration in the
* sequence, we treat it as a discontinuity. */
if (sti->info->fps_last_dts != AV_NOPTS_VALUE &&
sti->info->fps_last_dts_idx > sti->info->fps_first_dts_idx &&
(pkt->dts - (uint64_t)sti->info->fps_last_dts) / 1000 >
(sti->info->fps_last_dts - (uint64_t)sti->info->fps_first_dts) /
(sti->info->fps_last_dts_idx - sti->info->fps_first_dts_idx)) {
av_log(ic, AV_LOG_WARNING,
"DTS discontinuity in stream %d: packet %d with DTS "
"%"PRId64", packet %d with DTS %"PRId64"\n",
st->index, sti->info->fps_last_dts_idx,
sti->info->fps_last_dts, sti->codec_info_nb_frames,
pkt->dts);
sti->info->fps_first_dts =
sti->info->fps_last_dts = AV_NOPTS_VALUE;
}
/* update stored dts values */
if (sti->info->fps_first_dts == AV_NOPTS_VALUE) {
sti->info->fps_first_dts = pkt->dts;
sti->info->fps_first_dts_idx = sti->codec_info_nb_frames;
}
sti->info->fps_last_dts = pkt->dts;
sti->info->fps_last_dts_idx = sti->codec_info_nb_frames;
}
if (sti->codec_info_nb_frames > 1) {
int64_t t = 0;
int64_t limit;
if (st->time_base.den > 0)
t = av_rescale_q(sti->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q);
if (st->avg_frame_rate.num > 0)
t = FFMAX(t, av_rescale_q(sti->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q));
if ( t == 0
&& sti->codec_info_nb_frames > 30
&& sti->info->fps_first_dts != AV_NOPTS_VALUE
&& sti->info->fps_last_dts != AV_NOPTS_VALUE) {
int64_t dur = av_sat_sub64(sti->info->fps_last_dts, sti->info->fps_first_dts);
t = FFMAX(t, av_rescale_q(dur, st->time_base, AV_TIME_BASE_Q));
}
if (analyzed_all_streams) limit = max_analyze_duration;
else if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) limit = max_subtitle_analyze_duration;
else limit = max_stream_analyze_duration;
if (t >= limit) {
av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds st:%d\n",
limit,
t, pkt->stream_index);
if (ic->flags & AVFMT_FLAG_NOBUFFER)
av_packet_unref(pkt1);
break;
}
if (pkt->duration > 0) {
const int fields = sti->codec_desc && (sti->codec_desc->props & AV_CODEC_PROP_FIELDS);
if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE && pkt->pts != AV_NOPTS_VALUE && st->start_time != AV_NOPTS_VALUE && pkt->pts >= st->start_time
&& (uint64_t)pkt->pts - st->start_time < INT64_MAX
) {
sti->info->codec_info_duration = FFMIN(pkt->pts - st->start_time, sti->info->codec_info_duration + pkt->duration);
} else
sti->info->codec_info_duration += pkt->duration;
sti->info->codec_info_duration_fields += sti->parser && sti->need_parsing && fields
? sti->parser->repeat_pict + 1 : 2;
}
}
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
#if FF_API_R_FRAME_RATE
ff_rfps_add_frame(ic, st, pkt->dts);
#endif
if (pkt->dts != pkt->pts && pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE)
sti->info->frame_delay_evidence = 1;
}
if (!sti->avctx->extradata) {
ret = extract_extradata(si, st, pkt);
if (ret < 0)
goto unref_then_goto_end;
}
/* If still no information, we try to open the codec and to
* decompress the frame. We try to avoid that in most cases as
* it takes longer and uses more memory. For MPEG-4, we need to
* decompress for QuickTime.
*
* If AV_CODEC_CAP_CHANNEL_CONF is set this will force decoding of at
* least one frame of codec data, this makes sure the codec initializes
* the channel configuration and does not only trust the values from
* the container. */
try_decode_frame(ic, st, pkt,
(options && i < orig_nb_streams) ? &options[i] : NULL);
if (ic->flags & AVFMT_FLAG_NOBUFFER)
av_packet_unref(pkt1);
sti->codec_info_nb_frames++;
count++;
}
if (eof_reached) {
for (unsigned stream_index = 0; stream_index < ic->nb_streams; stream_index++) {
AVStream *const st = ic->streams[stream_index];
AVCodecContext *const avctx = ffstream(st)->avctx;
if (!has_codec_parameters(st, NULL)) {
const AVCodec *codec = find_probe_decoder(ic, st, st->codecpar->codec_id);
if (codec && !avctx->codec) {
AVDictionary *opts = NULL;
if (ic->codec_whitelist)
av_dict_set(&opts, "codec_whitelist", ic->codec_whitelist, 0);
if (avcodec_open2(avctx, codec, (options && stream_index < orig_nb_streams) ? &options[stream_index] : &opts) < 0)
av_log(ic, AV_LOG_WARNING,
"Failed to open codec in %s\n", __func__);
av_dict_free(&opts);
}
}
// EOF already reached while reading the stream above.
// So continue with reoordering DTS with whatever delay we have.
if (si->packet_buffer.head && !has_decode_delay_been_guessed(st)) {
update_dts_from_pts(ic, stream_index, si->packet_buffer.head);
}
}
}
if (flush_codecs) {
AVPacket *empty_pkt = si->pkt;
int err = 0;
av_packet_unref(empty_pkt);
for (unsigned i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
/* flush the decoders */
if (sti->info->found_decoder == 1) {
err = try_decode_frame(ic, st, empty_pkt,
(options && i < orig_nb_streams)
? &options[i] : NULL);
if (err < 0) {
av_log(ic, AV_LOG_INFO,
"decoding for stream %d failed\n", st->index);
}
}
}
}
ff_rfps_calculate(ic);
for (unsigned i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
AVCodecContext *const avctx = sti->avctx;
if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
if (avctx->codec_id == AV_CODEC_ID_RAWVIDEO && !avctx->codec_tag && !avctx->bits_per_coded_sample) {
uint32_t tag= avcodec_pix_fmt_to_codec_tag(avctx->pix_fmt);
if (avpriv_pix_fmt_find(PIX_FMT_LIST_RAW, tag) == avctx->pix_fmt)
avctx->codec_tag= tag;
}
/* estimate average framerate if not set by demuxer */
if (sti->info->codec_info_duration_fields &&
!st->avg_frame_rate.num &&
sti->info->codec_info_duration) {
int best_fps = 0;
double best_error = 0.01;
AVRational codec_frame_rate = avctx->framerate;
if (sti->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2||
sti->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den ||
sti->info->codec_info_duration < 0)
continue;
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
sti->info->codec_info_duration_fields * (int64_t) st->time_base.den,
sti->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000);
/* Round guessed framerate to a "standard" framerate if it's
* within 1% of the original estimate. */
for (int j = 0; j < MAX_STD_TIMEBASES; j++) {
AVRational std_fps = { get_std_framerate(j), 12 * 1001 };
double error = fabs(av_q2d(st->avg_frame_rate) /
av_q2d(std_fps) - 1);
if (error < best_error) {
best_error = error;
best_fps = std_fps.num;
}
if (si->prefer_codec_framerate && codec_frame_rate.num > 0 && codec_frame_rate.den > 0) {
error = fabs(av_q2d(codec_frame_rate) /
av_q2d(std_fps) - 1);
if (error < best_error) {
best_error = error;
best_fps = std_fps.num;
}
}
}
if (best_fps)
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
best_fps, 12 * 1001, INT_MAX);
}
if (!st->r_frame_rate.num) {
const AVCodecDescriptor *desc = sti->codec_desc;
AVRational mul = (AVRational){ desc && (desc->props & AV_CODEC_PROP_FIELDS) ? 2 : 1, 1 };
AVRational fr = av_mul_q(avctx->framerate, mul);
if (fr.num && fr.den && av_cmp_q(st->time_base, av_inv_q(fr)) <= 0) {
st->r_frame_rate = fr;
} else {
st->r_frame_rate.num = st->time_base.den;
st->r_frame_rate.den = st->time_base.num;
}
}
st->codecpar->framerate = avctx->framerate;
if (sti->display_aspect_ratio.num && sti->display_aspect_ratio.den) {
AVRational hw_ratio = { avctx->height, avctx->width };
st->sample_aspect_ratio = av_mul_q(sti->display_aspect_ratio,
hw_ratio);
}
} else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
if (!avctx->bits_per_coded_sample)
avctx->bits_per_coded_sample =
av_get_bits_per_sample(avctx->codec_id);
// set stream disposition based on audio service type
switch (avctx->audio_service_type) {
case AV_AUDIO_SERVICE_TYPE_EFFECTS:
st->disposition = AV_DISPOSITION_CLEAN_EFFECTS;
break;
case AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED:
st->disposition = AV_DISPOSITION_VISUAL_IMPAIRED;
break;
case AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED:
st->disposition = AV_DISPOSITION_HEARING_IMPAIRED;
break;
case AV_AUDIO_SERVICE_TYPE_COMMENTARY:
st->disposition = AV_DISPOSITION_COMMENT;
break;
case AV_AUDIO_SERVICE_TYPE_KARAOKE:
st->disposition = AV_DISPOSITION_KARAOKE;
break;
}
}
}
if (probesize)
estimate_timings(ic, old_offset);
av_opt_set_int(ic, "skip_clear", 0, AV_OPT_SEARCH_CHILDREN);
if (ret >= 0 && ic->nb_streams)
/* We could not have all the codec parameters before EOF. */
ret = -1;
for (unsigned i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
const char *errmsg;
/* if no packet was ever seen, update context now for has_codec_parameters */
if (!sti->avctx_inited) {
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
st->codecpar->format == AV_SAMPLE_FMT_NONE)
st->codecpar->format = sti->avctx->sample_fmt;
ret = avcodec_parameters_to_context(sti->avctx, st->codecpar);
if (ret < 0)
goto find_stream_info_err;
}
if (!has_codec_parameters(st, &errmsg)) {
char buf[256];
avcodec_string(buf, sizeof(buf), sti->avctx, 0);
av_log(ic, AV_LOG_WARNING,
"Could not find codec parameters for stream %d (%s): %s\n"
"Consider increasing the value for the 'analyzeduration' (%"PRId64") and 'probesize' (%"PRId64") options\n",
i, buf, errmsg, ic->max_analyze_duration, ic->probesize);
} else {
ret = 0;
}
}
ret = compute_chapters_end(ic);
if (ret < 0)
goto find_stream_info_err;
/* update the stream parameters from the internal codec contexts */
for (unsigned i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
if (sti->avctx_inited) {
ret = avcodec_parameters_from_context(st->codecpar, sti->avctx);
if (ret < 0)
goto find_stream_info_err;
if (sti->avctx->rc_buffer_size > 0 || sti->avctx->rc_max_rate > 0 ||
sti->avctx->rc_min_rate) {
size_t cpb_size;
AVCPBProperties *props = av_cpb_properties_alloc(&cpb_size);
if (props) {
if (sti->avctx->rc_buffer_size > 0)
props->buffer_size = sti->avctx->rc_buffer_size;
if (sti->avctx->rc_min_rate > 0)
props->min_bitrate = sti->avctx->rc_min_rate;
if (sti->avctx->rc_max_rate > 0)
props->max_bitrate = sti->avctx->rc_max_rate;
if (!av_packet_side_data_add(&st->codecpar->coded_side_data,
&st->codecpar->nb_coded_side_data,
AV_PKT_DATA_CPB_PROPERTIES,
(uint8_t *)props, cpb_size, 0))
av_free(props);
}
}
}
sti->avctx_inited = 0;
#if FF_API_AVSTREAM_SIDE_DATA
FF_DISABLE_DEPRECATION_WARNINGS
if (st->codecpar->nb_coded_side_data > 0) {
av_assert0(!st->side_data && !st->nb_side_data);
st->side_data = av_calloc(st->codecpar->nb_coded_side_data, sizeof(*st->side_data));
if (!st->side_data) {
ret = AVERROR(ENOMEM);
goto find_stream_info_err;
}
for (int j = 0; j < st->codecpar->nb_coded_side_data; j++) {
uint8_t *data = av_memdup(st->codecpar->coded_side_data[j].data,
st->codecpar->coded_side_data[j].size);
if (!data) {
ret = AVERROR(ENOMEM);
goto find_stream_info_err;
}
st->side_data[j].type = st->codecpar->coded_side_data[j].type;
st->side_data[j].size = st->codecpar->coded_side_data[j].size;
st->side_data[j].data = data;
st->nb_side_data++;
}
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif
}
find_stream_info_err:
for (unsigned i = 0; i < ic->nb_streams; i++) {
AVStream *const st = ic->streams[i];
FFStream *const sti = ffstream(st);
if (sti->info) {
av_freep(&sti->info->duration_error);
av_freep(&sti->info);
}
avcodec_close(sti->avctx);
// FIXME: avcodec_close() frees AVOption settable fields which includes ch_layout,
// so we need to restore it.
av_channel_layout_copy(&sti->avctx->ch_layout, &st->codecpar->ch_layout);
av_bsf_free(&sti->extract_extradata.bsf);
}
if (ic->pb) {
FFIOContext *const ctx = ffiocontext(ic->pb);
av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n",
avio_tell(ic->pb), ctx->bytes_read, ctx->seek_count, count);
}
return ret;
unref_then_goto_end:
av_packet_unref(pkt1);
goto find_stream_info_err;
}
代码调用流程图:
代码详细分析:
在进行探测前下面这部分代码用来设置探测的时长,可以看到部分时长和格式强相关的,应该和文件本身关系比较大。
cpp
max_stream_analyze_duration = max_analyze_duration;
max_subtitle_analyze_duration = max_analyze_duration;
if (!max_analyze_duration) {
max_stream_analyze_duration =
max_analyze_duration = 5*AV_TIME_BASE;
max_subtitle_analyze_duration = 30*AV_TIME_BASE;
if (!strcmp(ic->iformat->name, "flv"))
max_stream_analyze_duration = 90*AV_TIME_BASE;
if (!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts"))
max_stream_analyze_duration = 7*AV_TIME_BASE;
}
然后就是循环遍历打开每个流的解码器,为后续解码做准备,这部分就是调用avcodec_find_decoder和avcodec_open2查找解码器和打开解码器,具体实现等到讲解码时再说。
之后便是不断循环检测,循环内部会不断判断当前是否已经成功获取完整的流信息,成功或者超出探测时长上限的话就结束;否则就会从读取AVPacket和解码帧AVFrame,读取AVPacket和解码AVFrame分别是调用ff_read_packet和avcodec_send_packet,avcodec_receive_frame进行码流的读取和解码。
estimate_timings用于估算当前媒体文件的时长,根据不同的格式会采取不同的方式:
1. mpeg和mpegts会采用pts的方式估算,即调用estimate_timings_from_pts估算。
2. 如果非情况1且流本身已经探测到一部分时长信息,则调用fill_all_stream_timings根据已有的时长相关信息进行统一。
3. 其他情况调用estimate_timings_from_bit_rate,利用文件码流大小和码率估算。
timate_timings_from_pts核心就是累加AVPacket的时长,如下:
cpp
do {
is_end = found_duration;
offset = filesize - (DURATION_MAX_READ_SIZE << retry);
if (offset < 0)
offset = 0;
avio_seek(ic->pb, offset, SEEK_SET);
read_size = 0;
for (;;) {
AVStream *st;
FFStream *sti;
if (read_size >= DURATION_MAX_READ_SIZE << (FFMAX(retry - 1, 0)))
break;
do {
ret = ff_read_packet(ic, pkt);
} while (ret == AVERROR(EAGAIN));
if (ret != 0)
break;
read_size += pkt->size;
st = ic->streams[pkt->stream_index];
sti = ffstream(st);
if (pkt->pts != AV_NOPTS_VALUE &&
(st->start_time != AV_NOPTS_VALUE ||
sti->first_dts != AV_NOPTS_VALUE)) {
if (pkt->duration == 0) {
compute_frame_duration(ic, &num, &den, st, sti->parser, pkt);
if (den && num) {
pkt->duration = av_rescale_rnd(1,
num * (int64_t) st->time_base.den,
den * (int64_t) st->time_base.num,
AV_ROUND_DOWN);
}
}
duration = pkt->pts + pkt->duration;
found_duration = 1;
if (st->start_time != AV_NOPTS_VALUE)
duration -= st->start_time;
else
duration -= sti->first_dts;
if (duration > 0) {
if (st->duration == AV_NOPTS_VALUE || sti->info->last_duration<= 0 ||
(st->duration < duration && FFABS(duration - sti->info->last_duration) < 60LL*st->time_base.den / st->time_base.num))
st->duration = duration;
sti->info->last_duration = duration;
}
}
av_packet_unref(pkt);
}
/* check if all audio/video streams have valid duration */
if (!is_end) {
is_end = 1;
for (unsigned i = 0; i < ic->nb_streams; i++) {
const AVStream *const st = ic->streams[i];
switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
case AVMEDIA_TYPE_AUDIO:
if (st->duration == AV_NOPTS_VALUE)
is_end = 0;
}
}
}
} while (!is_end &&
offset &&
++retry <= DURATION_MAX_RETRY);
4.4、av_read_frame
FFmpeg使用av_read_frame()方法读取音频流、视频流、字幕流,得到AVPacket数据包。FFmpeg官方提供的samples有使用示例,或者在ffplay.c代码中:打开文件/网络流后,while循环调用av_read_frame()读取帧数据,也就是解封装demux过程,直到文件末尾EOF。
av_read_frame()的定义位于libavformat\utils.c,如下所示:
cpp
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
{
FFFormatContext *const si = ffformatcontext(s);
const int genpts = s->flags & AVFMT_FLAG_GENPTS;
int eof = 0;
int ret;
AVStream *st;
if (!genpts) {
ret = si->packet_buffer.head
? avpriv_packet_list_get(&si->packet_buffer, pkt)
: read_frame_internal(s, pkt);
if (ret < 0)
return ret;
goto return_packet;
}
for (;;) {
PacketListEntry *pktl = si->packet_buffer.head;
if (pktl) {
AVPacket *next_pkt = &pktl->pkt;
if (next_pkt->dts != AV_NOPTS_VALUE) {
int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;
// last dts seen for this stream. if any of packets following
// current one had no dts, we will set this to AV_NOPTS_VALUE.
int64_t last_dts = next_pkt->dts;
av_assert2(wrap_bits <= 64);
while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {
if (pktl->pkt.stream_index == next_pkt->stream_index &&
av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2ULL << (wrap_bits - 1)) < 0) {
if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2ULL << (wrap_bits - 1))) {
// not B-frame
next_pkt->pts = pktl->pkt.dts;
}
if (last_dts != AV_NOPTS_VALUE) {
// Once last dts was set to AV_NOPTS_VALUE, we don't change it.
last_dts = pktl->pkt.dts;
}
}
pktl = pktl->next;
}
if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
// Fixing the last reference frame had none pts issue (For MXF etc).
// We only do this when
// 1. eof.
// 2. we are not able to resolve a pts value for current packet.
// 3. the packets for this stream at the end of the files had valid dts.
next_pkt->pts = last_dts + next_pkt->duration;
}
pktl = si->packet_buffer.head;
}
/* read packet from packet buffer, if there is data */
st = s->streams[next_pkt->stream_index];
if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL &&
next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
ret = avpriv_packet_list_get(&si->packet_buffer, pkt);
goto return_packet;
}
}
ret = read_frame_internal(s, pkt);
if (ret < 0) {
if (pktl && ret != AVERROR(EAGAIN)) {
eof = 1;
continue;
} else
return ret;
}
ret = avpriv_packet_list_put(&si->packet_buffer,
pkt, NULL, 0);
if (ret < 0) {
av_packet_unref(pkt);
return ret;
}
}
return_packet:
st = s->streams[pkt->stream_index];
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {
ff_reduce_index(s, st->index);
av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);
}
if (is_relative(pkt->dts))
pkt->dts -= RELATIVE_TS_BASE;
if (is_relative(pkt->pts))
pkt->pts -= RELATIVE_TS_BASE;
return ret;
}
av_read_frame()的调用链如下图所示:
可以从源代码中看出,av_read_frame()调用了read_frame_internal()。
4.4.1、read_frame_internal
read_frame_internal 在ffmpeg中实现了将format格式的packet,最终转换成一帧帧的es流packet,并解析填充了packet的pts,dts等信息,为最终解码提供了重要的数据,read_frame_internal,调用ff_read_packet,每次只读取一个包,然后直到parser完这个包的所有数据,才开始读取下一个包,parser完的数据被保存在parser结构的数据缓冲中,这样即使ff_read_packet读取的下一包和前一包的流不一样,由于parser也不一样,所以实现了read_frame_internal这个函数调用,可以解析出不同流的es流,而read_frame_internal函数除非出错否则必须解析出一帧数据才能返回。
cpp
static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{
FFFormatContext *const si = ffformatcontext(s);
int ret, got_packet = 0;
AVDictionary *metadata = NULL;
while (!got_packet && !si->parse_queue.head) {
AVStream *st;
FFStream *sti;
// 读取下一个数据包
ret = ff_read_packet(s, pkt);
if (ret < 0) {
if (ret == AVERROR(EAGAIN))
return ret;
/* flush the parsers */
for (unsigned i = 0; i < s->nb_streams; i++) {
AVStream *const st = s->streams[i];
FFStream *const sti = ffstream(st);
if (sti->parser && sti->need_parsing)
parse_packet(s, pkt, st->index, 1);
}
/* all remaining packets are now in parse_queue =>
* really terminate parsing */
break;
}
ret = 0;
st = s->streams[pkt->stream_index];
sti = ffstream(st);
st->event_flags |= AVSTREAM_EVENT_FLAG_NEW_PACKETS;
/* update context if required */
if (sti->need_context_update) {
if (avcodec_is_open(sti->avctx)) {
av_log(s, AV_LOG_DEBUG, "Demuxer context update while decoder is open, closing and trying to re-open\n");
avcodec_close(sti->avctx);
sti->info->found_decoder = 0;
}
/* close parser, because it depends on the codec */
if (sti->parser && sti->avctx->codec_id != st->codecpar->codec_id) {
av_parser_close(sti->parser);
sti->parser = NULL;
}
ret = avcodec_parameters_to_context(sti->avctx, st->codecpar);
if (ret < 0) {
av_packet_unref(pkt);
return ret;
}
sti->codec_desc = avcodec_descriptor_get(sti->avctx->codec_id);
sti->need_context_update = 0;
}
if (pkt->pts != AV_NOPTS_VALUE &&
pkt->dts != AV_NOPTS_VALUE &&
pkt->pts < pkt->dts) {
av_log(s, AV_LOG_WARNING,
"Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n",
pkt->stream_index,
av_ts2str(pkt->pts),
av_ts2str(pkt->dts),
pkt->size);
}
if (s->debug & FF_FDEBUG_TS)
av_log(s, AV_LOG_DEBUG,
"ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%"PRId64", flags=%d\n",
pkt->stream_index,
av_ts2str(pkt->pts),
av_ts2str(pkt->dts),
pkt->size, pkt->duration, pkt->flags);
if (sti->need_parsing && !sti->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {
sti->parser = av_parser_init(st->codecpar->codec_id);
if (!sti->parser) {
av_log(s, AV_LOG_VERBOSE, "parser not found for codec "
"%s, packets or times may be invalid.\n",
avcodec_get_name(st->codecpar->codec_id));
/* no parser available: just output the raw packets */
sti->need_parsing = AVSTREAM_PARSE_NONE;
} else if (sti->need_parsing == AVSTREAM_PARSE_HEADERS)
sti->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
else if (sti->need_parsing == AVSTREAM_PARSE_FULL_ONCE)
sti->parser->flags |= PARSER_FLAG_ONCE;
else if (sti->need_parsing == AVSTREAM_PARSE_FULL_RAW)
sti->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
}
if (!sti->need_parsing || !sti->parser) {
/* no parsing needed: we just output the packet as is */
compute_pkt_fields(s, st, NULL, pkt, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
(pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {
ff_reduce_index(s, st->index);
av_add_index_entry(st, pkt->pos, pkt->dts,
0, 0, AVINDEX_KEYFRAME);
}
got_packet = 1;
} else if (st->discard < AVDISCARD_ALL) {
if ((ret = parse_packet(s, pkt, pkt->stream_index, 0)) < 0)
return ret;
st->codecpar->sample_rate = sti->avctx->sample_rate;
st->codecpar->bit_rate = sti->avctx->bit_rate;
#if FF_API_OLD_CHANNEL_LAYOUT
FF_DISABLE_DEPRECATION_WARNINGS
st->codecpar->channels = sti->avctx->ch_layout.nb_channels;
st->codecpar->channel_layout = sti->avctx->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
sti->avctx->ch_layout.u.mask : 0;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
ret = av_channel_layout_copy(&st->codecpar->ch_layout, &sti->avctx->ch_layout);
if (ret < 0)
return ret;
st->codecpar->codec_id = sti->avctx->codec_id;
} else {
/* free packet */
av_packet_unref(pkt);
}
if (pkt->flags & AV_PKT_FLAG_KEY)
sti->skip_to_keyframe = 0;
if (sti->skip_to_keyframe) {
av_packet_unref(pkt);
got_packet = 0;
}
}
if (!got_packet && si->parse_queue.head)
ret = avpriv_packet_list_get(&si->parse_queue, pkt);
if (ret >= 0) {
AVStream *const st = s->streams[pkt->stream_index];
FFStream *const sti = ffstream(st);
int discard_padding = 0;
if (sti->first_discard_sample && pkt->pts != AV_NOPTS_VALUE) {
int64_t pts = pkt->pts - (is_relative(pkt->pts) ? RELATIVE_TS_BASE : 0);
int64_t sample = ts_to_samples(st, pts);
int64_t duration = ts_to_samples(st, pkt->duration);
int64_t end_sample = sample + duration;
if (duration > 0 && end_sample >= sti->first_discard_sample &&
sample < sti->last_discard_sample)
discard_padding = FFMIN(end_sample - sti->first_discard_sample, duration);
}
if (sti->start_skip_samples && (pkt->pts == 0 || pkt->pts == RELATIVE_TS_BASE))
sti->skip_samples = sti->start_skip_samples;
sti->skip_samples = FFMAX(0, sti->skip_samples);
if (sti->skip_samples || discard_padding) {
uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
if (p) {
AV_WL32(p, sti->skip_samples);
AV_WL32(p + 4, discard_padding);
av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %u / discard %u\n",
(unsigned)sti->skip_samples, (unsigned)discard_padding);
}
sti->skip_samples = 0;
}
#if FF_API_AVSTREAM_SIDE_DATA
if (sti->inject_global_side_data) {
for (int i = 0; i < st->codecpar->nb_coded_side_data; i++) {
const AVPacketSideData *const src_sd = &st->codecpar->coded_side_data[i];
uint8_t *dst_data;
if (av_packet_get_side_data(pkt, src_sd->type, NULL))
continue;
dst_data = av_packet_new_side_data(pkt, src_sd->type, src_sd->size);
if (!dst_data) {
av_log(s, AV_LOG_WARNING, "Could not inject global side data\n");
continue;
}
memcpy(dst_data, src_sd->data, src_sd->size);
}
sti->inject_global_side_data = 0;
}
#endif
}
if (!si->metafree) {
int metaret = av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata);
if (metadata) {
s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
av_dict_copy(&s->metadata, metadata, 0);
av_dict_free(&metadata);
av_opt_set_dict_val(s, "metadata", NULL, AV_OPT_SEARCH_CHILDREN);
}
si->metafree = metaret == AVERROR_OPTION_NOT_FOUND;
}
if (s->debug & FF_FDEBUG_TS)
av_log(s, AV_LOG_DEBUG,
"read_frame_internal stream=%d, pts=%s, dts=%s, "
"size=%d, duration=%"PRId64", flags=%d\n",
pkt->stream_index,
av_ts2str(pkt->pts),
av_ts2str(pkt->dts),
pkt->size, pkt->duration, pkt->flags);
/* A demuxer might have returned EOF because of an IO error, let's
* propagate this back to the user. */
if (ret == AVERROR_EOF && s->pb && s->pb->error < 0 && s->pb->error != AVERROR(EAGAIN))
ret = s->pb->error;
return ret;
}
read_frame_internal()代码比较长,这里只简单看一下它前面的部分。它前面部分有2步是十分关键的:
1. 调用了ff_read_packet()从相应的AVInputFormat读取数据。
2. 如果媒体频流需要使用AVCodecParser,则调用parse_packet()解析相应的AVPacket。
下面我们分成分别看一下ff_read_packet()和parse_packet()的源代码。
4.4.2、ff_read_packet
ff_read_packet函数也是会判断缓存是否有数据,若有则从缓存中取出,若没有,则调用demuxer的read_packet来读取数据。ff_read_packet()中最关键的地方就是调用了AVInputFormat的read_packet()方法。AVInputFormat的read_packet()是一个函数指针,指向当前的AVInputFormat的读取数据的函数,比如flv的flv_read_packet,flv_read_packet()的代码比较长,但是逻辑比较简单。它的主要功能就是根据FLV文件格式的规范,逐层解析Tag以及TagData,获取Tag以及TagData中的信息。
ff_read_packet的缓存和av_read_frame函数里的缓存是不一样的,ff_read_packet的缓存为AVFormatInternal::raw_packet_buffer,在av_read_frame函数里缓存则为:
AVFormatInternal::packet_buffer,简单的理解为在codec被识别之前用raw_packet_buffer缓存,codec识别后用packet_buffer。
cpp
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FFFormatContext *const si = ffformatcontext(s);
int err;
#if FF_API_INIT_PACKET
FF_DISABLE_DEPRECATION_WARNINGS
pkt->data = NULL;
pkt->size = 0;
av_init_packet(pkt);
FF_ENABLE_DEPRECATION_WARNINGS
#else
av_packet_unref(pkt);
#endif
/* 这里是不断从队列中取出一个pkt(raw buffer只要有数据)返回给上层和不断的读取数据加入到raw buffer */
for (;;) {
PacketListEntry *pktl = si->raw_packet_buffer.head;
AVStream *st;
FFStream *sti;
const AVPacket *pkt1;
if (pktl) {
/* 得到AVPacket包 */
AVStream *const st = s->streams[pktl->pkt.stream_index];
if (si->raw_packet_buffer_size >= s->probesize)
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
/* -1是probe完成,0是不要probe */
if (ffstream(st)->request_probe <= 0) {
avpriv_packet_list_get(&si->raw_packet_buffer, pkt);
/* 归还队列空间 */
si->raw_packet_buffer_size -= pkt->size;
return 0;
}
}
/* 0表示成功,小于0表示错误,pkt就在这里获取到。*/
err = s->iformat->read_packet(s, pkt);
if (err < 0) {
av_packet_unref(pkt);
/* Some demuxers return FFERROR_REDO when they consume
data and discard it (ignored streams, junk, extradata).
We must re-call the demuxer to get the real packet. */
if (err == FFERROR_REDO)
continue;
if (!pktl || err == AVERROR(EAGAIN))
return err;
for (unsigned i = 0; i < s->nb_streams; i++) {
AVStream *const st = s->streams[i];
FFStream *const sti = ffstream(st);
if (sti->probe_packets || sti->request_probe > 0)
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
av_assert0(sti->request_probe <= 0);
}
continue;
}
err = av_packet_make_refcounted(pkt);
if (err < 0) {
av_packet_unref(pkt);
return err;
}
/* 读取成功,判断是否需要丢弃 */
if (pkt->flags & AV_PKT_FLAG_CORRUPT) {
av_log(s, AV_LOG_WARNING,
"Packet corrupt (stream = %d, dts = %s)",
pkt->stream_index, av_ts2str(pkt->dts));
if (s->flags & AVFMT_FLAG_DISCARD_CORRUPT) {
av_log(s, AV_LOG_WARNING, ", dropping it.\n");
av_packet_unref(pkt);
continue;
}
av_log(s, AV_LOG_WARNING, ".\n");
}
av_assert0(pkt->stream_index < (unsigned)s->nb_streams &&
"Invalid stream index.\n");
/* 得到读取到的这个包所在的stream,以为pkt获取时间戳 */
st = s->streams[pkt->stream_index];
sti = ffstream(st);
if (update_wrap_reference(s, st, pkt->stream_index, pkt) && sti->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
// correct first time stamps to negative values
if (!is_relative(sti->first_dts))
sti->first_dts = wrap_timestamp(st, sti->first_dts);
if (!is_relative(st->start_time))
st->start_time = wrap_timestamp(st, st->start_time);
if (!is_relative(sti->cur_dts))
sti->cur_dts = wrap_timestamp(st, sti->cur_dts);
}
pkt->dts = wrap_timestamp(st, pkt->dts);
pkt->pts = wrap_timestamp(st, pkt->pts);
force_codec_ids(s, st);
/* TODO: audio: time filter; video: frame reordering (pts != dts) */
if (s->use_wallclock_as_timestamps)
pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
if (!pktl && sti->request_probe <= 0)
return 0;
err = avpriv_packet_list_put(&si->raw_packet_buffer,
pkt, NULL, 0);
if (err < 0) {
av_packet_unref(pkt);
return err;
}
pkt1 = &si->raw_packet_buffer.tail->pkt;
si->raw_packet_buffer_size += pkt1->size;
if ((err = probe_codec(s, st, pkt1)) < 0)
return err;
}
}
4.4.3、parse_packet
用于将输入流中的音视频信息按帧封装为packet对象,供进一步处理。需传入输入流上下文和用于装载数据的packet对象
cpp
static int parse_packet(AVFormatContext *s, AVPacket *pkt,
int stream_index, int flush)
{
FFFormatContext *const si = ffformatcontext(s);
AVPacket *out_pkt = si->parse_pkt;
AVStream *st = s->streams[stream_index];
FFStream *const sti = ffstream(st);
const uint8_t *data = pkt->data;
int size = pkt->size;
int ret = 0, got_output = flush;
if (!size && !flush && sti->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) {
// preserve 0-size sync packets
compute_pkt_fields(s, st, sti->parser, pkt, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
}
while (size > 0 || (flush && got_output)) {
int64_t next_pts = pkt->pts;
int64_t next_dts = pkt->dts;
int len;
/* 真正去解析数据包 */
len = av_parser_parse2(sti->parser, sti->avctx,
&out_pkt->data, &out_pkt->size, data, size,
pkt->pts, pkt->dts, pkt->pos);
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
pkt->pos = -1;
/* increment read pointer */
av_assert1(data || !len);
data = len ? data + len : data;
size -= len;
got_output = !!out_pkt->size;
if (!out_pkt->size)
continue;
if (pkt->buf && out_pkt->data == pkt->data) {
/* reference pkt->buf only when out_pkt->data is guaranteed to point
* to data in it and not in the parser's internal buffer. */
/* XXX: Ensure this is the case with all parsers when sti->parser->flags
* is PARSER_FLAG_COMPLETE_FRAMES and check for that instead? */
out_pkt->buf = av_buffer_ref(pkt->buf);
if (!out_pkt->buf) {
ret = AVERROR(ENOMEM);
goto fail;
}
} else {
ret = av_packet_make_refcounted(out_pkt);
if (ret < 0)
goto fail;
}
if (pkt->side_data) {
out_pkt->side_data = pkt->side_data;
out_pkt->side_data_elems = pkt->side_data_elems;
pkt->side_data = NULL;
pkt->side_data_elems = 0;
}
/* set the duration */
out_pkt->duration = (sti->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->duration : 0;
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (sti->avctx->sample_rate > 0) {
out_pkt->duration =
av_rescale_q_rnd(sti->parser->duration,
(AVRational) { 1, sti->avctx->sample_rate },
st->time_base,
AV_ROUND_DOWN);
}
} else if (st->codecpar->codec_id == AV_CODEC_ID_GIF) {
if (st->time_base.num > 0 && st->time_base.den > 0 &&
sti->parser->duration) {
out_pkt->duration = sti->parser->duration;
}
}
out_pkt->stream_index = st->index;
out_pkt->pts = sti->parser->pts;
out_pkt->dts = sti->parser->dts;
out_pkt->pos = sti->parser->pos;
out_pkt->flags |= pkt->flags & (AV_PKT_FLAG_DISCARD | AV_PKT_FLAG_CORRUPT);
if (sti->need_parsing == AVSTREAM_PARSE_FULL_RAW)
out_pkt->pos = sti->parser->frame_offset;
if (sti->parser->key_frame == 1 ||
(sti->parser->key_frame == -1 &&
sti->parser->pict_type == AV_PICTURE_TYPE_I))
out_pkt->flags |= AV_PKT_FLAG_KEY;
if (sti->parser->key_frame == -1 && sti->parser->pict_type ==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY))
out_pkt->flags |= AV_PKT_FLAG_KEY;
compute_pkt_fields(s, st, sti->parser, out_pkt, next_dts, next_pts);
ret = avpriv_packet_list_put(&si->parse_queue,
out_pkt, NULL, 0);
if (ret < 0)
goto fail;
}
/* end of the stream => close and free the parser */
if (flush) {
av_parser_close(sti->parser);
sti->parser = NULL;
}
fail:
if (ret < 0)
av_packet_unref(out_pkt);
av_packet_unref(pkt);
return ret;
}
最终是调用libavcodec/parser.c的av_parser_parse2()方法去解析数据包。
4.5、avformat_seek_file
在做音视频数据分析的时候,经常会遇到这样的需求,每隔5分钟抽取一帧数据进行分析。
在做播放器开发的时候,也会遇到这种情况,就是拖动进度条跳转到某个位置进行播放。
如果直接用 av_read_frame() 不断读数据,读到第 5 分钟的 AVPacket 才开始处理,其他读出来的 AVPacket 丢弃,这样做会带来非常大的磁盘IO。
其实上面两种场景,都可以用同一个函数解决,那就是 avformat_seek_file(),这个函数类似于 Linux 的 lseek() ,设置文件的读取位置。
只不过 avformat_seek_file() 是用于音视频文件的。
cpp
int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
int64_t ts, int64_t max_ts, int flags)
{
if (min_ts > ts || max_ts < ts)
return -1;
if (stream_index < -1 || stream_index >= (int)s->nb_streams)
return AVERROR(EINVAL);
if (s->seek2any > 0)
flags |= AVSEEK_FLAG_ANY;
flags &= ~AVSEEK_FLAG_BACKWARD;
if (s->iformat->read_seek2) {
int ret;
ff_read_frame_flush(s);
if (stream_index == -1 && s->nb_streams == 1) {
AVRational time_base = s->streams[0]->time_base;
ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
min_ts = av_rescale_rnd(min_ts, time_base.den,
time_base.num * (int64_t)AV_TIME_BASE,
AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
max_ts = av_rescale_rnd(max_ts, time_base.den,
time_base.num * (int64_t)AV_TIME_BASE,
AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
stream_index = 0;
}
ret = s->iformat->read_seek2(s, stream_index, min_ts,
ts, max_ts, flags);
if (ret >= 0)
ret = avformat_queue_attached_pictures(s);
return ret;
}
if (s->iformat->read_timestamp) {
// try to seek via read_timestamp()
}
// Fall back on old API if new is not implemented but old is.
// Note the old API has somewhat different semantics.
if (s->iformat->read_seek || 1) {
int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
int ret = av_seek_frame(s, stream_index, ts, flags | dir);
if (ret < 0 && ts != min_ts && max_ts != ts) {
ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
if (ret >= 0)
ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
}
return ret;
}
// try some generic seek like seek_frame_generic() but with new ts semantics
return -1; //unreachable
}
参数解释如下:
1. AVFormatContext *s,已经打开的容器示例。
2. int stream_index,流索引,但是只有在 flags 包含 AVSEEK_FLAG_FRAME 的时候才是 设置某个流的读取位置。其他情况都只是把这个流的 time_base (时间基)作为参考。
3. int64_t min_ts,跳转到的最小的时间,但是这个变量不一定是时间单位,也有可能是字节单位,也可能是帧数单位(第几帧)。
4. int64_t ts,要跳转到的读取位置,单位同上。
5. int64_t max_ts,跳转到的最大的时间,单位同上,通常填 INT64_MAX 即可。
6. int flags,跳转的方式,有 4 个 flags,如下:
1. AVSEEK_FLAG_BYTE,按字节大小进行跳转。
2. AVSEEK_FLAG_FRAME,按帧数大小进行跳转。
3. AVSEEK_FLAG_ANY,可以跳转到非关键帧的读取位置,但是解码会出现马赛克。
4. AVSEEK_FLAG_BACKWARD,往 ts 的后面找关键帧,默认是往 ts 的前面找关键帧。
通过代码可知avformat_seek_file函数最终还是调用av_seek_frame函数来实现跳转操作的。
avformat_seek_file调用流程如下:
4.6、av_seek_frame
cpp
int av_seek_frame(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
int ret;
if (s->iformat->read_seek2 && !s->iformat->read_seek) {
int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
if ((flags & AVSEEK_FLAG_BACKWARD))
max_ts = timestamp;
else
min_ts = timestamp;
return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
flags & ~AVSEEK_FLAG_BACKWARD);
}
ret = seek_frame_internal(s, stream_index, timestamp, flags);
if (ret >= 0)
ret = avformat_queue_attached_pictures(s);
return ret;
}
av_seek_frame函数首先判断是否存在iformat->read_seek2,如果存在就调用对应read_seek2(),如果不存在则调用seek_frame_internal()去执行seek操作:
4.6.1、seek_frame_internal
cpp
static int seek_frame_internal(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
AVStream *st;
int ret;
/* 以字节数方式寻帧 */
if (flags & AVSEEK_FLAG_BYTE) {
if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
return -1;
ff_read_frame_flush(s);
return seek_frame_byte(s, stream_index, timestamp, flags);
}
if (stream_index < 0) {
stream_index = av_find_default_stream_index(s);
if (stream_index < 0)
return -1;
st = s->streams[stream_index];
/* timestamp for default must be expressed in AV_TIME_BASE units */
timestamp = av_rescale(timestamp, st->time_base.den,
AV_TIME_BASE * (int64_t) st->time_base.num);
}
/* first, we try the format specific seek */
if (s->iformat->read_seek) {
ff_read_frame_flush(s);
ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
} else
ret = -1;
if (ret >= 0)
return 0;
if (s->iformat->read_timestamp &&
!(s->iformat->flags & AVFMT_NOBINSEARCH)) {
/* 以二分查找方式寻帧 */
ff_read_frame_flush(s);
return ff_seek_frame_binary(s, stream_index, timestamp, flags);
} else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) {
/* 以通用方式寻帧 */
ff_read_frame_flush(s);
return seek_frame_generic(s, stream_index, timestamp, flags);
} else
return -1;
}
由此可见,该函数按照顺序有4个执行步骤:
1. 以字节数方式寻帧;
2. 以指定方式read_seek寻帧;
3. 以二分查找方式寻帧;
4. 以通用方式寻帧;
4.6.2、seek_frame_byte
我们看看byte方式的seek操作,直接调用avio_seek移动到指定位置:
cpp
static int seek_frame_byte(AVFormatContext *s, int stream_index,
int64_t pos, int flags)
{
FFFormatContext *const si = ffformatcontext(s);
int64_t pos_min, pos_max;
pos_min = si->data_offset;
pos_max = avio_size(s->pb) - 1;
if (pos < pos_min)
pos = pos_min;
else if (pos > pos_max)
pos = pos_max;
avio_seek(s->pb, pos, SEEK_SET);
s->io_repositioned = 1;
return 0;
}
4.7、avformat_close_input
该函数用于关闭一个AVFormatContext,一般情况下是和avformat_open_input()成对使用的。avformat_close_input()的声明位于libavformat\avformat.h,如下所示。
cpp
void avformat_close_input(AVFormatContext **ps)
{
AVFormatContext *s;
AVIOContext *pb;
if (!ps || !*ps)
return;
s = *ps;
pb = s->pb;
if ((s->iformat && strcmp(s->iformat->name, "image2") && s->iformat->flags & AVFMT_NOFILE) ||
(s->flags & AVFMT_FLAG_CUSTOM_IO))
pb = NULL;
if (s->iformat)
if (s->iformat->read_close)
s->iformat->read_close(s);
avformat_free_context(s);
*ps = NULL;
avio_close(pb);
}
函数调用关系图
从源代码中可以看出,avformat_close_input()主要做了以下几步工作:
1. 调用AVInputFormat的read_close()方法关闭输入流。
2. 调用avformat_free_context()释放AVFormatContext。
3. 调用avio_close()关闭并且释放AVIOContext。
AVInputFormat-> read_close()
1. AVInputFormat的read_close()是一个函数指针,指向关闭输入流的函数。
2. 不同的AVInputFormat包含有不同的read_close()方法。
3. 例如,FLV格式对应的AVInputFormat的定义如下。
五、实例
cpp
#include <stdio.h>
#include <libavformat/avformat.h>
int main(int argc, char **argv)
{
// 1. 打开文件
const char *ifilename = "believe.flv";
printf("in_filename = %s\n", ifilename);
// AVFormatContext是描述一个媒体文件或媒体流的构成和基本信息的结构体
AVFormatContext *ifmt_ctx = NULL; // 输入文件的demux
// 打开文件,主要是探测协议类型,如果是网络文件则创建网络链接
int ret = avformat_open_input(&ifmt_ctx, ifilename, NULL, NULL);
if (ret < 0) {
char buf[1024] = {0};
av_strerror(ret, buf, sizeof (buf) - 1);
printf("open %s failed: %s\n", ifilename, buf);
return -1;
}
// 2. 读取码流信息
ret = avformat_find_stream_info(ifmt_ctx, NULL);
if (ret < 0) //如果打开媒体文件失败,打印失败原因
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
printf("avformat_find_stream_info %s failed:%s\n", ifilename, buf);
avformat_close_input(&ifmt_ctx);
return -1;
}
// 3.打印总体信息
printf_s("\n==== av_dump_format in_filename:%s ===\n", ifilename);
av_dump_format(ifmt_ctx, 0, ifilename, 0);
printf_s("\n==== av_dump_format finish =======\n\n");
printf("media name:%s\n", ifmt_ctx->url);
printf("stream number:%d\n", ifmt_ctx->nb_streams); // nb_streams媒体流数量
printf("media average ratio:%lldkbps\n",(int64_t)(ifmt_ctx->bit_rate/1024)); // 媒体文件的码率,单位为bps
// duration: 媒体文件时长,单位微妙
int total_seconds = (ifmt_ctx->duration) / AV_TIME_BASE; // 1000us = 1ms, 1000ms = 1秒
printf("audio duration: %02d:%02d:%02d\n",
total_seconds / 3600, (total_seconds % 3600) / 60, (total_seconds % 60));
printf("\n");
// 4.读取码流信息
// 音频
int audioindex = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (audioindex < 0) {
printf("av_find_best_stream %s eror.", av_get_media_type_string(AVMEDIA_TYPE_AUDIO));
return -1;
}
AVStream *audio_stream = ifmt_ctx->streams[audioindex];
printf("----- Audio info:\n");
printf("index: %d\n", audio_stream->index); // 序列号
printf("samplarate: %d Hz\n", audio_stream->codecpar->sample_rate); // 采样率
printf("sampleformat: %d\n", audio_stream->codecpar->format); // 采样格式 AV_SAMPLE_FMT_FLTP:8
printf("audio codec: %d\n", audio_stream->codecpar->codec_id); // 编码格式 AV_CODEC_ID_MP3:86017 AV_CODEC_ID_AAC:86018
if (audio_stream->duration != AV_NOPTS_VALUE) {
int audio_duration = audio_stream->duration * av_q2d(audio_stream->time_base);
printf("audio duration: %02d:%02d:%02d\n",
audio_duration / 3600, (audio_duration % 3600) / 60, (audio_duration % 60));
}
// 视频
int videoindex = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (videoindex < 0) {
printf("av_find_best_stream %s eror.", av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
return -1;
}
AVStream *video_stream = ifmt_ctx->streams[videoindex];
printf("----- Video info:\n");
printf("index: %d\n", video_stream->index); // 序列号
printf("fps: %lf\n", av_q2d(video_stream->avg_frame_rate)); // 帧率
printf("width: %d, height:%d \n", video_stream->codecpar->width, video_stream->codecpar->height);
printf("video codec: %d\n", video_stream->codecpar->codec_id); // 编码格式 AV_CODEC_ID_H264: 27
if (video_stream->duration != AV_NOPTS_VALUE) {
int video_duration = video_stream->duration * av_q2d(video_stream->time_base);
printf("audio duration: %02d:%02d:%02d\n",
video_duration / 3600, (video_duration % 3600) / 60, (video_duration % 60));
}
// 5.提取码流
AVPacket *pkt = av_packet_alloc();
int pkt_count = 0;
int print_max_count = 10;
printf("\n-----av_read_frame start\n");
while (1)
{
ret = av_read_frame(ifmt_ctx, pkt);
if (ret < 0) {
printf("av_read_frame end\n");
break;
}
if(pkt_count++ < print_max_count)
{
if (pkt->stream_index == audioindex)
{
printf("audio pts: %lld\n", pkt->pts);
printf("audio dts: %lld\n", pkt->dts);
printf("audio size: %d\n", pkt->size);
printf("audio pos: %lld\n", pkt->pos);
printf("audio duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[audioindex]->time_base));
}
else if (pkt->stream_index == videoindex)
{
printf("video pts: %lld\n", pkt->pts);
printf("video dts: %lld\n", pkt->dts);
printf("video size: %d\n", pkt->size);
printf("video pos: %lld\n", pkt->pos);
printf("video duration: %lf\n\n",
pkt->duration * av_q2d(ifmt_ctx->streams[videoindex]->time_base));
}
else
{
printf("unknown stream_index:\n", pkt->stream_index);
}
}
av_packet_unref(pkt);
}
// 6.结束
if(pkt)
av_packet_free(&pkt);
if(ifmt_ctx)
avformat_close_input(&ifmt_ctx);
getchar(); //加上这一句,防止程序打印完信息马上退出
return 0;
}
输出:
cpp
in_filename = believe.flv
==== av_dump_format in_filename:believe.flv ===
Input #0, flv, from 'believe.flv':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
comment : www.ieway.cn
encoder : Lavf58.29.100
Duration: 00:03:42.53, start: 0.000000, bitrate: 286 kb/s
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 1920x1080, 150 kb/s, 14.46 fps, 15 tbr, 1k tbn, 30 tbc
Stream #0:1: Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
==== av_dump_format finish =======
media name:believe.flv
stream number:2
media average ratio:279kbps
audio duration: 00:03:42
----- Audio info:
index: 1
samplarate: 48000 Hz
sampleformat: 8
audio codec: 86018
----- Video info:
index: 0
fps: 14.464286
width: 1920, height:1080
video codec: 27
-----av_read_frame start
audio pts: 0
audio dts: 0
audio size: 341
audio pos: 502
audio duration: 0.021000
video pts: 14
video dts: 14
video size: 66736
video pos: 860
video duration: 0.066000
audio pts: 21
audio dts: 21
audio size: 341
audio pos: 67616
audio duration: 0.021000
audio pts: 43
audio dts: 43
audio size: 342
audio pos: 67974
audio duration: 0.021000
audio pts: 64
audio dts: 64
audio size: 341
audio pos: 68333
audio duration: 0.021000
video pts: 81
video dts: 81
video size: 580
video pos: 68691
video duration: 0.066000
audio pts: 85
audio dts: 85
audio size: 341
audio pos: 69291
audio duration: 0.021000
audio pts: 107
audio dts: 107
audio size: 342
audio pos: 69649
audio duration: 0.021000
audio pts: 128
audio dts: 128
audio size: 341
audio pos: 70008
audio duration: 0.021000
video pts: 147
video dts: 147
video size: 11289
video pos: 70366
video duration: 0.066000
av_read_frame end