当前位置: 首页 > news >正文

ijkplayer 自定义协议播放加密内容 Android

想对播放的音视频进行加密,防止资源被盗用,该怎么办呢?

这篇文章从自定义协议的角度来提供一中实现思路。在 ijkplayer 的基础上,通过实现自定义协议对文件进行解密。边解边播,以此为基础,还可以实现在线资源边下载边解密边播放。

结合 ijkplayer 源码阅读本文效果最佳。

FFmpeg 文件协议

ffmpeg 中定义了 URLProtocol, 对接入 ffmpeg 中的各种协议进行了统一的抽象,这里可以理解为 C++ 中的抽象基类,并基于此抽象协议实现了 file、http、ftp、cache 等许多不同的具体文件传输协议。
而在 libavformat 模块中的 avio.c aviobuf.c 两个文件则是在 ffmpeg 对文件传输协议抽象的基础上进行的封装,使对文件的操作能够在 ffmpeg 中其他对文件协议细节不关心的地方使用。这就好比是面向对象中的模版模式。
ffmpeg 中的文件协议简单讲就是这样,更深入复杂的我也还没具体研究,本文中也用不到。

URLProtocol 的部分代码如下,这里我只留下了最常用的一部分。URLProtocol 中定义了很多函数指针,在 avio.c 的模板模式代码中用到。

 

代码解读

复制代码

typedef struct URLProtocol { const char *name; int (*url_open)( URLContext *h, const char *url, int flags); 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; } URLProtocol;

通过实现 URLProtocol 中的函数指针,就完成了一个可以用在 ffmpeg 中的文件协议。比如我找了一番 ffmpeg 中一个比较简单的文件协议,从实现上可以看出这个 bluray 在ffmpeg 中是一个只读协议。

 

代码解读

复制代码

const URLProtocol ff_bluray_protocol = { .name = "bluray", .url_close = bluray_close, .url_open = bluray_open, .url_read = bluray_read, .url_seek = bluray_seek, .priv_data_size = sizeof(BlurayContext), .priv_data_class = &bluray_context_class, };

ffmpeg 中通过一个列表保存了所有实现了的文件协议,进行各种文件操作的第一步,就是先根据 url(filename)找到对应的 URLProtocol。这段代码中通过匹配 url 中的 scheme 字符串,找到并返回对应的 protocol 指针。

 

代码解读

复制代码

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

如果对 ffmpeg 有一定的了解,可能会知道  ffmpeg 中的 Codec 还有 avcodec_register。FFmpeg 通过接口 avcodec_register 在运行时动态添加编解码器。但是却没有类似的 avformat_register 或者 av_urlprotocol_register 来实现运行时动态注册自定义的 protocol。为什么不实现这个的原因没有研究过,所以不能瞎吹。但是我们可以改 ffmpeg 源代码呀。

ijkplayer 的作者就改了 ffmpeg ,新增了几个 URLProtocol 并加入到了默认的 protocols 数组中,这些新增的 protocols 在 ffmpeg 源码中默认是空的实现。但是在 ffmpeg 中预留了接口可以在 ijkplayer 中使用后期实现的 protocol 替换这个空的 protocol。相当于添加了作用类似于 av_urlprotocol_register 但是有一定限制的接口。

ijkmediadatasource 协议实现

在 ijkplayer 项目的 ijkmediadatasource.c 源文件中,实现了一种 URLProtocol

 

代码解读

复制代码

URLProtocol ijkimp_ff_ijkmediadatasource_protocol = { .name = "ijkmediadatasource", .url_open2 = ijkmds_open, .url_read = ijkmds_read, .url_seek = ijkmds_seek, .url_close = ijkmds_close, .priv_data_size = sizeof(Context), .priv_data_class = &ijkmediadatasource_context_class, };

在每个具体的函数指针实现中,又通过 J4A 生成的胶水代码去调用到 java 层的代码。
进一步解释一下, setDataSource 的时候调用到这一块代码,callback 已经是一个具体的 java 对象了,并且是一个 tv/danmaku/ijk/media/player/misc/IMediaDataSource 接口的具体实现。

 

代码解读

复制代码

IjkMediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject callback) { nativeMediaDataSource = jni_set_media_data_source(env, thiz, callback); snprintf(uri, sizeof(uri), "ijkmediadatasource:%"PRId64, nativeMediaDataSource); retval = ijkmp_set_data_source(mp, uri); }

jni_set_media_data_source 函数新建一个 NDK 环境对 callback 这个 jobject 的全局引用,并把引用作为 intptr_t 类型保存在 IjkMediaPlayer 的 mNativeMediaDataSource 字段中,方便后面再次使用以及最后需要close 是用到。 通过这样的转换之后,url 进入 ffmpeg  avformat 逻辑中就成了 “ijkmediadatasource:2234234290" 这样的形式。 再通过 url_find_protocol 找到  ijkimp_ff_ijkmediadatasource_protocol ,所有的对这个文件协议的操作又回到 ijkplayer 的代码中了。
在 ijkmds_open  中,只需要把 intptr_t 的变量转换成 jobject 就行,不必实际去打开某个文件。 ijkmds_read 、 ijkmds_seek  函数通过 J4A 去调用  IMediaDataSource 接口的 readAt 方法。 readAt 方法多了 pos 参数,所以 read 和 seek 都可以通过 readAt 实现, ijkmds_close  调用 IMediaDataSource 接口的 close 方法,并释放 NDK 环境中的 jobject 全局引用。

通过这一层套一层的接口定义实现、struct 函数指针定义实现, java 代码中设置的 dataSource 在 ijkplayer 、ffmpeg 中打了个转之后最终又回到 java 代码中。

jni4android 自动生成代码

jni4android 是 B 站出品的开源项目 github.com/bilibili/jn…。能够根据简单的 java 接口描述代码生成 ndk 胶水代码,方便在 ndk c/c++ 环境中调用 java 代码。
ijkmediadatasource.c 源文件中 JNI 相关调用的代码,都是 j4a 自动生成的。按照 jni4android 中 readme 编译好 j4a 之后,结合 ijkplayer/ijkmedia/j4a  中的 makefile 文件,就可以快速掌握 j4a 在 ijkplayer 中的作用和使用方法了。

加密和解密

前面代码分析中解释了 ijkplayer 中自定义文件协议到底是怎么一回事,以及其中的函数调用过程怎么样的。
分析完了,终于可以开始代码敲起来。我们先对一个视频文件加密,然后实现解密的文件协议并在播放中使用。

这里采用古老的凯撒加解密算法,加密过程就是每个 byte 加个数字,解密过程就是每个 byte 减去个数字。相当简单,很容易暴力破解,这里仅作为示例参考。

加密过程如下(截取部分代码):

 

代码解读

复制代码

func main() { ibuf := bufio.NewReader(inputfile) obuf := bufio.NewWriter(outputfile) buf := make([]byte, 128) for { n, err := ibuf.Read(buf) if err == nil { for index := 0; index < n; index++ { buf[index] = buf[index] + byte(cck) } obuf.Write(buf[:n]) } else if err == io.EOF { break } } obuf.Flush() }

解密的 java IMediaDataSource 实现如下,这里只给出关键部分,其他的和项目中 FileMediaDataSource 一样。

 

代码解读

复制代码

public class CCFileMediaDataSource implements IMediaDataSource { @Override public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { if (mFile.getFilePointer() != position) mFile.seek(position); if (size == 0) return 0; int s = mFile.read(buffer, 0, size); for (int i = 0; i < s; i++) { buffer[i] = (byte)(buffer[i] - 10); } return s; } }

什么情况下会用到 CCFileMediaDataSource 呢? 简单粗暴,把项目中 IjkVieoView.java 用到 FileMediaDataSource 的地方都改成 CCFileMediaDataSource,其实也没几处,然后别忘了在 demo 中设置选项里选中使用MediaDataSource。

IMediaDataSource 其他实现

RandomAccessFile 实现的 IMediaDataSource, 支持本地保存的文件。

 

代码解读

复制代码

public class FileMediaDataSource implements IMediaDataSource { private RandomAccessFile mFile; private long mFileSize; public FileMediaDataSource(File file) throws IOException { mFile = new RandomAccessFile(file, "r"); mFileSize = mFile.length(); } @Override public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { if (mFile.getFilePointer() != position) mFile.seek(position); if (size == 0) return 0; return mFile.read(buffer, 0, size); } @Override public long getSize() throws IOException { return mFileSize; } @Override public void close() throws IOException { mFileSize = 0; mFile.close(); mFile = null; } }

InputStream 实现的 IMediaDataSource,可以用于播放 asset 资源文件

 

代码解读

复制代码

public class StreamDataSource implements IMediaDataSource { private InputStream mIs; private long mPosition = 0; public StreamDataSource(InputStream mIs) { this.mIs = mIs; } @Override public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { if (size <= 0) return size; if (mPosition != position) { mIs.reset(); mPosition = mIs.skip(position); } int length = mIs.read(buffer, offset, size); mPosition += length; return length; } @Override public long getSize() throws IOException { return mIs.available(); } @Override public void close() throws IOException { if (mIs != null) mIs.close(); mIs = null; } }

 

代码解读

复制代码

AssetManager assetManager = mContext.getAssets(); InputStream is = assetManager.open("asset_file_path", AssetManager.ACCESS_RANDOM); mIjkMediaPlayer.setDataSource(new StreamDataSource(is));

相关文章:

ijkplayer 自定义协议播放加密内容 Android

想对播放的音视频进行加密&#xff0c;防止资源被盗用&#xff0c;该怎么办呢&#xff1f; 这篇文章从自定义协议的角度来提供一中实现思路。在 ijkplayer 的基础上&#xff0c;通过实现自定义协议对文件进行解密。边解边播&#xff0c;以此为基础&#xff0c;还可以实现在线资…...

【kill】Centos/Linux 如何杀死那该死的进程?

简介 系统版本&#xff1a;Centos7.6 kill 命令发送指定的信号到指定的进程或者进程组。如果该信号没有指定&#xff0c;则发送SIGTERM信号&#xff08;15&#xff09;&#xff0c;即终止信号。如果SIGTERM信号&#xff08;15&#xff09;无法终止&#xff0c;可使用SIGKILL&am…...

Cadence23学习笔记(十七)

吴老师的网站里面有很多cadence的开源项目&#xff0c;可以用来学习&#xff1a; 全志 H3 SOC 官方参考设计 DD3 16bitX2 原理图及PCB – 吴川斌的博客 (mr-wu.cn) cadence设置显示实时的走线长度&#xff1a; 在allegro进行布线时可以实时显示当先布线的实际长度有助于pcb的…...

WinFrom调用webapi接口方法及其应用实例

1.WinFrom调用webapi接口方法 最近项目要在winfrom项目中调用webAPI&#xff0c;故在网上查找资料&#xff0c;找到了一个WinFrom调用webapi接口的通用方法&#xff0c;关键代码&#xff1a; #region WinFrom调用webapi接口通用方法private async Task<string> InvokeWe…...

智能巡检企业级域名 SSL 证书

一、概述 SSL 证书是一种数字证书&#xff0c;用于在用户和服务器之间建立加密链接&#xff0c;确保数据传输的安全性&#xff0c;防止数据在传输过程中被截获或篡改。SSL 证书不仅保护了数据传输过程中的隐私和完整性&#xff0c;还可以帮助验证网站的身份&#xff0c;防止钓…...

海思35XX系列(三)sensor(传感器)

刚开始接触这个概念的时候感觉比较模糊&#xff0c;简单记录一下吧 Sensor&#xff08;传感器&#xff09;是一种可以感知外部环境并将感知到的信息转化为可用的电信号或其他形式的工具。传感器广泛应用于电子设备、工业自动化、汽车、医疗器械等领域&#xff0c;用于测量、监…...

dfs(续做)

1.混境之地5 #include<bits/stdc.h> using namespace std; typedef long long ll; const int dx[4] {0,1,0,-1}; const int dy[4] {1,0,-1,0}; int n,m,k,a,b,c,d,sign0; int h[1010][1010],visit[1010][1010]; void dfs(int x,int y,bool used) {if(xc&&yd){si…...

OpenStack;异构算力网络架构;算力服务与交易技术;服务编排与调度技术

目录 OpenStack 一、OpenStack概述 二、OpenStack的主要组件及功能 三、OpenStack的架构 四、OpenStack的应用场景 异构算力网络架构 算力服务与交易技术 服务编排与调度技术 OpenStack 是一个开源的云计算管理平台项目,由NASA(美国国家航空航天局)和Rackspace合作…...

PLC-Recorder对于数据采集时间戳偏差的修正功能

目录 一、修正原理 二、使用步骤 1、初始状态&#xff0c;计算修正系数 2、启动和使用 3、修正系数的手动修改 三、修正前后的效果对比 1、修正前的时间偏差曲线 2、修正后的效果曲线 四、注意事项 1、控制器可能的时钟波动 2、平移参数评估 3、参数保存 五、关于…...

自定义监控

代码说明&#xff1a; 导入必要的库 import time import psutil import GPUtil from prometheus_client import start_http_server, Summary, Counter, Gaugepsutil&#xff1a;用于获取系统的CPU、内存、磁盘和网络信息。GPUtil&#xff1a;用于获取GPU信息。prometheus_cli…...

关于使用php的mpdf插件遇到的一些问题

一.插件版本 "mpdf/mpdf": "^8.0", 二.报错&#xff1a;Undefined index: list_style_type 这个是插件无法识别 li 标签导致&#xff0c;生成pdf是加入下面代码 <style> li { list-style-type: none; list-style-image: none; list-style-positi…...

电脑截图,颜色变淡的问题解决

解决 Windows 11 在 HDR 模式下截图 Edge 浏览器界面时画面过曝的问题-腾讯云开发者社区-腾讯云 (tencent.com) 主要是浏览器用错了东西&#xff0c;调一下就好&#xff0c;详情看链接 联想拯救者y9000p为例&#xff0c;选择sRGB&#xff0c;就好啦&#xff0c;拜拜喽&#x…...

uniApp跳转外链

创建一个新的页面&#xff0c;在该页面中使用web-view组件加载外部URL&#xff1a;pages/web-view/web-view <template><view><uni-list><uni-list-itemtitle"打开外部链接"click"openExternalLink"></uni-list-item></…...

科技云报道:大模型引领技术浪潮,AI安全治理面临“大考”

科技云报道原创。 从文生文到文生图&#xff0c;再到文生视频&#xff0c;近年来&#xff0c;以ChatGPT、Sora等为代表的大模型引领了全球人工智能技术与产业的新一轮浪潮。2024年更是被业内称为大模型应用爆发元年。 年初&#xff0c;Sora横空出世验证了Scalling Law在视频生…...

SpringSecurity+Mysql数据库实现用户安全登录认证

Spring Security 是一个提供身份认证、授权和防范常见攻击的安全权限框架。无论是对命令式&#xff0c;还是响应式web应用程序都完美支持&#xff0c;现在主要用作保护基于 Spring 框架的应用程序的事实标准。相对于shiro来说&#xff0c;SpringSecurity功能更加复杂而且更加强…...

虚拟网卡添加ip

1.虚拟机网卡添加 1.进入虚拟机设置添加网卡即网络适配器 2.配置文件修改 1.查看网卡是否添加成功 ip ad ifconfig 其中ens161就是我们新添加的设备同时这个ens161也是我们硬件名字 2.进入系统配置文件 cd /etc/sysconfig/network-scripts/#配置文件目录[rootlocalhost ne…...

Unity向量线性插值Lerp

inline glm::vec3 Lerp(glm::vec3 start, glm::vec3 end, float t){t glm::clamp(t, 0.0f, 1.0f);return (start*(1-t)end*t); }...

fatal: Could not read from remote repository. 解决方法

问题描述&#xff1a; Git : fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists。 解决方法&#xff1a; 当在网上尝试大量方法仍然失败的时候&#xff0c;不妨试试这个方法。 在 github 上&…...

postman查询单条数据Get方法,无任何输出,idea后端也没有任何数据和提示的解决方法

问题描述&#xff1a; 正常使用postman测试&#xff0c;输入内容没有错误&#xff0c;但是却没有任何消息 后端也是&#xff0c;没有任何消息&#xff1a; 解决方法&#xff1a; 问题的原因主要是因为postman&#xff1a; 我们只需要新建一个页面&#xff0c;把刚才的查询语…...

query怎么改写,才能实现高质量的知识问答系统

为了实现高质量的知识问答系统&#xff0c;query改写需要综合利用多种技术&#xff0c;确保改写后的查询更具语义性、准确性和完整性。以下是具体的步骤和方法&#xff1a; 1. 同义词和短语替换 步骤&#xff1a; 建立同义词库&#xff1a;使用现有的同义词词典或根据特定领…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...