您的位置:首页 > 其它

ijkplayer--播放器改动之私有协议注册

2017-09-01 17:43 393 查看
最近升级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 =
4000
{
.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等实际上都没有注册。可能他们还没有找到合适的方式来提供方便的私有协议注册接口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: