FFmpeg源码:url_find_protocol函数分析

一、url_find_protocol函数的定义

url_find_protocol函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/avio.c中:

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");elseav_strlcpy(proto_str, filename,FFMIN(proto_len + 1, sizeof(proto_str)));av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));if ((ptr = strchr(proto_nested, '+')))*ptr = '\0';protocols = ffurl_get_protocols(NULL, NULL);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);if (av_strstart(filename, "https:", NULL) || av_strstart(filename, "tls:", NULL))av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with ""openssl, gnutls or securetransport enabled.\n");return NULL;
}

该函数在avformat_open_input函数内部被调用。其作用是:根据形参filename查找并返回匹配的流媒体协议类型 ;如果没有匹配的协议但filename符合“file”协议的url格式,那就返回“file”协议类型(在FFmpeg源码中,“文件”也被当作一种协议类型);如果都不符合则返回NULL。

形参filename:输入型参数,包含流媒体协议的名称信息。比如RTP对应的filename为:rtp://XXX,UDP对应的filename为:udp://XXX。

返回值:匹配到的流媒体协议类型,为URLProtocol类型。该结构体声明在libavformat/url.h中:

typedef struct URLProtocol {const char *name;int     (*url_open)( URLContext *h, const char *url, int flags);/*** This callback is to be used by protocols which open further nested* protocols. options are then to be passed to ffurl_open_whitelist()* or ffurl_connect() for those nested protocols.*/int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);int     (*url_accept)(URLContext *s, URLContext **c);int     (*url_handshake)(URLContext *c);/*** Read data from the protocol.* If data is immediately available (even less than size), EOF is* reached or an error occurs (including EINTR), return immediately.* Otherwise:* In non-blocking mode, return AVERROR(EAGAIN) immediately.* In blocking mode, wait for data/EOF/error with a short timeout (0.1s),* and return AVERROR(EAGAIN) on timeout.* Checking interrupt_callback, looping on EINTR and EAGAIN and until* enough data has been read is left to the calling function; see* retry_transfer_wrapper in avio.c.*/int     (*url_read)( URLContext *h, unsigned char *buf, int size);int     (*url_write)(URLContext *h, const unsigned char *buf, int size);int64_t (*url_seek)( URLContext *h, int64_t pos, int whence);int     (*url_close)(URLContext *h);int (*url_read_pause)(void *urlcontext, int pause);int64_t (*url_read_seek)(void *urlcontext, int stream_index,int64_t timestamp, int flags);int (*url_get_file_handle)(URLContext *h);int (*url_get_multi_file_handle)(URLContext *h, int **handles,int *numhandles);int (*url_get_short_seek)(URLContext *h);int (*url_shutdown)(URLContext *h, int flags);const AVClass *priv_data_class;int priv_data_size;int flags;int (*url_check)(URLContext *h, int mask);int (*url_open_dir)(URLContext *h);int (*url_read_dir)(URLContext *h, AVIODirEntry **next);int (*url_close_dir)(URLContext *h);int (*url_delete)(URLContext *h);int (*url_move)(URLContext *h_src, URLContext *h_dst);const char *default_whitelist;
} URLProtocol;

URLProtocol是FFmpeg协议解析器的注册结构体。每个流媒体协议都有一个与之对应的URLProtocol结构,其定义了协议的名称、流媒体url的打开、读取、写入等操作的函数指针。

比如RTP这种流媒体协议,其对应的URLProtocol结构为:

const URLProtocol ff_rtp_protocol = {.name                      = "rtp",.url_open                  = rtp_open,.url_read                  = rtp_read,.url_write                 = rtp_write,.url_close                 = rtp_close,.url_get_file_handle       = rtp_get_file_handle,.url_get_multi_file_handle = rtp_get_multi_file_handle,.priv_data_size            = sizeof(RTPContext),.flags                     = URL_PROTOCOL_FLAG_NETWORK,.priv_data_class           = &rtp_class,
};

“file”协议对应的URLProtocol结构为:

const URLProtocol ff_file_protocol = {.name                = "file",.url_open            = file_open,.url_read            = file_read,.url_write           = file_write,.url_seek            = file_seek,.url_close           = file_close,.url_get_file_handle = file_get_handle,.url_check           = file_check,.url_delete          = file_delete,.url_move            = file_move,.priv_data_size      = sizeof(FileContext),.priv_data_class     = &file_class,.url_open_dir        = file_open_dir,.url_read_dir        = file_read_dir,.url_close_dir       = file_close_dir,.default_whitelist   = "file,crypto,data"
};

“rtmp”协议对应的URLProtocol结构为:

const URLProtocol ff_librtmp_protocol = {.name                = "rtmp",.url_open            = rtmp_open,.url_read            = rtmp_read,.url_write           = rtmp_write,.url_close           = rtmp_close,.url_read_pause      = rtmp_read_pause,.url_read_seek       = rtmp_read_seek,.url_get_file_handle = rtmp_get_file_handle,.priv_data_size      = sizeof(LibRTMPContext),.priv_data_class     = &librtmp_class,.flags               = URL_PROTOCOL_FLAG_NETWORK,
};

二、url_find_protocol函数的内部实现分析

url_find_protocol函数中首先通过下面代码块将形参filename中的流媒体协议名称拷贝到数组proto_str中。如果没有匹配的协议但filename符合“file”协议的url格式,那就拷贝“file”,表示是“文件”协议类型:

    if (filename[proto_len] != ':' &&(strncmp(filename, "subfile,", 8) || !strchr(filename + proto_len + 1, ':')) ||is_dos_path(filename))strcpy(proto_str, "file");elseav_strlcpy(proto_str, filename,FFMIN(proto_len + 1, sizeof(proto_str)));

拷贝流媒体协议名称到数组proto_nested中。关于av_strlcpy函数的用法可以参考:《FFmpeg源码:av_strlcpy函数分析》:

    av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));if ((ptr = strchr(proto_nested, '+')))*ptr = '\0';

返回指向全局数组url_protocols开头的二级指针:

    protocols = ffurl_get_protocols(NULL, NULL);if (!protocols)return NULL;

ffurl_get_protocols函数的定义如下。可以看到其内部遍历了全局数组url_protocols:

const URLProtocol **ffurl_get_protocols(const char *whitelist,const char *blacklist)
{const URLProtocol **ret;int i, ret_idx = 0;ret = av_calloc(FF_ARRAY_ELEMS(url_protocols), sizeof(*ret));if (!ret)return NULL;for (i = 0; url_protocols[i]; i++) {const URLProtocol *up = url_protocols[i];if (whitelist && *whitelist && !av_match_name(up->name, whitelist))continue;if (blacklist && *blacklist && av_match_name(up->name, blacklist))continue;ret[ret_idx++] = up;}return ret;
}

全局数组url_protocols定义在libavformat/protocol_list.c中,该数组中的每个元素都对应一种URLProtocol结构,也就是说数组中的每个元素都对应一种流媒体协议(RTP、FILE、RTMP等):

static const URLProtocol * const url_protocols[] = {&ff_async_protocol,&ff_cache_protocol,&ff_concat_protocol,&ff_concatf_protocol,&ff_crypto_protocol,&ff_data_protocol,&ff_fd_protocol,&ff_ffrtmphttp_protocol,&ff_file_protocol,&ff_ftp_protocol,&ff_gopher_protocol,&ff_hls_protocol,&ff_http_protocol,&ff_httpproxy_protocol,&ff_icecast_protocol,&ff_mmsh_protocol,&ff_mmst_protocol,&ff_md5_protocol,&ff_pipe_protocol,&ff_prompeg_protocol,&ff_rtmp_protocol,&ff_rtmpt_protocol,&ff_rtp_protocol,&ff_srtp_protocol,&ff_subfile_protocol,&ff_tee_protocol,&ff_tcp_protocol,&ff_udp_protocol,&ff_udplite_protocol,&ff_unix_protocol,NULL };

url_find_protocol函数中,通过遍历全局数组url_protocols,比较协议名称,查找出该流媒体协议匹配的URLProtocol结构。如果查找到了,那就赋值给指针up,作为url_find_protocol函数的返回值返回:

    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;}}

如果查找不到匹配的流媒体协议,那就打印警报日志,返回NULL:

    av_freep(&protocols);if (av_strstart(filename, "https:", NULL) || av_strstart(filename, "tls:", NULL))av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with ""openssl, gnutls or securetransport enabled.\n");return NULL;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/69929.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DeepSeek 助力 Vue 开发:打造丝滑的无限滚动(Infinite Scroll)

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…

【区块链】零知识证明基础概念详解

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 零知识证明基础概念详解引言1. 零知识证明的定义与特性1.1 基本定义1.2 三个核心…

蓝桥杯篇---IAP15F2K61S2串口

文章目录 前言简介串口通信的基本参数1.波特率2.数据位3.停止位4.校验位 串口相关寄存器1.SCON2.SBUF3.PCON4.TMOD5.TH1/TL1 串口使用步骤1.配置波特率2.配置串口模式3.使能串口中断4.发送数据5.接收数据6.处理中断 示例代码:串口发送与接收示例代码:串口…

「vue3-element-admin」Vue3 + TypeScript 项目整合 Animate.css 动画效果实战指南

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template 🌺 仓库主页: GitCode︱ Gitee ︱ Github 💖 欢迎点赞 👍 收藏 ⭐评论 …

MyBatis:动态SQL高级标签使用方法指南

一、引言 目前互联网大厂在搭建后端Java服务时,常使用Springboot搭配Mybatis/Mybatis-plus的框架。Mybatis/Mybatis-plus之所以能成为当前国内主流的持久层框架,与其本身的优点有关:支持定制动态 SQL、存储过程及高级映射,简化数…

untiy3D 让角色动起来,角色动画的使用

1.untiy 商店下载动画模型 2.导入项目 模型拖入到场景中 3.创建动画器控制器 4.动画控制器挂载到plarer上 5.把动画idle和pickup拖入到动画器 6.右键动画创建过渡效果(Make Transition) 6.设置参数用条件控制 7.当选中参数时启动过渡 运行效果 119 (二)用脚本控制动画…

XXL-Job入门

XXL-Job入门 什么是xxl-job? ​ xxl-job是一个分布式的任务调度平台,其核心设计目标是:学习简单、开发迅速、轻量级、易扩展,现在已经开放源代码并接入多家公司的线上产品线,开箱即用。xxl是xxl-job的开发者…

Linux 基于共享内存的循环队列实现

Linux 基于共享内存的循环队列实现 Linux 基于共享内存的循环队列实现一、共享内存与循环队列基础1.1 共享内存特性1.2 循环队列优势 二、系统关键技术分析2.1 共享内存操作APIshmget() 创建共享内存shmat() 映射共享内存 2.2 模板类设计要点 三、循环队列核心方法实现3.1 初始…

【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第十九节】

ISO 14229-1:2023 UDS诊断服务测试用例全解析(ClearDiagnosticInformation_0x84服务) 作者:车端域控测试工程师 更新日期:2025年02月14日 关键词:UDS协议、0x84服务、清除诊断信息、ISO 14229-1:2023、ECU测试 一、服…

盛铂科技 SMF106 低相位噪声贴片式频率综合器模块

在现代通信和电子设备领域,频率综合器作为关键组件,其性能优劣直接影响系统的整体表现。盛铂科技的 SMF106 低相位噪声贴片式频率综合器,以其卓越的性能和独特设计,成为众多高性能系统的选择。 一、频率覆盖范围广,步进…

Java语言在微服务架构中的应用研究

Java语言在微服务架构中的应用研究 微服务架构是现代软件系统中一种重要的设计模式,它通过将单一的应用程序拆解成多个小型、独立的服务来增强系统的可扩展性、灵活性和可维护性。Java作为一种成熟的编程语言,在微服务架构的实现中发挥了重要作用。本文…

深度解析前端性能优化:策略与实践

在当今数字化时代,前端性能对于用户体验和业务成功至关重要。缓慢加载的页面会导致用户流失,而高效的前端性能则能提升用户满意度、转化率和品牌形象。本文将深入探讨前端性能优化的关键策略与实践,帮助开发者打造快速响应的优质 Web 应用。 一、资源加载优化 1. 压缩与合…

Mybatis-扩展功能

逻辑删除乐观锁 MyBatisPlus从入门到精通-3(含mp代码生成器) Db静态工具类 Spring依赖循环问题 代码生成器 MybatisPlus代码生成器 枚举处理器 我们这里用int来存储状态 需要注解,很不灵活 希望用枚举类来代替这个Integer 这样的话我…

请解释设备像素、CSS 像素、设备独立像素、DPR、PPI 之间的区别?

设备像素(Device Pixels) 定义:设备像素,也称为物理像素,是屏幕上能够显示的最小物理单位。每个设备像素代表屏幕上的一个点,用于显示颜色。 代码示例: console.log(window.screen.width); /…

【golang】channel带缓存和不带缓存的区别,应用场景解读

在Go语言中,channel(通道)分为带缓存的通道(Buffered Channel)和不带缓存的通道(Unbuffered Channel),它们的核心区别在于数据传递的同步机制和性能特性。以下是详细对比&#xff1a…

《Foundation 起步》

《Foundation 起步》 引言 在当今快速发展的科技时代,了解并掌握最新的技术是至关重要的。本文旨在为初学者提供一个全面的《Foundation》起步指南,帮助大家快速入门并掌握这一强大的技术。 一、什么是Foundation? Foundation 是一个流行的前端框架,由 ZURB 公司开发。…

Java Lambda 表达式的实践与思考

一、引言 自Java 8引入Lambda表达式以来,Java语言在函数式编程方面迈出了重要一步。Lambda不仅让代码变得更简洁,还极大地提升了对集合、流操作等场景下的处理能力。作为一名资深Java后端程序员,多年的开发实践让我深刻体会到Lambda在提升代…

记忆力训练day19

万能字母组合编码法 所有的文字和字母的背后都有画面 练的不是记单词,练的是注意力给到单词,出什么画面,然后画面与画面之间进行连接 拆的过程就是找熟词的过程 要关注自己的回忆路径是什么?也就是你是怎么回忆起来的&#xff0c…

【第13章:自监督学习与少样本学习—13.4 自监督学习与少样本学习的未来研究方向与挑战】

凌晨三点的实验室里,博士生小张盯着屏幕上的训练曲线——他设计的跨模态少样本学习模型在医疗影像诊断任务上突然出现了诡异的性能断崖。前一秒还在92%的准确率高位运行,下一秒就暴跌到47%。这个看似灾难性的现象,却意外揭开了自监督学习与少样本学习技术深藏的核心挑战… 一…

unity学习43:子状态机 sub-state machine

目录 1sub-state machine子状态机 1.1 创建 sub-state machine 1.2 sub-state machine 内容 1.3 子状态机的应用 2 子状态机不同于blend tree的嵌套 3 应用例子:若角色拿不同武器的动画设计,可以使用2种方法 3.1 在1个图层layer里,使用…