首页 > 编程知识 正文

支持自定义功能的视频播放器,幻灯片如何自定义播放

时间:2023-05-05 19:49:53 阅读:163586 作者:2188

FFmpeg实现了http、https等标准协议,但如何播放加密的视频呢? ijkplayer通过FFmpeg的libavformat模块进行扩展ijkio、ijklongurl、ijktcphook、ijkhttphook,并也能够基于此定制协议进行解密再现。 主要基于URLProtocol和AVClass进行扩展,实现支持protocol的方法。

URLProtocol的结构如下。

typedefstructurlprotocol { const char * name; int(*URL_open ) ) URLContext *h,const char *url,int flags ); int(*URL_open2 ) ) URLContext *h、const char *url、int flags、AVDictionary **options; int(*URL_accept ) ) URLContext *s,URLContext **c; int(URL_Handshake ) ) URL上下文* 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 priv_data_size; const AVClass *priv_data_class; const char *default_whitelist; } URLProtocol; FFmpeg实现的标准协议包括http、https、hls、tcp和rtmp,如下图所示。

1、添加自定义协议并将新的源文件ijkdecrypt.c放在libavformat中,然后单击ijkdecrypt_open、ijkdecrypt_read、ijkdecrypt_seek和ijkdecrypt.c

staticintijkdecrypt _ open (URL context * h ) returndecrypt_open ) h; } staticintijkdecrypt _ read (URL context * h,unsigned char *buf,int size ) returndecrypt_read,buf,size ); } static int 64 _ t decrypt _ seek (URL context * h,int64_t offset,int whence ) returndecrypt_seek ) h、offset、whee ee ee } staticconstavclassijkio _ context _ class={.class _ name=' ijk decrypt ', item _ name=av _ default _ item " . url_open2=ijkdecrypt_open, URL _ read.URL _ close=ijk decrypt _ close, priv _ data _ size=sizeof (corl ) . priv_data_class ) ijKio_context 2,声明自定义协议并修改此libavformat/protocols.c,添加自定义协议并将其声明为全局变量:

externconsturlprotocolff _ ijk decrypt _ protocol; ffbuild/config.mak将自动生成CONFIG_FF_IJKDECRYPT_PROTOCOL

3、在libavformat/makefi中依赖定制协议

le添加依赖文件:

OBJS-$(CONFIG_FF_IJKDECRYPT_PROTOCOL) += ijkdecrypt.o 4、dummy自定义协议

在libavformat/ijkutils.c添加dummy的ijkdecrypt:

IJK_DUMMY_PROTOCOL(ijkdecrypt);

dummy过程是生成AVClass和URLProtocol:

#define IJK_DUMMY_PROTOCOL(x) IJK_FF_PROTOCOL(x); static const AVClass ijk_##x##_context_class = { .class_name = #x, .item_name = av_default_item_name, .version = LIBAVUTIL_VERSION_INT, }; URLProtocol ff_##x##_protocol = { .name = #x, .url_open2 = ijkdummy_open, .priv_data_size = 1, .priv_data_class = &ijk_##x##_context_class, }; 5、注册自定义协议

在allformats.c调用ijkav_register_all进行注册自定义协议:

void ijkav_register_all(void){ av_register_all(); /* protocols */#ifdef __ANDROID__ IJK_REGISTER_PROTOCOL(ijkmediadatasource);#endif IJK_REGISTER_PROTOCOL(ijkio); IJK_REGISTER_PROTOCOL(async); IJK_REGISTER_PROTOCOL(ijklongurl); IJK_REGISTER_PROTOCOL(ijktcphook); IJK_REGISTER_PROTOCOL(ijkhttphook); IJK_REGISTER_PROTOCOL(ijksegment); /* demuxers */ IJK_REGISTER_DEMUXER(ijklivehook); IJK_REGISTER_DEMUXER(ijklas);}

IJK_REGISTER_PROTOCOL()对应的宏定义:

#define IJK_REGISTER_PROTOCOL(x) { extern URLProtocol ijkmp_ff_##x##_protocol; int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size); ijkav_register_##x##_protocol(&ijkimp_ff_##x##_protocol, sizeof(URLProtocol));}

其中ijkav_register_##x##_protocol的宏定义如下:

int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size) { if (protocol_size != sizeof(URLProtocol)) { av_log(NULL, AV_LOG_ERROR, "ABI mismatch.n"); return -1; } memcpy(&ff_##x##_protocol, protocol, protocol_size); return 0; } 6、拦截自定义协议

首先在ijkioprotocol.c声明自定义协议:

extern IjkURLProtocol ijkio_decrypt_rotocol;

然后对scheme进行拦截,把自定义协议赋值给IjkURLProtocol:

int ijkio_alloc_url(IjkURLContext **ph, const char *url) { if (!ph) { return -1; } IjkURLContext *h = NULL; if (!strncmp(url, "httphook:", strlen("httphook:"))) { h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext)); h->prot = &ijkio_httphook_protocol; h->priv_data = calloc(1, ijkio_httphook_protocol.priv_data_size); } else if (!strncmp(url, "decrypt:", strlen("decrypt:"))) { h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext)); h->prot = &ijkio_decrypt_protocol; h->priv_data = calloc(1, ijkio_decrypt_protocol.priv_data_size); } else { return -1; } *ph = h; return 0;} 7、查找自定义协议

在avformat_open_input时,会初始化input、打开avio、根据scheme查找对应协议,完整调用路径为init_input->avio_open2->ffurl_open->ffurl_alloc->url_find_protocol。在avio.c的查找协议过程为:

static const struct URLProtocol *url_find_protocol(const char *filename) { ...... 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); return NULL;}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。