ffmpeg源码分析--5.avio分析

2500阅读 0评论2016-04-25 wangcong02345
分类:LINUX

一.协议层的注册及初始化过程
1. 协议的注册av_register_all
  1. void av_register_all(void)
  2. {
  3.     REGISTER_PROTOCOL(FILE, file);
  4.     REGISTER_PROTOCOL(FTP, ftp);
  5.     REGISTER_PROTOCOL(HTTP, http);
  6.     REGISTER_PROTOCOL(RTP, rtp);
  7.     REGISTER_PROTOCOL(SCTP, sctp);
  8.     ...
  9. }
在av_register_all中注册了一条protocol的链表,
FILE FTP HTTP RTP等协议都属于protocol
2. 协议的初始化过程
  1. avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
  2. {
  3.   1.avformat_alloc_context
  4.     --> avformat_get_context_defaults
  5.      :: s->io_open = io_open_default;    //初始化了AVFormatContext的io_open
  6.   2. init_input(s, filename, &tmp);
  7.        --> av_probe_input_format2        //没有打开媒体文件之前,先去probe input的类型,这儿一般是失败的
  8.        -->s->io_open                     //先probe协议类型,然后用probe到的协议类型去打开媒体文件
  9.        -->io_open_default                //options.c
  10.        -->ffio_open_whitelist            //aviobuf.c
  11.          -->ffurl_open_whitelist         //avio.c
  12.            --> ffurl_alloc               //avio.c  
  13.            --> ffurl_connect             //avio.c
  14. }
2.1 ffurl_alloc
   -->url_find_protocol              //解析filename,并返回查找到的协议类型
   -->url_alloc_for_protocol      //为这个协议类型分配内存,并初始化
  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.     //如果文件名中没有:则协议类型的名字是file,若有则把:之前的当做协议类型
  7.     //例如: /tmp/friends.mkv则协议类型为name=file
  8.     //     ,则协议类型的name=http
  9.     if (filename[proto_len] != ':' &&
  10.         (strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) ||
  11.         is_dos_path(filename))
  12.         strcpy(proto_str, "file");
  13.     else
  14.         av_strlcpy(proto_str, filenameFFMIN(proto_len + 1, sizeof(proto_str)));

  15.     if ((ptr = strchr(proto_str, ',')))
  16.         *ptr = '\0';
  17.     av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
  18.     if ((ptr = strchr(proto_nested, '+')))
  19.         *ptr = '\0';
  20.     //然后按名字查找协议类型,把查找到的返回
  21.     while (up = ffurl_protocol_next(up)) {
  22.         if (!strcmp(proto_str, up->name))
  23.             break;
  24.         if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
  25.             !strcmp(proto_nested, up->name))
  26.             break;
  27.     }
  28.     return up;
  29. }
2.2 ffurl_connnect
ffurl_connect  //如果protocol中没有url_open2则调用url_open
 ::err = uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags,options) :
        uc->prot->url_open(uc, uc->filename, uc->flags);
这儿以file的protocol为例说明
在file中其url_open就是file_open
.url_open            = file_open,
  1. static int file_open(URLContext *h, const char *filename, int flags)
  2. {
  3.     FileContext *c = h->priv_data;
  4.     int access;
  5.     int fd;
  6.     struct stat st;
  7.     fd = avpriv_open(filename, access, 0666);  //这个就是调用系统调用open
  8.     if (fd == -1)
  9.         return AVERROR(errno);
  10.     c->fd = fd;

  11.     h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);

  12.     return 0;
  13. }

二.协议层的操作

具体的AVInputFormat对文件的操作都是直接调用aviobuf层的接口来实现的
2.1 函数指针的初始化
ffio_open_whitelist
ffio_fdopen
 -->avio_alloc_context
    ::分别初始化如下
       write_packet= ffurl_write
       read_packet= ffurl_read
       seek = ffurl_seek
2.2 avio_size的调用
  1. avio_size
  2. --> s->seek(s->opaque, 0, AVSEEK_SIZE);
  3.     ::ffurl_seek();

  4. int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
  5. {
  6.     int64_t ret;

  7.     if (!h->prot->url_seek)
  8.         return AVERROR(ENOSYS);
  9.     ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
  10.     return ret;
  11. }
在file.c中
  1. .url_seek = file_seek,
  2. static int64_t file_seek(URLContext *h, int64_t pos, int whence)
  3. {
  4.     FileContext *c = h->priv_data;
  5.     int64_t ret;
  6.     //如果whence是AVSEEK_SIZE,则返回长度
  7.     if (whence == AVSEEK_SIZE) {
  8.         struct stat st;
  9.         ret = fstat(c->fd, &st);
  10.         return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
  11.     }
  12.     //否则就调用lseek   
  13.     ret = lseek(c->fd, pos, whence);
  14.     return ret < 0 ? AVERROR(errno) : ret;
  15. }

上一篇:ffmpeg源码分析--4.关于mpeg文件格式1总
下一篇:ffmpeg源码分析--6.关于mpeg文件格式2之video的track