ffmpeg源代码解读:ffurl_alloc
来源:互联网 发布:外网访问centos 编辑:程序博客网 时间:2024/05/18 04:37
ffurl_alloc主要包括url_find_protocol和url_alloc_for_protocol两个函数,前者根据filename查找匹配的url协议类型,后者根据找到的URLProtocol创建对应的URLContext。
url_find_protocol 函数根据文件名filename (准确来说可以叫做url),函数如下
static const struct URLProtocol *url_find_protocol(const char *filename){ const URLProtocol **protocols; char proto_str[128], proto_nested[128], *ptr; size_t proto_len = strspn(filename, URL_SCHEME_CHARS); int i; if (filename[proto_len] != ':' && (strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) || is_dos_path(filename)) strcpy(proto_str, "file"); else av_strlcpy(proto_str, filename, FFMIN(proto_len + 1, sizeof(proto_str))); if ((ptr = strchr(proto_str, ','))) *ptr = '\0'; av_strlcpy(proto_nested, proto_str, sizeof(proto_nested)); if ((ptr = strchr(proto_nested, '+'))) *ptr = '\0'; protocols = ffurl_get_protocols(NULL, NULL); //获得已经注册的所有url protocols if (!protocols) return NULL; for (i = 0; protocols[i]; i++) { const URLProtocol *up = protocols[i]; if (!strcmp(proto_str, up->name)) { av_freep(&protocols); return up; } if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME && !strcmp(proto_nested, up->name)) { av_freep(&protocols); return up; } } av_freep(&protocols); return NULL;}
这个函数比较简单,首先是截取到url开头的字符串获得url类型。比如 rtp://xxxxx/yyyyy就会截取到”rtp”,于是可以获得协议的类型,将描述协议类型的字符串如“rtp”,“http”等拷贝到proto_str中,接下来进行比对。需要注意的是,如果输入的是普通的磁盘上的文件,这里的filename就是文件的路径和文件名了,此时提取不到url协议的类型,ffmpeg将文件也当做一种特殊的url协议,即“file”协议。如果是普通的磁盘上的文件输入,则把proto_str赋值为”file”。 接下来就是遍历所有的ffmpeg支持的url协议类型,将和我们的proto_str匹配的协议类型的URLProtocol指针返回。 找到对应的输入url的协议类型后,调用url_alloc_for_protocol函数创建对应的URLContex,并进行初始化,如下
static int url_alloc_for_protocol(URLContext **puc, const URLProtocol *up, const char *filename, int flags, const AVIOInterruptCB *int_cb){ URLContext *uc; int err;#if CONFIG_NETWORK if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init()) return AVERROR(EIO);#endif if ((flags & AVIO_FLAG_READ) && !up->url_read) { av_log(NULL, AV_LOG_ERROR, "Impossible to open the '%s' protocol for reading\n", up->name); return AVERROR(EIO); } if ((flags & AVIO_FLAG_WRITE) && !up->url_write) { av_log(NULL, AV_LOG_ERROR, "Impossible to open the '%s' protocol for writing\n", up->name); return AVERROR(EIO); } uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1); if (!uc) { err = AVERROR(ENOMEM); goto fail; } uc->av_class = &ffurl_context_class; uc->filename = (char *)&uc[1]; strcpy(uc->filename, filename); uc->prot = up; uc->flags = flags; uc->is_streamed = 0; /* default = not streamed */ uc->max_packet_size = 0; /* default: stream file */ if (up->priv_data_size) { uc->priv_data = av_mallocz(up->priv_data_size); if (!uc->priv_data) { err = AVERROR(ENOMEM); goto fail; } if (up->priv_data_class) { int proto_len= strlen(up->name); char *start = strchr(uc->filename, ','); *(const AVClass **)uc->priv_data = up->priv_data_class; av_opt_set_defaults(uc->priv_data); // subfile协议,比如下面一行所描述的filename /* subfile,,start,153391104,end,268142592,,:/media/dvd/VIDEO_TS/VTS_08_1.VOB */ if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){ int ret= 0; char *p= start; char sep= *++p; char *key, *val; p++; if (strcmp(up->name, "subfile")) ret = AVERROR(EINVAL); while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){ *val= *key= 0; if (strcmp(p, "start") && strcmp(p, "end")) { ret = AVERROR_OPTION_NOT_FOUND; } else ret= av_opt_set(uc->priv_data, p, key+1, 0); if (ret == AVERROR_OPTION_NOT_FOUND) av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p); *val= *key= sep; p= val+1; } if(ret<0 || p!=key){ av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start); av_freep(&uc->priv_data); av_freep(&uc); err = AVERROR(EINVAL); goto fail; } // subfile:/media/dvd/VIDEO_TS/VTS_08_1.VOB memmove(start, key+1, strlen(key)); } } } if (int_cb) uc->interrupt_callback = *int_cb; *puc = uc; return 0;fail: *puc = NULL; if (uc) av_freep(&uc->priv_data); av_freep(&uc);#if CONFIG_NETWORK if (up->flags & URL_PROTOCOL_FLAG_NETWORK) ff_network_close();#endif return err;}
函数首先判断相关的flag所描述的需求是否满足,比如flag有AVIO_FLAG_READ,那么对应找到的URLProtocol必须要有url_read函数。后面是对创建的URLContext进行初始化,如av_class 、filename、 prot等等,其中prot就是之前我们找到的匹配的URLProtocol。接下来的if (up->priv_data_size){xx}是对priv_data的初始化,设定默认的参数值。后面if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start) 这个if语句块是对于“subfile”协议进行start和end值得设置,并且将正确的文件名前移,形成类似“subfile:abc.vob” 这样格式的filename。
subfile协议url的一个例子我上面注释中给了一个,具体的subfile协议可以参考subfile协议
- ffmpeg源代码解读:ffurl_alloc
- FFMPEG框架代码解读
- Ffmpeg框架结构解读
- FFmpeg框架解读
- Ffmpeg框架结构解读
- ffmpeg框架结构解读
- Ffmpeg框架结构解读
- FFmpeg框架结构解读
- ffmpeg框架结构解读
- Ffmpeg框架结构解读
- Ffmpeg框架结构解读
- Ffmpeg框架结构解读(转)
- Ffmpeg框架结构解读 .
- ffmpeg框架结构解读
- Ffmpeg框架结构解读
- ffmpeg框架结构解读大全
- Ffmpeg框架结构解读
- Ffmpeg框架结构解读
- cocoapods的安装 遇到 Error installing pods:activesupport requires Ruby version >=2.2.2
- Spring学习总结——Spring整合MyBatis(Maven+MySQL)二
- android studio 更新 Gradle错误解决方法
- 朴素贝叶斯分类
- 深度学习caffe平台--train_val.prototxt文件中视觉层(Vision Layers)层及参数详解
- ffmpeg源代码解读:ffurl_alloc
- 通过CAGradientLayer制作渐变色效果【原创】
- python中*args **kw到底是什么意思?
- 数据结构实验之二叉树的建立与遍历
- HTML5 视频播放
- Web.xml配置详解之context-param
- 安卓实战开发之JNI入门及高效的配置
- hdu-1216-Assistance Required
- 学期总结