ffmpeg probe一个文件的过程

ffmpeg在看media文件信息的时候特别方便,通过-i参数指定input文件,就可以得到下面这样的输出,当然通过ffprobe也是一样的,只是ffmpeg用的太习惯了而已。

$ ffmpeg -i ~/h264.mp4

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/hui/h264.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf55.37.102
  Duration: 00:00:18.04, start: 0.000000, bitrate: 390 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720, 389 kb/s, 25 fps, 25 tbr, 1200k tbn, 50 tbc (default)
    Metadata:
      handler_name    : VideoHandler

下面是对这个处理过程的一个简单的分析,首先是调用栈:

av_demuxer_iterate
av_probe_input_format3 format.c     165  0x7ffff70bf3dc 
av_probe_input_format2 format.c     208  0x7ffff70bf5ca 
av_probe_input_buffer2 format.c     280  0x7ffff70bf8b5 
init_input             utils.c      446  0x7ffff722ed5d 
avformat_open_input    utils.c      576  0x7ffff722f26a 
open_input_file        ffmpeg_opt.c 1105 0x555555563c13 
open_files             ffmpeg_opt.c 3280 0x55555556dba3 
ffmpeg_parse_options   ffmpeg_opt.c 3320 0x55555556dd57 
main                   ffmpeg.c     4874 0x55555558d9d8 

从ffmpeg的main函数开始,最后进入av_probe_input_format3中调用av_demuxer_iterate,av_demuxer_iterate遍历所有的demuxer,进行打分,最后返回打分最高的fmt,完成了container format的识别。

const AVInputFormat *av_demuxer_iterate(void **opaque)
{
    static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
    uintptr_t i = (uintptr_t)*opaque;
    const AVInputFormat *f = NULL;

    if (i < size) {
        f = demuxer_list[i];
    } else if (outdev_list) {
        f = indev_list[i - size];
    }

    if (f)
        *opaque = (void*)(i + 1);
    return f;
}

这部分是demuxer_list的列表定义,为了方便阅读,省略掉很多:

static const AVInputFormat * const demuxer_list[] = {
    &ff_aa_demuxer,
    &ff_aac_demuxer,
    &ff_ac3_demuxer,
    &ff_acm_demuxer,
    &ff_act_demuxer,
    &ff_adf_demuxer,
    &ff_adp_demuxer,
    &ff_ads_demuxer,
    &ff_adx_demuxer,
    &ff_aea_demuxer,
    &ff_afc_demuxer,
    &ff_aiff_demuxer,
    &ff_aix_demuxer,
    &ff_amr_demuxer,
    &ff_amrnb_demuxer,
    &ff_amrwb_demuxer,
    &ff_anm_demuxer,
    &ff_apc_demuxer,
    &ff_ape_demuxer,
    &ff_m4v_demuxer,
    &ff_matroska_demuxer,
    &ff_mgsts_demuxer,
    &ff_microdvd_demuxer,
    &ff_mjpeg_demuxer,
    &ff_mjpeg_2000_demuxer,
    &ff_mlp_demuxer,
    &ff_mlv_demuxer,
    &ff_mm_demuxer,
    &ff_mmf_demuxer,
    &ff_mov_demuxer,
    &ff_mp3_demuxer,
    &ff_mpc_demuxer,
    &ff_mpc8_demuxer,
    &ff_mpegps_demuxer,
    &ff_mpegts_demuxer,
    &ff_mpegtsraw_demuxer,
    &ff_mpegvideo_demuxer,
    &ff_mpjpeg_demuxer,
    &ff_image_tiff_pipe_demuxer,
    &ff_image_webp_pipe_demuxer,
    &ff_image_xpm_pipe_demuxer,
    &ff_image_xwd_pipe_demuxer,
    NULL };

av_probe_input_format3的代码分析:


ff_const59 AVInputFormat *av_probe_input_format3(ff_const59 AVProbeData *pd, int is_opened,
                                                 int *score_ret)
{
    AVProbeData lpd = *pd;
    const AVInputFormat *fmt1 = NULL;
    ff_const59 AVInputFormat *fmt = NULL;
    int score, score_max = 0;
    void *i = 0;
    const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
    enum nodat {
        NO_ID3,
        ID3_ALMOST_GREATER_PROBE,
        ID3_GREATER_PROBE,
        ID3_GREATER_MAX_PROBE,
    } nodat = NO_ID3;

    if (!lpd.buf)
        lpd.buf = (unsigned char *) zerobuffer;

    if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
        int id3len = ff_id3v2_tag_len(lpd.buf);
        if (lpd.buf_size > id3len + 16) {
            if (lpd.buf_size < 2LL*id3len + 16)
                nodat = ID3_ALMOST_GREATER_PROBE;
            lpd.buf      += id3len;
            lpd.buf_size -= id3len;
        } else if (id3len >= PROBE_BUF_MAX) {
            nodat = ID3_GREATER_MAX_PROBE;
        } else
            nodat = ID3_GREATER_PROBE;
    }

    // 遍历所有的demuxer
    while ((fmt1 = av_demuxer_iterate(&i))) {
        if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
            continue;
        score = 0;
        if (fmt1->read_probe) {
            // 调用demuxer的read_probe函数计算score
            score = fmt1->read_probe(&lpd);
            if (score)
                av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
            if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
                switch (nodat) {
                    case NO_ID3:
                        score = FFMAX(score, 1);
                        break;
                    case ID3_GREATER_PROBE:
                    case ID3_ALMOST_GREATER_PROBE:
                        score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);
                        break;
                    case ID3_GREATER_MAX_PROBE:
                        score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
                        break;
                }
            }
        } else if (fmt1->extensions) {
            if (av_match_ext(lpd.filename, fmt1->extensions))
                score = AVPROBE_SCORE_EXTENSION;
        }
        if (av_match_name(lpd.mime_type, fmt1->mime_type)) {
            if (AVPROBE_SCORE_MIME > score) {
                score = AVPROBE_SCORE_MIME;
            }
        }
        
        // 记录分值最高的format
        if (score > score_max) {
            score_max = score;
            fmt       = (AVInputFormat*)fmt1;
        } else if (score == score_max)
            fmt = NULL;
    }
    
    // 返回score_max对应的fmt
    if (nodat == ID3_GREATER_PROBE)
        score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
    *score_ret = score_max;

    return fmt;
}

在前面probe到具体的format之后,就调用真正的demuxer来处理,这里是iso base的文件类型,进入mov对应的处理逻辑,下面是调用栈:

mov_read_ftyp        mov.c        1120 0x7ffff71261bd 
mov_read_default     mov.c        6929 0x7ffff713864d 
mov_read_header      mov.c        7468 0x7ffff713a38b 
avformat_open_input  utils.c      634  0x7ffff722f56b 
open_input_file      ffmpeg_opt.c 1105 0x555555563c13 
open_files           ffmpeg_opt.c 3280 0x55555556dba3 
ffmpeg_parse_options ffmpeg_opt.c 3320 0x55555556dd57 
main                 ffmpeg.c     4874 0x55555558d9d8 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值