Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2120139
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-05-04 11:14:26

1. 调用avformat_find_stream_info的原因
如下是avformat_open_input与avformat_find_stream_info之后调用av_dump_format的不同
  1. Duration: 00:22:17.75, bitrate: N/A
  2.     Stream #0:0(eng): Video: h264 (avc1 / 0x31637661), none, 470x352, 520 kb/s, 15 fps, 23.98 tbr, 24002 tbn (default)
  3. Duration: 00:22:17.75, start: 0.000000, bitrate: 610 kb/s
  4.     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
  1. a.解码器的注册过程
  2. avcodec_register_all
  3.    -->REGISTER_DECODER(H264, h264);
  4. 将解码器都放在first_avcodec至last_avcodec的链表中
  5. b. 媒体文件的解码器
  6.    在mov_read_header中解析出format=avc1,然后查表知avc1对应的code_id=AV_CODEC_ID_H264
  7. c.解码器的匹配
  8.    find_encdec查找链表,并找到id=AV_CODEC_ID_H264的AVCodec,返回H264的AVCodec
3. avformat_find_stream_info
  1. int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
  2. {
  3.     int i, count, ret = 0, j;
  4.     int64_t read_size;
  5.     AVStream *st;
  6.     AVPacket pkt1, *pkt;
  7.     int64_t old_offset = avio_tell(ic->pb);
  8.     // new streams might appear, no options for those
  9.     int orig_nb_streams = ic->nb_streams;
  10.     int flush_codecs;
  11.     int64_t max_analyze_duration = ic->max_analyze_duration;
  12.     int64_t max_stream_analyze_duration;
  13.     int64_t max_subtitle_analyze_duration;
  14.     int64_t probesize = ic->probesize;

  15.     flush_codecs = probesize > 0;
  16.     av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN);

  17.     max_stream_analyze_duration = max_analyze_duration;
  18.     max_subtitle_analyze_duration = max_analyze_duration;
  19.     if (!max_analyze_duration) {
  20.         max_stream_analyze_duration max_analyze_duration = 5*AV_TIME_BASE;   //设初值
  21.         max_subtitle_analyze_duration = 30*AV_TIME_BASE;                       //设初值
  22.         if (!strcmp(ic->iformat->name, "flv"))
  23.             max_stream_analyze_duration = 90*AV_TIME_BASE;
  24.     }


  25.     for (i = 0; i < ic->nb_streams; i++) {
  26.         const AVCodec *codec;
  27.         AVDictionary *thread_opt = NULL;
  28.         st = ic->streams[i];

  29.         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
  30.             st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
  31.             if (!st->codec->time_base.num)
  32.                 st->codec->time_base = st->time_base;                //这儿把codec的time_base设为mp4的box中读到的time_base=0x5dc2
  33.         }
  34.         // only for the split stuff
  35.         if (!st->parser && !(ic->flags & AVFMT_FLAG_NOPARSE) && st->request_probe <= 0) {
  36.             st->parser = av_parser_init(st->codec->codec_id);
  37.             if (st->parser) {
  38.                 if (st->need_parsing == AVSTREAM_PARSE_HEADERS) {
  39.                     st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
  40.                 } else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) {
  41.                     st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
  42.                 }
  43.             } else if (st->need_parsing) {
  44.                 av_log(ic, AV_LOG_VERBOSE, "parser not found for codec "
  45.                        "%s, packets or times may be invalid.\n",
  46.                        avcodec_get_name(st->codec->codec_id));
  47.             }
  48.         }
  49.         //mov_read_header中解析出format=avc1,然后查表知avc1对应的code_id=AV_CODEC_ID_H264返回H264的AVCodec
  50.         codec = find_decoder(ic, st, st->codec->codec_id);
  51.         av_dict_set(options ? &options[i] : &thread_opt, "threads", "1", 0);

  52.         //打开解码器
  53.         if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) {
  54.             if (codec && !st->codec->codec)
  55.             {
  56.                 avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt);
  57.             }
  58.         }
  59.     }

  60.     for (i = 0; i < ic->nb_streams; i++) {
  61. #if FF_API_R_FRAME_RATE
  62.         ic->streams[i]->info->last_dts = AV_NOPTS_VALUE;
  63. #endif
  64.         ic->streams[i]->info->fps_first_dts = AV_NOPTS_VALUE;
  65.         ic->streams[i]->info->fps_last_dts = AV_NOPTS_VALUE;
  66.     }

  67.     count = 0;
  68.     read_size = 0;
  69.     for (;;) {
  70.         int analyzed_all_streams;        
  71.         analyzed_all_streams = 0;
  72.         if (i == ic->nb_streams) {
  73.             analyzed_all_streams = 1;
  74.             if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) {    //这儿是死循环的结束条件:如果所有的streams都分析好了,就结束
  75.                 ret = count;
  76.                 flush_codecs = 0;
  77.                 break;
  78.             }
  79.         }
  80.         if (read_size >= probesize) {           //这儿判断读到的数据read_size是否超过了预设值probeszie,要跳出不再读了
  81.             ret = count;            
  82.             break;
  83.         }

  84.         ret = read_frame_internal(ic, &pkt1);    //从媒体文件中读取一帧,这儿是mp4格式就是读取一个sample

  85.         pkt = &pkt1;

  86.         if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) {   //把这一帧加入到队列中
  87.             ret = add_to_pktbuf(&ic->internal->packet_buffer, pkt, &ic->internal->packet_buffer_end, 0);
  88.         }

  89.         st = ic->streams[pkt->stream_index];
  90.         if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
  91.             read_size += pkt->size;                //read_size是己读到的数据size

  92.         if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {
  93.             if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
  94.                 st->info->fps_last_dts >= pkt->dts) {                
  95.                 st->info->fps_first_dts st->info->fps_last_dts = AV_NOPTS_VALUE;
  96.             }

  97.             if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
  98.                 st->info->fps_last_dts_idx > st->info->fps_first_dts_idx &&
  99.                 (pkt->dts - st->info->fps_last_dts) / 1000 >
  100.                 (st->info->fps_last_dts - st->info->fps_first_dts) /
  101.                 (st->info->fps_last_dts_idx - st->info->fps_first_dts_idx)) {
  102.                 st->info->fps_first_dts st->info->fps_last_dts = AV_NOPTS_VALUE;
  103.             }

  104.             if (st->info->fps_first_dts == AV_NOPTS_VALUE) {
  105.                 st->info->fps_first_dts = pkt->dts;
  106.                 st->info->fps_first_dts_idx = st->codec_info_nb_frames;
  107.             }
  108.             st->info->fps_last_dts = pkt->dts;
  109.             st->info->fps_last_dts_idx = st->codec_info_nb_frames;
  110.         }
  111.         if (st->codec_info_nb_frames>1) {
  112.                     //这儿一直为0,没有超过1,不管它
  113.         }
  114. #if FF_API_R_FRAME_RATE
  115.         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  116.             ff_rfps_add_frame(ic, st, pkt->dts);
  117. #endif
  118.         if (st->parser && st->parser->parser->split && !st->codec->extradata) {
  119.             int i = st->parser->parser->split(st->codec, pkt->data, pkt->size);
  120.             if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) {
  121.                 if (ff_alloc_extradata(st->codec, i))
  122.                     return AVERROR(ENOMEM);
  123.                 memcpy(st->codec->extradata, pkt->datast->codec->extradata_size);
  124.             }
  125.         }

  126.         //video调用avcodec_decode_video2,audio调用avcodec_decode_audio4去解码这一帧
  127.         //有些参数,如vidoe的pix_fmt是需要调用h264_decode_frame才可以获取其pix_fmt的
  128.         try_decode_frame(ic, st, pkt(options && i < orig_nb_streams) ? &options[i] : NULL);

  129.         if (ic->flags & AVFMT_FLAG_NOBUFFER)
  130.             av_packet_unref(pkt);

  131.         st->codec_info_nb_frames++;
  132.         count++;
  133.     }

  134.     if (flush_codecs) {
  135.         ..         //flush_codecs=0
  136.     }

  137.     // close codecs which were opened in try_decode_frame()
  138.     for (i = 0; i < ic->nb_streams; i++) {
  139.         st = ic->streams[i];
  140.         avcodec_close(st->codec);
  141.     }

  142.     ff_rfps_calculate(ic);

  143.     for (i = 0; i < ic->nb_streams; i++) {
  144.         st = ic->streams[i];
  145.         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  146.             if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) {
  147.                 uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
  148.                 if (avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), tag) == st->codec->pix_fmt)
  149.                     st->codec->codec_tag= tag;
  150.             }

  151.             /* estimate average framerate if not set by demuxer */
  152.             if (st->info->codec_info_duration_fields &&
  153.                 !st->avg_frame_rate.num &&
  154.                 st->info->codec_info_duration) {
  155.                 int best_fps = 0;
  156.                 double best_error = 0.01;

  157.                 if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2||
  158.                     st->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den ||
  159.                     st->info->codec_info_duration < 0)
  160.                     continue;
  161.                 av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
  162.                           st->info->codec_info_duration_fields * (int64_t) st->time_base.den,
  163.                           st->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000);

  164.                 for (j = 0; j < MAX_STD_TIMEBASES; j++) {
  165.                     AVRational std_fps = { get_std_framerate(j), 12 * 1001 };
  166.                     double error = fabs(av_q2d(st->avg_frame_rate) /
  167.                                               av_q2d(std_fps) - 1);

  168.                     if (error < best_error) {
  169.                         best_error = error;
  170.                         best_fps = std_fps.num;
  171.                     }
  172.                 }
  173.                 if (best_fps)
  174.                     av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
  175.                               best_fps, 12 * 1001, INT_MAX);
  176.             }

  177.             if (!st->r_frame_rate.num) {
  178.                 if ( st->codec->time_base.den * (int64_t) st->time_base.num
  179.                     <= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t) st->time_base.den) {
  180.                     st->r_frame_rate.num = st->codec->time_base.den;
  181.                     st->r_frame_rate.den = st->codec->time_base.num * st->codec->ticks_per_frame;
  182.                 } else {
  183.                     st->r_frame_rate.num = st->time_base.den;
  184.                     st->r_frame_rate.den = st->time_base.num;
  185.                 }
  186.             }
  187.             if (st->display_aspect_ratio.num && st->display_aspect_ratio.den) {
  188.                 AVRational hw_ratio = { st->codec->height, st->codec->width };
  189.                 st->sample_aspect_ratio = av_mul_q(st->display_aspect_ratio,
  190.                                                    hw_ratio);
  191.             }
  192.         } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
  193.             if (!st->codec->bits_per_coded_sample)
  194.                 st->codec->bits_per_coded_sample =
  195.                     av_get_bits_per_sample(st->codec->codec_id);
  196.             // set stream disposition based on audio service type
  197.             switch (st->codec->audio_service_type) {
  198.             case AV_AUDIO_SERVICE_TYPE_EFFECTS:
  199.                 st->disposition = AV_DISPOSITION_CLEAN_EFFECTS;
  200.                 break;
  201.             case AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED:
  202.                 st->disposition = AV_DISPOSITION_VISUAL_IMPAIRED;
  203.                 break;
  204.             case AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED:
  205.                 st->disposition = AV_DISPOSITION_HEARING_IMPAIRED;
  206.                 break;
  207.             case AV_AUDIO_SERVICE_TYPE_COMMENTARY:
  208.                 st->disposition = AV_DISPOSITION_COMMENT;
  209.                 break;
  210.             case AV_AUDIO_SERVICE_TYPE_KARAOKE:
  211.                 st->disposition = AV_DISPOSITION_KARAOKE;
  212.                 break;
  213.             }
  214.         }
  215.     }

  216.     if (probesize)
  217.         estimate_timings(ic, old_offset);

  218.     if (ret >= 0 && ic->nb_streams)
  219.         ret = -1;
  220.     for (i = 0; i < ic->nb_streams; i++) {
  221.         const char *errmsg;
  222.         st = ic->streams[i];
  223.         if (!has_codec_parameters(st, &errmsg)) {
  224.             char buf[256];
  225.             avcodec_string(buf, sizeof(buf), st->codec, 0);
  226.         } else {
  227.             ret = 0;
  228.         }
  229.     }

  230.     compute_chapters_end(ic);

  231. find_stream_info_err:
  232.     for (i = 0; i < ic->nb_streams; i++) {
  233.         st = ic->streams[i];
  234.         if (ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
  235.             ic->streams[i]->codec->thread_count = 0;
  236.         if (st->info)
  237.             av_freep(&st->info->duration_error);
  238.         av_freep(&ic->streams[i]->info);
  239.     }
  240.     return ret;
  241. }
为了获取媒体中的stream参数,这儿动真格了:
read_frame_internal    -->从媒体文件中读取sample数据
add_to_pktbuf             -->加入buf队列
try_decode_frame       -->解码sample数据
最后又计算了一堆参数。





4.一些参数的获取
4.1 bitrate的计算
计算公式 bitrate=(filesize*8)/duration,单位是b/s
  1. 在函数update_stream_timings中
  2. double bitrate = (double) filesize * 8.0 * AV_TIME_BASE / (double) ic->duration;
  3. 为什么写得这么复杂呢?
  4. 从moov中读出duration=0x146995(单位是time_units)
  5. a.媒体文件在播放过程中用的时间单位,是由timescale计算出来的
  6.    一个time units=1s/timescale=1ms,这儿1个time_unts=1ms
  7. b.通过duration可计算媒体的播放时间 0x146995*1ms=1337749ms=1337.749s,对上了
  8.    filesize=102119991,duration=0x4fbc6e08=1337749000
  9.    bitrate=(filesize*8)/duration
  10.    因为这儿是ms,同时bitrate的单位是kb/s
  11.    (102119991*8)/1000 / (1337749/1000)=102119991*8/1337749=610kb/s
4.2 关于duration
  1. 在函数mov_read_mvhd中有:
  2. c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
  3. 把c->duration=1337749扩大了1000倍
4.3关于vidoe的pix_fmt
  1. 从mp4的box中是无法解析出这个pix_fmt的,需要调用try_decode_frame-->h264_decode_frame
  2. 然后才得知这个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
  1. void av_bprint_channel_layout(struct AVBPrint *bp,
  2.                               int nb_channels, uint64_t channel_layout)
  3. {
  4.     //匹配channel_layout_map的nb_channels与layout,然后返回name
  5.     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
  6.         if (nb_channels == channel_layout_map[i].nb_channels &&  //channels=2
  7.             channel_layout == channel_layout_map[i].layout) {   //channel_layout=3
  8.             av_bprintf(bp, "%s", channel_layout_map[i].name);
  9.             return;
  10.         }
  11. }
  12. 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


阅读(6383) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~