ffmpeg——avformat_new_stream创建流通道

时间:2023-01-08 20:39:12

一:介绍

1.1 AVStream

首先了解下 AVStream : http://ffmpeg.org/doxygen/3.1/structAVStream.html

AVStream 即是流通道。例如我们将 H264 和 AAC 码流存储为MP4文件的时候,就需要在 MP4文件中增加两个流通道,一个存储Video:H264,一个存储Audio:AAC。(假设H264和AAC只包含单个流通道)。

typedef struct AVStream {
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;
#if FF_API_LAVF_AVCTX
/**
* @deprecated use the codecpar struct instead
*/
attribute_deprecated
AVCodecContext *codec;
#endif
void *priv_data;

#if FF_API_LAVF_FRAC
/**
* @deprecated this field is unused
*/
attribute_deprecated
struct AVFrac pts;
#endif

/**
* 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.
*/
int64_t duration;

int64_t nb_frames; ///< number of frames in this stream if known or 0

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

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;

/**
* 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().
*
* @see av_format_inject_global_side_data()
*/
AVPacketSideData *side_data;
/**
* The number of elements in the AVStream.side_data array.
*/
int nb_side_data;

/**
* Flags for the user to detect events happening on the stream. Flags must
* be cleared by the user once the event has been handled.
* A combination of AVSTREAM_EVENT_FLAG_*.
*/
int event_flags;
#define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata.

/*****************************************************************
* All fields below this line are not part of the public API. They
* may not be used outside of libavformat and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/

/**
* Stream information used internally by av_find_stream_info()
*/
#define MAX_STD_TIMEBASES (30*12+30+3+6)
struct {
int64_t last_dts;
int64_t duration_gcd;
int duration_count;
int64_t rfps_duration_sum;
double (*duration_error)[2][MAX_STD_TIMEBASES];
int64_t codec_info_duration;
int64_t codec_info_duration_fields;

/**
* 0 -> decoder has not been searched for yet.
* >0 -> decoder found
* <0 -> decoder with codec_id == -found_decoder has not been found
*/
int found_decoder;

int64_t last_duration;

/**
* Those are used for average framerate estimation.
*/
int64_t fps_first_dts;
int fps_first_dts_idx;
int64_t fps_last_dts;
int fps_last_dts_idx;

} *info;

int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */

// Timestamp generation support:
/**
* Timestamp corresponding to the last dts sync point.
*
* Initialized when AVCodecParserContext.dts_sync_point >= 0 and
* a DTS is received from the underlying container. Otherwise set to
* AV_NOPTS_VALUE by default.
*/
int64_t first_dts;
int64_t cur_dts;
int64_t last_IP_pts;
int last_IP_duration;

/**
* Number of packets to buffer for codec probing
*/
int probe_packets;

/**
* Number of frames that have been demuxed during av_find_stream_info()
*/
int codec_info_nb_frames;

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

/**
* last packet in packet_buffer for this stream when muxing.
*/
struct AVPacketList *last_in_packet_buffer;
AVProbeData probe_data;
#define MAX_REORDER_DELAY 16
int64_t pts_buffer[MAX_REORDER_DELAY+1];

AVIndexEntry *index_entries; /**< Only used if the format does not
support seeking natively. */
int nb_index_entries;
unsigned int index_entries_allocated_size;

/**
* 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.
*
* Code outside avformat should access this field using:
* av_stream_get/set_r_frame_rate(stream)
*/
AVRational r_frame_rate;

/**
* Stream Identifier
* This is the MPEG-TS stream identifier +1
* 0 means unknown
*/
int stream_identifier;

int64_t interleaver_chunk_size;
int64_t interleaver_chunk_duration;

/**
* stream probing state
* -1 -> probing finished
* 0 -> no probing requested
* rest -> perform probing with request_probe being the minimum score to accept.
* NOT PART OF PUBLIC API
*/
int request_probe;
/**
* Indicates that everything up to the next keyframe
* should be discarded.
*/
int skip_to_keyframe;

/**
* Number of samples to skip at the start of the frame decoded from the next packet.
*/
int skip_samples;

/**
* If not 0, the number of samples that should be skipped from the start of
* the stream (the samples are removed from packets with pts==0, which also
* assumes negative timestamps do not happen).
* Intended for use with formats such as mp3 with ad-hoc gapless audio
* support.
*/
int64_t start_skip_samples;

/**
* If not 0, the first audio sample that should be discarded from the stream.
* This is broken by design (needs global sample count), but can't be
* avoided for broken by design formats such as mp3 with ad-hoc gapless
* audio support.
*/
int64_t first_discard_sample;

/**
* The sample after last sample that is intended to be discarded after
* first_discard_sample. Works on frame boundaries only. Used to prevent
* early EOF if the gapless info is broken (considered concatenated mp3s).
*/
int64_t last_discard_sample;

/**
* Number of internally decoded frames, used internally in libavformat, do not access
* its lifetime differs from info which is why it is not in that structure.
*/
int nb_decoded_frames;

/**
* Timestamp offset added to timestamps before muxing
* NOT PART OF PUBLIC API
*/
int64_t mux_ts_offset;

/**
* Internal data to check for wrapping of the time stamp
*/
int64_t pts_wrap_reference;

/**
* Options for behavior, when a wrap is detected.
*
* Defined by AV_PTS_WRAP_ values.
*
* If correction is enabled, there are two possibilities:
* If the first time stamp is near the wrap point, the wrap offset
* will be subtracted, which will create negative time stamps.
* Otherwise the offset will be added.
*/
int pts_wrap_behavior;

/**
* Internal data to prevent doing update_initial_durations() twice
*/
int update_initial_durations_done;

/**
* Internal data to generate dts from pts
*/
int64_t pts_reorder_error[MAX_REORDER_DELAY+1];
uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1];

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

/**
* Internal data to inject global side data
*/
int inject_global_side_data;

/**
* String containing paris of key and values describing recommended encoder configuration.
* Paris are separated by ','.
* Keys are separated from values by '='.
*/
char *recommended_encoder_configuration;

/**
* display aspect ratio (0 if unknown)
* - encoding: unused
* - decoding: Set by libavformat to calculate sample_aspect_ratio internally
*/
AVRational display_aspect_ratio;

struct FFFrac *priv_pts;

/**
* An opaque field for libavformat internal usage.
* Must not be accessed in any way by callers.
*/
AVStreamInternal *internal;

/*
* 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;
} AVStream;

AVStream包含很多参数,用于记录通道信息,其中最重要的是  :

AVCodecParameterscodecpar  :用于记录编码后的流信息,即通道中存储的流的编码信息。

AVRational time_base :AVStream通道的时间基,时间基是个相当重要的概念。(可参考之后的关于ffmpeg时间的文章)

需要注意的是:现在的 ffmpeg 3.1.4版本已经使用AVCodecParameterscodecpar替换了原先的CodecContext* codec !


1.2 avformat_new_stream

avformat_new_stream 在 AVFormatContext 中创建 Stream 通道。

AVFormatContext 

    unsigned int nb_streams;    记录stream通道数目。

    AVStream **streams;    存储stream通道。

AVStream :

    int index;   在AVFormatContext 中所处的通道索引



二:分析

ffmpeg——avformat_new_stream创建流通道

AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
{
AVStream *st;
int i;
AVStream **streams;

//创建AVStream
if (s->nb_streams >= INT_MAX/sizeof(*streams))
return NULL;
streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));
if (!streams)
return NULL;
s->streams = streams;

st = av_mallocz(sizeof(AVStream));
if (!st)
return NULL;
if (!(st->info = av_mallocz(sizeof(*st->info)))) {
av_free(st);
return NULL;
}
st->info->last_dts = AV_NOPTS_VALUE;

//ffmpeg 3.1.4版本codec 已经废除了
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
st->codec = avcodec_alloc_context3(c);
if (!st->codec) {
av_free(st->info);
av_free(st);
return NULL;
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif

//internal 部分为avformat内部使用,主要是备份一些数据,无需管它
st->internal = av_mallocz(sizeof(*st->internal));
if (!st->internal)
goto fail;

//
//通道记录的流的编码参数的默认设置
//注: AVCodecParameters codecpar 替换原先的CodecContext codec
st->codecpar = avcodec_parameters_alloc();
if (!st->codecpar)
goto fail;

st->internal->avctx = avcodec_alloc_context3(NULL);
if (!st->internal->avctx)
goto fail;

if (s->iformat) {
#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS
/* no default bitrate if decoding */
st->codec->bit_rate = 0;
FF_ENABLE_DEPRECATION_WARNINGS
#endif

/* default pts setting is MPEG-like */
avpriv_set_pts_info(st, 33, 1, 90000);
/* we set the current DTS to 0 so that formats without any timestamps
* but durations get some timestamps, formats with some unknown
* timestamps have their first few packets buffered and the
* timestamps corrected before they are returned to the user */
st->cur_dts = RELATIVE_TS_BASE;
} else {
st->cur_dts = AV_NOPTS_VALUE;
}

st->index = s->nb_streams;
st->start_time = AV_NOPTS_VALUE;
st->duration = AV_NOPTS_VALUE;
st->first_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
st->pts_wrap_reference = AV_NOPTS_VALUE;
st->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;

st->last_IP_pts = AV_NOPTS_VALUE;
st->last_dts_for_order_check = AV_NOPTS_VALUE;
for (i = 0; i < MAX_REORDER_DELAY + 1; i++)
st->pts_buffer[i] = AV_NOPTS_VALUE;

st->sample_aspect_ratio = (AVRational) { 0, 1 };

#if FF_API_R_FRAME_RATE
st->info->last_dts = AV_NOPTS_VALUE;
#endif
st->info->fps_first_dts = AV_NOPTS_VALUE;
st->info->fps_last_dts = AV_NOPTS_VALUE;

st->inject_global_side_data = s->internal->inject_global_side_data;

st->internal->need_context_update = 1;

s->streams[s->nb_streams++] = st;
return st;
fail:
free_stream(&st);
return NULL;
}

avformat_new_stream之后便在 AVFormatContext 里增加了 AVStream 通道(相关的index已经被设置了) 之后,我们就可以自行设置 AVStream 的一些参数信息。例如 : codec_id , format ,bit_rate ,width , height ... ...