最近升级ijkplayer过程中发现其协议注册接口已经失效了,仔细看了看ffmpeg相关代码基本弄清楚了。
旧版ijkplayer协议注册方式:
使用宏定义来注册私有协议ijkhttphook
//调用宏实现私有协议注册
IJK_REGISTER_PROTOCOL(ijklongurl);
//宏定义代码实现,#号为连接符号,最终执行代码
//ijkav_register_protocol(&ijkff_ijklongurl_protocol);
#define IJK_REGISTER_PROTOCOL(x) \
{ \
extern URLProtocol ijkff_##x##_protocol; \
ijkav_register_protocol(&ijkff_##x##_protocol); \
}
//ijkav_register_protocol代码实现
static void ijkav_register_protocol(URLProtocol *protocol)
{
if (ijkav_find_protocol(protocol->name)) {
av_log(NULL, AV_LOG_WARNING, "skip protocol: %s (duplicated)\n",
protocol->name);
} else {
av_log(NULL, AV_LOG_INFO, "register protocol: %s\n", protocol->name);
ffurl_register_protocol(protocol);
}
}
代码最终通过方法
ffurl_register_protocol来注册协议,此方法位于旧版ffmpeg url.h中声明
ijkff_ijklongurl_protocol 是一个URLProtocol结构体,在旧版ijkplayer代码中位于ijkavformat/ijklongurl.c文件中。
URLProtocol ijkff_ijklongurl_protocol = {
.name = "ijklongurl",
.url_open2 = ijklongurl_open,
.url_read = ijklongurl_read,
.url_seek = ijklongurl_seek,
.url_close = ijklongurl_close,
.priv_data_size = sizeof(Context),
.priv_data_class = &ijklongurl_context_class,
};
ijklongurl_open, ijklongurl_read等分别为打开文件,读取流的实现方法。
新版ffmpeg协议注册
在新版ffmpeg中删除了ffurl_register_protocol方法及url.h文件,且在av_register_all方法中只保留了REGISTER_MUTEX等封装,解封装,编解码器注册宏,删除了REGISTER_PROTOCOL协议注册宏。
step1, 在实现私有协议的open, read, write,close,init等方法。及URLProtocol结构体对象如ff_async_protocol(可参考旧版ijkplayer对ijktcphook协议的实现或ffmpeg中其他协议实现)于单个.c文件中,如async.c
static const AVClass async_context_class = {
.class_name = "Async",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
const URLProtocol ff_async_protocol = {
.name = "async",
.url_open2 = async_open,
.url_read = async_read,
.url_seek = async_seek,
.url_close = async_close,
.priv_data_size = sizeof(Context),
.priv_data_class = &async_context_class,
};
其中async_open, async_read, async_seek, async_close为要实现的私有协议内容。
step2, 将实现好的私有协议文件(.c文件)加入libavformat目录
step3, 修改ffmpeg/libavformat/protocols.c, 添加自定义网络协议URLProtocol全局变量声明
#include "config.h"
#include "libavutil/avstring.h"
#include "libavutil/mem.h"
#include "url.h"
extern const URLProtocol ff_async_protocol;
extern const URLProtocol ff_bluray_protocol;
extern const URLProtocol ff_cache_protocol;
extern const URLProtocol ff_concat_protocol;
extern const URLProtocol ff_crypto_protocol;
extern const URLProtocol ff_data_protocol;
extern const URLProtocol ff_ffrtmpcrypt_protocol;
extern const URLProtocol ff_ffrtmphttp_protocol;
extern const URLProtocol ff_file_protocol;
extern const URLProtocol ff_ftp_protocol;
extern const URLProtocol ff_gopher_protocol;
extern const URLProtocol ff_hls_protocol;
extern const URLProtocol ff_http_protocol;
extern const URLProtocol ff_httpproxy_protocol;
extern const URLProtocol ff_https_protocol;
extern const URLProtocol ff_icecast_protocol;
extern const URLProtocol ff_mmsh_protocol;
extern const URLProtocol ff_mmst_protocol;
extern const URLProtocol ff_md5_protocol;
extern const URLProtocol ff_pipe_protocol;
extern const URLProtocol ff_prompeg_protocol;
extern const URLProtocol ff_rtmp_protocol;
extern const URLProtocol ff_rtmpe_protocol;
extern const URLProtocol ff_rtmps_protocol;
extern const URLProtocol ff_rtmpt_protocol;
extern const URLProtocol ff_rtmpte_protocol;
extern const URLProtocol ff_rtmpts_protocol;
extern const URLProtocol ff_rtp_protocol;
extern const URLProtocol ff_sctp_protocol;
extern const URLProtocol ff_srtp_protocol;
extern const URLProtocol ff_subfile_protocol;
extern const URLProtocol ff_tee_protocol;
extern const URLProtocol ff_tcp_protocol;
extern const URLProtocol ff_tls_gnutls_protocol;
extern const URLProtocol ff_tls_schannel_protocol;
extern const URLProtocol ff_tls_securetransport_protocol;
extern const URLProtocol ff_tls_openssl_protocol;
extern const URLProtocol ff_udp_protocol;
extern const URLProtocol ff_udplite_protocol;
extern const URLProtocol ff_unix_protocol;
extern const URLProtocol ff_librtmp_protocol;
extern const URLProtocol ff_librtmpe_protocol;
extern const URLProtocol ff_librtmps_protocol;
extern const URLProtocol ff_librtmpt_protocol;
extern const URLProtocol ff_librtmpte_protocol;
extern const URLProtocol ff_libssh_protocol;
extern const URLProtocol ff_libsmbclient_protocol;
//可在此处继续添加一个自定义URLProtocol全局变量的外部声明如ff_async_protocol
#include "libavformat/protocol_list.c" //此文件为动态生成文件,在编译时由shell脚本文件生成。
至此,自定义协议注册到ffmpeg已经完成。我们可进一步看一下protocol_list.c是如何动态生成的:
# generate the lists of enabled components
print_enabled_components(){
file=$1
struct_name=$2
name=$3
shift 3
echo "static const $struct_name *$name[] = {" > $TMPH
for c in $*; do
enabled $c && printf " &ff_%s,\n" $c >> $TMPH
done
echo " NULL };" >> $TMPH
cp_if_changed $TMPH $file
}
print_enabled_components libavcodec/bsf_list.c AVBitStreamFilter bitstream_filters $BSF_LIST
print_enabled_components libavformat/protocol_list.c URLProtocol url_protocols $PROTOCOL_LIST
生成后的protocol_list.c内容:
static const URLProtocol *url_protocols[] = {
&ff_async_protocol,
&ff_cache_protocol,
&ff_concat_protocol,
&ff_crypto_protocol,
上面代码为生成protocol_list.c的脚本文件ffmpeg/configure,可见其遍历将所有protocol加入到了url_protocols[]中。因此,在新版 ffmpeg中不再提供url.h及ffurl_register_protocol等方法来注册了。而新版ijkplayer中的注册宏IJK_REGISTER_PROTOCOL内部的ijkav_register_**_protocol方法函数体都没有实现,是个空定义。ijkplayer实验性的一些协议(主要用于IO控制和统计):ijklongurl, ijktcphook, ijkhttphook等实际上都没有注册。可能他们还没有找到合适的方式来提供方便的私有协议注册接口。