当前位置:   article > 正文

ijkplayer自定义协议播放加密视频_ijkplayer 播放加密视频 ios

ijkplayer 播放加密视频 ios

FFmpeg实现http、https这些标准协议,但是要播放加密视频怎么办呢?ijkplayer在FFmpeg的libavformat模块进行扩展ijkio、ijklongurl、ijktcphook、ijkhttphook,我们也可以在这个基础上,自定义协议来进行解密播放。主要基于URLProtocol和AVClass进行扩展,实现protocol对应的方法。

 

 URLProtocol的结构体如下:

  1. typedef struct URLProtocol {
  2. const char *name;
  3. int (*url_open)(URLContext *h, const char *url, int flags);
  4. int (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);
  5. int (*url_accept)(URLContext *s, URLContext **c);
  6. int (*url_handshake)(URLContext *c);
  7. int (*url_read)(URLContext *h, unsigned char *buf, int size);
  8. int (*url_write)(URLContext *h, const unsigned char *buf, int size);
  9. int64_t (*url_seek)(URLContext *h, int64_t pos, int whence);
  10. int (*url_close)(URLContext *h);
  11. int priv_data_size;
  12. const AVClass *priv_data_class;
  13. const char *default_whitelist;
  14. } URLProtocol;

FFmpeg实现的标准协议有包括http、https、hls、tcp、rtmp等,如下图所示:

​​​​​​​ 

1、添加自定义协议

新建一个源文件ijkdecrypt.c放在libavformat,实现ijkdecrypt_open、ijkdecrypt_read、ijkdecrypt_seek、ijkdecrypt_close等方法,然后把方法注册到URLProtocol:

  1. static int ijkdecrypt_open(URLContext *h) {
  2. return decrypt_open(h);
  3. }
  4. static int ijkdecrypt_read(URLContext *h, unsigned char *buf, int size) {
  5. return decrypt_read(h, buf, size);
  6. }
  7. static int64_t decrypt_seek(URLContext *h, int64_t offset, int whence) {
  8. return decrypt_seek(h, offset, whence);
  9. }
  10. static int decrypt_close(URLContext *h) {
  11. return decrypt_close(h);
  12. }
  13. static const AVClass ijkio_context_class = {
  14. .class_name = "IjkDecrypt",
  15. .item_name = av_default_item_name,
  16. .option = options,
  17. .version = LIBAVUTIL_VERSION_INT,
  18. };
  19. URLProtocol ijkimp_ff_ijkio_protocol = {
  20. .name = "ijkdecrypt",
  21. .url_open2 = ijkdecrypt_open,
  22. .url_read = ijkdecrypt_read,
  23. .url_seek = ijkdecrypt_seek,
  24. .url_close = ijkdecrypt_close,
  25. .priv_data_size = sizeof(Context),
  26. .priv_data_class = &ijkio_context_class,
  27. };

2、声明自定义协议

修该libavformat/protocols.c,添加自定义协议并声明为全局变量:

extern const URLProtocol ff_ijkdecrypt_protocol;

在ffbuild/config.mak会自动生成CONFIG_FF_IJKDECRYPT_PROTOCOL

3、依赖自定义协议

在libavformat/makefile添加依赖文件:

OBJS-$(CONFIG_FF_IJKDECRYPT_PROTOCOL)             += ijkdecrypt.o

4、dummy自定义协议

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

IJK_DUMMY_PROTOCOL(ijkdecrypt);

dummy过程是生成AVClass和URLProtocol:

  1. #define IJK_DUMMY_PROTOCOL(x) \
  2. IJK_FF_PROTOCOL(x); \
  3. static const AVClass ijk_##x##_context_class = { \
  4. .class_name = #x, \
  5. .item_name = av_default_item_name, \
  6. .version = LIBAVUTIL_VERSION_INT, \
  7. }; \
  8. \
  9. URLProtocol ff_##x##_protocol = { \
  10. .name = #x, \
  11. .url_open2 = ijkdummy_open, \
  12. .priv_data_size = 1, \
  13. .priv_data_class = &ijk_##x##_context_class, \
  14. };

5、注册自定义协议

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

  1. void ijkav_register_all(void)
  2. {
  3. av_register_all();
  4. /* protocols */
  5. #ifdef __ANDROID__
  6. IJK_REGISTER_PROTOCOL(ijkmediadatasource);
  7. #endif
  8. IJK_REGISTER_PROTOCOL(ijkio);
  9. IJK_REGISTER_PROTOCOL(async);
  10. IJK_REGISTER_PROTOCOL(ijklongurl);
  11. IJK_REGISTER_PROTOCOL(ijktcphook);
  12. IJK_REGISTER_PROTOCOL(ijkhttphook);
  13. IJK_REGISTER_PROTOCOL(ijksegment);
  14. /* demuxers */
  15. IJK_REGISTER_DEMUXER(ijklivehook);
  16. IJK_REGISTER_DEMUXER(ijklas);
  17. }

IJK_REGISTER_PROTOCOL()对应的宏定义:

  1. #define IJK_REGISTER_PROTOCOL(x)
  2. { \
  3. extern URLProtocol ijkmp_ff_##x##_protocol; \
  4. int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size); \
  5. ijkav_register_##x##_protocol(&ijkimp_ff_##x##_protocol, sizeof(URLProtocol));\
  6. }

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

  1. int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size)
  2. {
  3. if (protocol_size != sizeof(URLProtocol)) {
  4. av_log(NULL, AV_LOG_ERROR, "ABI mismatch.\n");
  5. return -1;
  6. }
  7. memcpy(&ff_##x##_protocol, protocol, protocol_size);
  8. return 0;
  9. }

6、拦截自定义协议

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

extern IjkURLProtocol ijkio_decrypt_protocol;

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

  1. int ijkio_alloc_url(IjkURLContext **ph, const char *url) {
  2. if (!ph) {
  3. return -1;
  4. }
  5. IjkURLContext *h = NULL;
  6. if (!strncmp(url, "httphook:", strlen("httphook:"))) {
  7. h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext));
  8. h->prot = &ijkio_httphook_protocol;
  9. h->priv_data = calloc(1, ijkio_httphook_protocol.priv_data_size);
  10. } else if (!strncmp(url, "decrypt:", strlen("decrypt:"))) {
  11. h = (IjkURLContext *)calloc(1, sizeof(IjkURLContext));
  12. h->prot = &ijkio_decrypt_protocol;
  13. h->priv_data = calloc(1, ijkio_decrypt_protocol.priv_data_size);
  14. } else {
  15. return -1;
  16. }
  17. *ph = h;
  18. return 0;
  19. }

7、查找自定义协议

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

  1. static const struct URLProtocol *url_find_protocol(const char *filename) {
  2. ......
  3. protocols = ffurl_get_protocols(NULL, NULL);
  4. if (!protocols)
  5. return NULL;
  6. for (i = 0; protocols[i]; i++) {
  7. const URLProtocol *up = protocols[i];
  8. if (!strcmp(proto_str, up->name)) {
  9. av_freep(&protocols);
  10. return up;
  11. }
  12. if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
  13. !strcmp(proto_nested, up->name)) {
  14. av_freep(&protocols);
  15. return up;
  16. }
  17. }
  18. av_freep(&protocols);
  19. return NULL;
  20. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/949493
推荐阅读
相关标签
  

闽ICP备14008679号