1. 调用
avformat_find_stream_info的原因
如下是avformat_open_input与
avformat_find_stream_info之后调用av_dump_format的不同
-
Duration: 00:22:17.75, bitrate: N/A
-
Stream #0:0(eng): Video: h264 (avc1 / 0x31637661), none, 470x352, 520 kb/s, 15 fps, 23.98 tbr, 24002 tbn (default)
-
Duration: 00:22:17.75, start: 0.000000, bitrate: 610 kb/s
-
Stream #0:0(eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 470x352 [SAR 1:1 DAR 235:176], 520 kb/s, 15 fps, 23.98 tbr, 24002 tbn, 47.96 tbc (default)
发现有很多参数只是调用avformat_open_input是获取不了的,所以这儿需要再调用avformat_find_stream_info
2.
匹配解码器的过程
avformat_find_stream_info
对每一个trak都执行如下
-->find_decoder
::匹配解码器
-->avcodec_find_decoder
-->find_encdec
-
a.解码器的注册过程
-
avcodec_register_all
-
-->REGISTER_DECODER(H264, h264);
-
将解码器都放在first_avcodec至last_avcodec的链表中
-
b. 媒体文件的解码器
-
在mov_read_header中解析出format=avc1,然后查表知avc1对应的code_id=AV_CODEC_ID_H264
-
c.解码器的匹配
-
find_encdec查找链表,并找到id=AV_CODEC_ID_H264的AVCodec,返回H264的AVCodec
3. avformat_find_stream_info
-
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
-
{
-
int i, count, ret = 0, j;
-
int64_t read_size;
-
AVStream *st;
-
AVPacket pkt1, *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;
-
-
flush_codecs = probesize > 0;
-
av_opt_set(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;
-
}
-
-
-
for (i = 0; i < ic->nb_streams; i++) {
-
const AVCodec *codec;
-
AVDictionary *thread_opt = NULL;
-
st = ic->streams[i];
-
-
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
-
st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
-
if (!st->codec->time_base.num)
-
st->codec->time_base = st->time_base; //这儿把codec的time_base设为mp4的box中读到的time_base=0x5dc2
-
}
-
// only for the split stuff
-
if (!st->parser && !(ic->flags & AVFMT_FLAG_NOPARSE) && st->request_probe <= 0) {
-
st->parser = av_parser_init(st->codec->codec_id);
-
if (st->parser) {
-
if (st->need_parsing == AVSTREAM_PARSE_HEADERS) {
-
st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
-
} else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) {
-
st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
-
}
-
} else if (st->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->codec->codec_id));
-
}
-
}
-
//mov_read_header中解析出format=avc1,然后查表知avc1对应的code_id=AV_CODEC_ID_H264返回H264的AVCodec
-
codec = find_decoder(ic, st, st->codec->codec_id);
-
av_dict_set(options ? &options[i] : &thread_opt, "threads", "1", 0);
-
-
//打开解码器
-
if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) {
-
if (codec && !st->codec->codec)
-
{
-
avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt);
-
}
-
}
-
}
-
-
for (i = 0; i < ic->nb_streams; i++) {
-
#if FF_API_R_FRAME_RATE
-
ic->streams[i]->info->last_dts = AV_NOPTS_VALUE;
-
#endif
-
ic->streams[i]->info->fps_first_dts = AV_NOPTS_VALUE;
-
ic->streams[i]->info->fps_last_dts = AV_NOPTS_VALUE;
-
}
-
-
count = 0;
-
read_size = 0;
-
for (;;) {
-
int analyzed_all_streams;
-
analyzed_all_streams = 0;
-
if (i == ic->nb_streams) {
-
analyzed_all_streams = 1;
-
if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) { //这儿是死循环的结束条件:如果所有的streams都分析好了,就结束
-
ret = count;
-
flush_codecs = 0;
-
break;
-
}
-
}
-
if (read_size >= probesize) { //这儿判断读到的数据read_size是否超过了预设值probeszie,要跳出不再读了
-
ret = count;
-
break;
-
}
-
-
ret = read_frame_internal(ic, &pkt1); //从媒体文件中读取一帧,这儿是mp4格式就是读取一个sample
-
-
pkt = &pkt1;
-
-
if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) { //把这一帧加入到队列中
-
ret = add_to_pktbuf(&ic->internal->packet_buffer, pkt, &ic->internal->packet_buffer_end, 0);
-
}
-
-
st = ic->streams[pkt->stream_index];
-
if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
-
read_size += pkt->size; //read_size是己读到的数据size
-
-
if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {
-
if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
-
st->info->fps_last_dts >= pkt->dts) {
-
st->info->fps_first_dts = st->info->fps_last_dts = AV_NOPTS_VALUE;
-
}
-
-
if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
-
st->info->fps_last_dts_idx > st->info->fps_first_dts_idx &&
-
(pkt->dts - st->info->fps_last_dts) / 1000 >
-
(st->info->fps_last_dts - st->info->fps_first_dts) /
-
(st->info->fps_last_dts_idx - st->info->fps_first_dts_idx)) {
-
st->info->fps_first_dts = st->info->fps_last_dts = AV_NOPTS_VALUE;
-
}
-
-
if (st->info->fps_first_dts == AV_NOPTS_VALUE) {
-
st->info->fps_first_dts = pkt->dts;
-
st->info->fps_first_dts_idx = st->codec_info_nb_frames;
-
}
-
st->info->fps_last_dts = pkt->dts;
-
st->info->fps_last_dts_idx = st->codec_info_nb_frames;
-
}
-
if (st->codec_info_nb_frames>1) {
-
//这儿一直为0,没有超过1,不管它
-
}
-
#if FF_API_R_FRAME_RATE
-
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
-
ff_rfps_add_frame(ic, st, pkt->dts);
-
#endif
-
if (st->parser && st->parser->parser->split && !st->codec->extradata) {
-
int i = st->parser->parser->split(st->codec, pkt->data, pkt->size);
-
if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) {
-
if (ff_alloc_extradata(st->codec, i))
-
return AVERROR(ENOMEM);
-
memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size);
-
}
-
}
-
-
//video调用avcodec_decode_video2,audio调用avcodec_decode_audio4去解码这一帧
-
//有些参数,如vidoe的pix_fmt是需要调用h264_decode_frame才可以获取其pix_fmt的
-
try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams) ? &options[i] : NULL);
-
-
if (ic->flags & AVFMT_FLAG_NOBUFFER)
-
av_packet_unref(pkt);
-
-
st->codec_info_nb_frames++;
-
count++;
-
}
-
-
if (flush_codecs) {
-
.. //flush_codecs=0
-
}
-
-
// close codecs which were opened in try_decode_frame()
-
for (i = 0; i < ic->nb_streams; i++) {
-
st = ic->streams[i];
-
avcodec_close(st->codec);
-
}
-
-
ff_rfps_calculate(ic);
-
-
for (i = 0; i < ic->nb_streams; i++) {
-
st = ic->streams[i];
-
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-
if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) {
-
uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
-
if (avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), tag) == st->codec->pix_fmt)
-
st->codec->codec_tag= tag;
-
}
-
-
/* estimate average framerate if not set by demuxer */
-
if (st->info->codec_info_duration_fields &&
-
!st->avg_frame_rate.num &&
-
st->info->codec_info_duration) {
-
int best_fps = 0;
-
double best_error = 0.01;
-
-
if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2||
-
st->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den ||
-
st->info->codec_info_duration < 0)
-
continue;
-
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
-
st->info->codec_info_duration_fields * (int64_t) st->time_base.den,
-
st->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000);
-
-
for (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 (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) {
-
if ( st->codec->time_base.den * (int64_t) st->time_base.num
-
<= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t) st->time_base.den) {
-
st->r_frame_rate.num = st->codec->time_base.den;
-
st->r_frame_rate.den = st->codec->time_base.num * st->codec->ticks_per_frame;
-
} else {
-
st->r_frame_rate.num = st->time_base.den;
-
st->r_frame_rate.den = st->time_base.num;
-
}
-
}
-
if (st->display_aspect_ratio.num && st->display_aspect_ratio.den) {
-
AVRational hw_ratio = { st->codec->height, st->codec->width };
-
st->sample_aspect_ratio = av_mul_q(st->display_aspect_ratio,
-
hw_ratio);
-
}
-
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
-
if (!st->codec->bits_per_coded_sample)
-
st->codec->bits_per_coded_sample =
-
av_get_bits_per_sample(st->codec->codec_id);
-
// set stream disposition based on audio service type
-
switch (st->codec->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);
-
-
if (ret >= 0 && ic->nb_streams)
-
ret = -1;
-
for (i = 0; i < ic->nb_streams; i++) {
-
const char *errmsg;
-
st = ic->streams[i];
-
if (!has_codec_parameters(st, &errmsg)) {
-
char buf[256];
-
avcodec_string(buf, sizeof(buf), st->codec, 0);
-
} else {
-
ret = 0;
-
}
-
}
-
-
compute_chapters_end(ic);
-
-
find_stream_info_err:
-
for (i = 0; i < ic->nb_streams; i++) {
-
st = ic->streams[i];
-
if (ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
-
ic->streams[i]->codec->thread_count = 0;
-
if (st->info)
-
av_freep(&st->info->duration_error);
-
av_freep(&ic->streams[i]->info);
-
}
-
return ret;
-
}
为了获取媒体中的stream参数,这儿动真格了:
read_frame_internal -->从媒体文件中读取sample数据
add_to_pktbuf -->加入buf队列
try_decode_frame -->解码sample数据
最后又计算了一堆参数。
4.一些参数的获取
4.1 bitrate的计算
计算公式 bitrate=(filesize*8)/duration,单位是b/s
-
在函数update_stream_timings中
-
double bitrate = (double) filesize * 8.0 * AV_TIME_BASE / (double) ic->duration;
-
为什么写得这么复杂呢?
-
从moov中读出duration=0x146995(单位是time_units)
-
a.媒体文件在播放过程中用的时间单位,是由timescale计算出来的
-
一个time units=1s/timescale=1ms,这儿1个time_unts=1ms
-
b.通过duration可计算媒体的播放时间 0x146995*1ms=1337749ms=1337.749s,对上了
-
filesize=102119991,duration=0x4fbc6e08=1337749000
-
bitrate=(filesize*8)/duration
-
因为这儿是ms,同时bitrate的单位是kb/s
-
(102119991*8)/1000 / (1337749/1000) 即=102119991*8/1337749=610kb/s
4.2 关于duration
-
在函数mov_read_mvhd中有:
-
c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
-
把c->duration=1337749扩大了1000倍
4.3关于vidoe的pix_fmt
-
从mp4的box中是无法解析出这个pix_fmt的,需要调用try_decode_frame-->h264_decode_frame
-
然后才得知这个pix_fmt=0=yuv420p
4.4关于audio的channels与channel_layout与name=stereo
a. channels的得出很简单
mp4的box-->stsd直接就读到 0002-->audio的channels=0x02 ;;双声道
b.
channel_layout=3得出有点复杂
avformat_find_stream_info
-->aac_decode_init
-->output_configure
-->sniff_channel_order
得出layout=3,也就是说这个layout是解码器给出的,跟解码器相关
c.如何得出name=stereo
av_dump_format
-->dump_stream_format
--> avcodec_string
--> av_get_channel_layout_string
-
void av_bprint_channel_layout(struct AVBPrint *bp,
-
int nb_channels, uint64_t channel_layout)
-
{
-
//匹配channel_layout_map的nb_channels与layout,然后返回name
-
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
-
if (nb_channels == channel_layout_map[i].nb_channels && //channels=2
-
channel_layout == channel_layout_map[i].layout) { //channel_layout=3
-
av_bprintf(bp, "%s", channel_layout_map[i].name);
-
return;
-
}
-
}
-
static const struct {
const char *name;
int nb_channels;
uint64_t layout;
} channel_layout_map[] = {
{ "mono", 1, AV_CH_LAYOUT_MONO },
{ "stereo", 2, AV_CH_LAYOUT_STEREO },
{ "2.1", 3, AV_CH_LAYOUT_2POINT1 },
{ "3.0", 3, AV_CH_LAYOUT_SURROUND },
...
};
#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
#define AV_CH_FRONT_LEFT 0x00000001
#define AV_CH_FRONT_RIGHT 0x00000002
可知AV_CH_LAYOUT_STEREO=0x03
4.6 audio的sample_format的确定
跟上面的
channel_layout=3的确定一样是在aac_decode_init中设置
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; //< float, planar
阅读(6499) | 评论(0) | 转发(0) |