ffmpeg源码分析--3.avformat_alloc_context与avformat_open_input

2120阅读 0评论2016-04-13 wangcong02345
分类:LINUX

一. avformat_alloc_context
1.1 在./libavformat/options.c中
  1. AVFormatContext *avformat_alloc_context(void)
  2. {
  3.     AVFormatContext *ic;
  4.     ic = av_malloc(sizeof(AVFormatContext));   //为AVFormatContex分配内存
  5.     avformat_get_context_defaults(ic);         //下面就是一些初始化的操作

  6.     ic->internal = av_mallocz(sizeof(*ic->internal));
  7.     if (!ic->internal) {
  8.         avformat_free_context(ic);
  9.         return NULL;
  10.     }
  11.     ic->internal->offset = AV_NOPTS_VALUE;
  12.     ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;

  13.     return ic;
  14. }
为AVFormatContext分配内存并初始化

二. avformat_open_init
2.1 
avformat_open_init总体分析
在libavformat/utils.c中
avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
{
     1. avformat_alloc_context                          ::分配一个AVFormatContext结构体
     2.init_input(s, filename, &tmp);
      --> av_probe_input_format2                     ::没有打开媒体文件之前的probe
      -->s->io_open                                           ::打开媒体文件
        -->io_open_default
        -->ffio_open_whitelist
          -->ffurl_alloc
              -->url_find_protocol   (file protocol)
              -->url_alloc_for_protocol
          -->ffurl_connect ::uc->prot->url_open
               -->file_open
               -->avpriv_open   ::即调用系统的open
      -->av_probe_input_buffer2                             ::打开媒体文件之后的probe
          --> avio_read   ::s->read_packet
              --> ffurl_read
              --> file_read ::即调用系统的read
          -->av_probe_input_format2  
            --> av_probe_input_format3
               --> matroska_probe
               --> mov_probe
    3.s->iformat->read_header(s)                     ::读取媒体文件中的信息并分析
         --> mov_read_header                            
}
2.2代码分析 
2.2.1 avformat_open_input
            --> init_input
  1. static int init_input(AVFormatContext *s, const char *filenameAVDictionary **options)
  2. {
  3.     int ret;
  4.     AVProbeData pd = { filename, NULL, 0 };
  5.     int score = AVPROBE_SCORE_RETRY;

  6.     if (s->pb) {                    //如果用户指定了必须使用哪个iformat则进入下面的流程
  7.         ...  //这儿略过        
  8.         return 0;
  9.     }

  10.     if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
  11.         (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
  12.         return score;

  13.     if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
  14.         return ret;

  15.     if (s->iformat)
  16.         return 0;
  17.     return av_probe_input_buffer2(s->pb, &s->iformat, filenames, 0, s->format_probesize);
  18. }
说明:
a.av_probe_input_format2 时score=25,probe出来的probe_score=0,
probe_scoreiformat=NULL

b. av_probe_input_buffer2中也调用了av_probe_input_format2只不过中间的参数is_opened是1
说明文件己被打开
2.2.2 
avformat_open_input
--> init_input
     --> av_probe_input_buffer2
  1. int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
  2.                           const char *filename, void *logctx,
  3.                           unsigned int offset, unsigned int max_probe_size)
  4. {
  5.     AVProbeData pd = { filename ? filename : "" };
  6.     uint8_t *buf = NULL;
  7.     int ret = 0, probe_size, buf_offset = 0;
  8.     int score = 0;
  9.     int ret2;

  10.     if (!max_probe_size)
  11.         max_probe_size = PROBE_BUF_MAX;
  12.     else if (max_probe_size < PROBE_BUF_MIN) {
  13.         av_log(logctx, AV_LOG_ERROR,
  14.                "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN);
  15.         return AVERROR(EINVAL);
  16.     }

  17.     if (offset >= max_probe_size)
  18.         return AVERROR(EINVAL);

  19.     if (pb->av_class) {
  20.         uint8_t *mime_type_opt = NULL;
  21.         char *semi;
  22.         av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt);
  23.         pd.mime_type = (const char *)mime_type_opt;
  24.         semi = pd.mime_type ? strchr(pd.mime_type, ';') : NULL;
  25.         if (semi) {
  26.             *semi = '\0';
  27.         }
  28.     }


  29.     for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt;
  30.          probe_size = FFMIN(probe_size << 1,
  31.                             FFMAX(max_probe_size, probe_size + 1))) {
  32.         score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;

  33.         //分配内存为读取媒体文件的内容作准备
  34.         av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE);
  35.         //读取媒体文件的内容作,就是一个调用read的过程
  36.         avio_read(pb, buf + buf_offsetprobe_size - buf_offset);
  37.         buf_offset += ret;
  38.         if (buf_offset < offset)
  39.             continue;
  40.         pd.buf_size = buf_offset - offset;
  41.         pd.buf = &buf[offset];

  42.         memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);

  43.         /* Guess file format. */
  44.         *fmt = av_probe_input_format2(&pd, 1, &score);    //对媒体文件的内容进行probe看是属于哪个类型
  45.         if (*fmt) {
  46.             /* This can only be true in the last iteration. */
  47.             if (score <= AVPROBE_SCORE_RETRY) {
  48.                 av_log(logctx, AV_LOG_WARNING,
  49.                        "Format %s detected only with low score of %d, "
  50.                        "misdetection possible!\n", (*fmt)->name, score);
  51.             } else
  52.                 av_log(logctx, AV_LOG_DEBUG,
  53.                        "Format %s probed with size=%d and score=%d\n",
  54.                        (*fmt)->name, probe_size, score);

  55.         }
  56.     }

  57.     if (!*fmt)
  58.         ret = AVERROR_INVALIDDATA;

  59. fail:
  60.     /* Rewind. Reuse probe buffer to avoid seeking. */
  61.     ret2 = ffio_rewind_with_probe_data(pb, &buf, buf_offset);
  62.     if (ret >= 0)
  63.         ret = ret2;

  64.     av_freep(&pd.mime_type);
  65.     return ret < 0 ? ret : score;
  66. }
2.2.3 
avformat_open_input
--> init_input
     --> av_probe_input_buffer2
        -->av_probe_input_format3
  1. AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened,
  2.                                       int *score_ret)
  3. {
  4.     AVProbeData lpd = *pd;
  5.     AVInputFormat *fmt1 = NULL, *fmt;
  6.     int score, score_max = 0;
  7.     const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
  8.     enum nodat {
  9.         NO_ID3,
  10.         ID3_ALMOST_GREATER_PROBE,
  11.         ID3_GREATER_PROBE,
  12.         ID3_GREATER_MAX_PROBE,
  13.     } nodat = NO_ID3;

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

  16.     if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
  17.         int id3len = ff_id3v2_tag_len(lpd.buf);
  18.         if (lpd.buf_size > id3len + 16) {
  19.             if (lpd.buf_size < 2LL*id3len + 16)
  20.                 nodat = ID3_ALMOST_GREATER_PROBE;
  21.             lpd.buf += id3len;
  22.             lpd.buf_size -= id3len;
  23.         } else if (id3len >= PROBE_BUF_MAX) {
  24.             nodat = ID3_GREATER_MAX_PROBE;
  25.         } else
  26.             nodat = ID3_GREATER_PROBE;
  27.     }

  28.     fmt = NULL;
  29.     while ((fmt1 = av_iformat_next(fmt1))) {
  30.         //当is_opened=0时,只对alsa fbdev rtp rtsp这样flag=AVFMT_NOFILE的AVInputFormat调用probe
  31.         //当is_opened=1时,只对ac3 dts h263 h264 这样flag不含AVFMT_NOFILE的调用probe
  32.         if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
  33.             continue;
  34.         score = 0;
  35.         if (fmt1->read_probe) {
  36.             score = fmt1->read_probe(&lpd);         //lpd中的buf是媒体文件中的头2048个字节
  37.             if (score)
  38.                 av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
  39.             if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
  40.                 switch (nodat) {
  41.                 case NO_ID3:
  42.                     score = FFMAX(score, 1);
  43.                     break;
  44.                 case ID3_GREATER_PROBE:
  45.                 case ID3_ALMOST_GREATER_PROBE:
  46.                     score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);
  47.                     break;
  48.                 case ID3_GREATER_MAX_PROBE:
  49.                     score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
  50.                     break;
  51.                 }
  52.             }
  53.         } else if (fmt1->extensions) {
  54.             if (av_match_ext(lpd.filename, fmt1->extensions))
  55.                 score = AVPROBE_SCORE_EXTENSION;
  56.         }
  57.         if (av_match_name(lpd.mime_type, fmt1->mime_type))
  58.             score = FFMAX(score, AVPROBE_SCORE_MIME);
  59.         if (score > score_max) {    //循环结束之后就是要取最大的score所代表的fmt
  60.             score_max = score;
  61.             fmt = fmt1;
  62.         } else if (score == score_max)
  63.             fmt = NULL;
  64.     }
  65.     if (nodat == ID3_GREATER_PROBE)
  66.         score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
  67.     *score_ret = score_max;             //将probe中产生的最大的score与fmt返回

  68.     return fmt;
  69. }
s->iformat->name=mov,mp4,m4a,3gp,3g2,mj2
s->iformat->name=matroska,webm


三. 媒体文件的读写
3.1 媒体文件的打开过程
avformat_open_input
init_input
    --> s->io_open    
       -->io_open_default                   ::libavformat/options.c
            --> ffio_open_whitelist         ::libavformat/aviobuf.c
                 --> ffurl_open_whitelist   ::libavformat/avio.c
                    -->ffurl_connect           ::libavformat/avio.c
                      --> file_open             ::libavformat/file.c 
AVFormatContext s;
s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)
3.2代码分析
3.2.1 avio层
  1. int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags,
  2.                          const AVIOInterruptCB *int_cb, AVDictionary **options,
  3.                          const char *whitelist
  4.                         )
  5. {
  6.     ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist);
  7.     --> furl_alloc(puc, filename, flags, int_cb);
  8.         --> p = url_find_protocol(filename);  //根据文件名判断protocol类型,并返回protocol的指针             
  9.         --> url_alloc_for_protocol(puc, p, filename, flags, int_cb);  //分配内存并初始化p
  10.     --> ffurl_connect(*puc, options);
  11.     ffio_fdopen(s, h);
  12.     return 0;
  13. }
3.2.2 avio层
  1. static struct URLProtocol *url_find_protocol(const char *filename)
  2. {
  3.     URLProtocol *up = NULL;
  4.     char proto_str[128], proto_nested[128], *ptr;
  5.     size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
  6.     //根据文件名来判断protocol类型,若文件名中没有:则为file类型的protocol
  7.     if (filename[proto_len] != ':' &&
  8.         (strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) ||
  9.         is_dos_path(filename))
  10.         strcpy(proto_str, "file");
  11.     else
  12.         av_strlcpy(proto_str, filename,
  13.                    FFMIN(proto_len + 1, sizeof(proto_str)));

  14.     if ((ptr = strchr(proto_str, ',')))
  15.         *ptr = '\0';
  16.     av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
  17.     if ((ptr = strchr(proto_nested, '+')))
  18.         *ptr = '\0';
  19.     while (up = ffurl_protocol_next(up)) {      //查找到file类型的URLProtocol并返回
  20.         if (!strcmp(proto_str, up->name))
  21.             break;
  22.         if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
  23.             !strcmp(proto_nested, up->name))
  24.             break;
  25.     }

  26.     return up;
  27. }
注:ffmpeg所支持的所有的protocol都在libavformat/Makefile中以CONFIG_XXX_PROTOCOL标志
3.2.3 avio层
  1. int ffurl_connect(URLContext *uc, AVDictionary **options)
  2. {
  3.     //uc->prot->url_open是真正的打开文件的函数
  4.     uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filenameuc->flagsoptions) :
  5.         uc->prot->url_open(uc, uc->filename, uc->flags);        
  6.     return 0;
  7. }
3.2.4 这就到了protocol层
libavformat/file.c
  1. static int file_open(URLContext *h, const char *filename, int flags)
  2. {
  3.     FileContext *c = h->priv_data;
  4.     int fd;  
  5.     
  6.     fd = avpriv_open(filename, access, 0666);
  7.        --> 这个就是open函数的最后一层封装    
  8.     c->fd = fd;
  9.     return 0;
  10. }
3.3 媒体文件的读过程
3.3.1 读写函数的初始化过程
ffio_open_whitelist                           ::libavformat/aviobuf.c
ffio_fdopen 初始代读写函数                ::libavformat/aviobuf.c        
avio_alloc_context                            ::libavformat/aviobuf.c
ffio_init_context                                ::libavformat/aviobuf.c           
ffio_init_context                                ::libavformat/aviobuf.c
   s->write_packet    = write_packet;  :: ffurl_write  终于找到了
    s->read_packet     = read_packet;   :: ffurl_read
3.3.2 读写函数的调用过程
av_probe_input_buffer2        ::libavformat/format.c
avio_read                              ::libavformat/aviobuf.c   ::ffmpeg提供的read接口

    s->read_packet
    ffurl_read                                ::libavformat/avio.c
    retry_transfer_wrapper           ::libavformat/avio.c

上一篇:ffmpeg源码分析--2.av_register_all
下一篇:ffmpeg源码分析--4.关于mpeg文件格式1总