DRM(数字权限管理技术)防截屏录屏----视频转hls流加密、web解密播放

提示:视频转hls流加密、web解密播放
需求:研究视频截屏时,播放器变黑,所以先研究的视频转hls流加密

文章目录

    • @[TOC](文章目录)
  • 前言
  • 一、工具ffmpeg、openssl
  • 二、后端node+express
  • 三、web播放
  • 四、文档
  • 总结

前言

‌HLS流媒体协议‌(HTTP Live Streaming)是苹果公司提出的一种基于HTTP的流媒体传输协议,主要用于音视频的实时传输和点播。HLS流媒体协议的核心优势在于其自适应比特率流式传输功能,可以根据网络条件的变化自动调整视频质量,确保视频流畅播放。‌

HLS流媒体协议的工作原理
1‌、编码和分段‌:HLS流媒体服务器将视频重新格式化为H.264或H.265编码,并将视频分割成几秒钟的片段。这些片段被组织成不同质量等级(如480p、720p和1080p),并创建索引文件记录它们的顺序。
2、分发‌:当客户端设备请求流时,已编码的视频片段通过互联网推送到客户端设备。通常,内容交付网络(CDN)可以协助将流分发到地理上不同的区域,并缓存流以加快传输速度。
3‌、客户端播放‌:客户端设备使用索引文件按顺序组装视频,并根据需要从更高质量影像切换到低质量影像(反之亦然)。自适应比特率流式传输使视频质量可以根据网络条件动态调整,确保视频流畅播放。

一、工具ffmpeg、openssl

ffmpeg安装教程
openssl安装教程

如有工具安装的问题,请查看上面安装教程

二、后端node+express

主要功能:生成加密密钥,视频加密生成hls流文件,提供返回密钥接口

index.js

const { exec } = require('child_process');
const express = require('express');
const crypto = require('crypto');
const path = require('path');
const cors = require('cors');
const fs = require('fs');

const app = express();
const port = 1990;

// 允许跨域
app.use(cors());
// 允许访问的request header配置
app.all('*',  (req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    // res.header('Access-Control-Allow-Headers', 'Content-Type');
    res.header("Access-Control-Allow-Headers", "Authorization,token,content-type");
    res.header('Access-Control-Allow-Methods', '*');
    res.header('Content-Type', 'application/json;charset=utf-8');
    next();
});
// 指定静态文件目录
app.use(express.static('public'));

// 返回生成的key(密钥)的值
app.get('/getkey', (req, res) => {
	/**	返回读取文件流数据
		const key = fs.readFileSync('./public/hls.key');
		res.set('Content-Type', 'application/octet-stream');
	 	res.send(key);**/
	
	// 直接返回存储key(密钥)的文件  这种方式需要指定静态文件目录
	res.sendFile(path.join(__dirname, 'public/hls.key'));
});

// 生成key(密钥)文件和加密用的keyinfo文件
const createKeyInfo = () => {
	/** 生成密钥文件(exec+openssl)
		exec('openssl rand -hex 16 > public/hls.key', (error, stdout, stderr) => {
		   if (error) {
		     console.error(`执行出错: ${error}`);
		     return;
		   }
		   if (stderr) {
		     console.error(`标准错误: ${stderr}`);
		     return;
		   }
		   console.log(`标准输出: ${stdout}`);
		   //这里在执行生成public/hls.keyinfo文件操作
		   fs.writeFileSync('public/hls.keyinfo',`http://localhost:1990/getkey\nD:/Project//nodeProject/express/express-kimi/Public/hls.key`);
		 });**/
		 
 	// 生成密钥文件(crypto+fs.write)
	const key = crypto.randomBytes(16).toString('hex');
	// 生成hls.key文件
	fs.writeFileSync('public/hls.key',key); 
	// 生产hls.keyinfo文件
	fs.writeFileSync('public/hls.keyinfo',`http://localhost:1990/getkey\nD:/Project/nodeProject/express/express-kimi/Public/hls.key`);

	
	
	// 视频通过生成的key(密钥)加密并生成hls流文件
	encryptionVideoToHls()
}

// 加密视频转hls
const encryptionVideoToHls = () => {
	/** 程序执行
		const ffmpeg = require('fluent-ffmpeg');
		const ffmpegInstaller = require('@ffmpeg-installer/ffmpeg');
		ffmpeg.setFfmpegPath(ffmpegInstaller.path);
		
		const proc = ffmpeg("input/test2.mp4")
			.addOption("-c:v", "copy")                              // 复制视频流
			.addOption("-hls_time", "100")                          // 片段时长/秒
			.addOption("-hls_list_size", "0")                       // 播放列表中的最大段数
			.addOption("-hls_key_info_file", "public/hls.keyinfo")  // 密钥信息文件
			.addOption("-hls_playlist_type", "vod")                 // 播放列表类型
			.addOption("-hls_segment_filename", "output/test%d.ts") // hls文件命名
			.addOption("-f", "hls")                                 // 输出格式
		
		proc.on('start', (data) => { console.log('Start: ' + data); });
		proc.on('error', (err) => { console.log('Error: ' + err); });
		proc.on('end', () => { console.log('Success!'); });
		
		proc.save('output/video.m3u8'); // 保存生成的hls文件 **/
		
		// cmd命令行执行
	    exec('ffmpeg -i input/test2.mp4 -y -c:v copy -hls_time 100 -hls_list_size 0 -hls_key_info_file public/hls.keyinfo -hls_playlist_type vod -hls_segment_filename output/test%d.ts -f hls output/video.m3u8', (error, stdout, stderr) => {
		  if (error)return console.error(`cmd Error: ${error}`);
		  if (stderr)return console.error(`ffmpeg Error: ${stderr}`);
		  console.log(`Success: ${stdout}`);
		});
}

(一) hls.keyinfo文件内容介绍

	/** hls.keyinfo文件内容
		1、hls.key的访问方式:
			接口:http://localhost:1990/getkey
			静态目录文件:http://localhost:1990/file.key
		2、hls.key的存放目录(绝对路径)
			D:/Project/nodeProject/express/express-kimi/Public/hls.key**/

(二)hls.keyinfo预览,两种方式都可以

1、接口形式:
在这里插入图片描述
2、静态目录文件形式:
在这里插入图片描述
(三)执行完成文件目录

node index.js

在这里插入图片描述

三、web播放

test.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test hls video play</title>
</head>

<body>
    <video id="video" src="" controls></video>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js"></script>
    <script>
	        var video = document.getElementById('video');
	        let videoUrl = 'source/video.m3u8';
	        if (Hls.isSupported()) {
	            var hls = new Hls();
	            hls.loadSource(videoUrl);
	            hls.attachMedia(video);
	            hls.on(Hls.Events.MANIFEST_PARSED, function () {
	
	            });
	        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
	            video.src = videoUrl;
	            video.addEventListener('loadedmetadata', function (e) {
	                console.log(e)
	            });
	        }
    </script>

</body>

</html>

播放成功
在这里插入图片描述
视频仅做测试使用,未进行任何商业用途, 遮挡一下看到播放效果即可,如有侵权,联系作者删除。

四、文档

Hls播放器cdn地址
Hls文档

总结

踩坑路漫漫长@~@

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924177.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Rk3588 onnx转rknn,出现 No module named ‘rknn‘

一、操作步骤&#xff1a; rk3588 需要将yolo11 的模型onnx转rknn。 https://github.com/airockchip/rknn_model_zoo/tree/main/examples/yolo11 这个是用yolo11训练的模型&#xff0c;有80种类型。 完整下载下来后&#xff0c;在按文档描述下载模型下来&#xff1a; 然后进…

IDEA 解决Python项目import导入报错、引用不到的问题

使用Idea 23.1 专业版编写Python项目时&#xff0c;import 导入爆红&#xff0c;无法引入其他package的代码&#xff0c;现象如&#xff1a; 解决方案&#xff1a;Idea表头打开 File -> Project Settring 解决效果&#xff1a;

unity 使用UI上的数字按钮,给text添加数字,并且显示光标,删除光标前数字,

今天有个需求&#xff0c;输入身份证&#xff0c;但是不用键盘&#xff0c;要点击按钮输入数字&#xff0c;并且可以控制光标&#xff0c; 1、数字按钮&#xff1a;点击后text添加数字内容 2、删除按钮&#xff1a;删除光标前的一个字符 3、左箭头&#xff1a;移动光标向左移动…

火山引擎VeDI在AI+BI领域的演进与实践

随着数字化时代的到来&#xff0c;企业对于数据分析与智能决策的需求日益增强。作为新一代企业级数据智能平台&#xff0c;火山引擎数智平台VeDI基于字节跳动多年的“数据驱动”实践经验&#xff0c;也正逐步在AI&#xff08;人工智能&#xff09;与BI&#xff08;商业智能&…

【逐行注释】自适应观测协方差R的AUKF(自适应无迹卡尔曼滤波,MATLAB语言编写),附下载链接

文章目录 自适应R的UKF逐行注释的说明运行结果部分代码各模块解释 自适应R的UKF 自适应无迹卡尔曼滤波&#xff08;Adaptive Unscented Kalman Filter&#xff0c;AUKF&#xff09;是一种用于状态估计的滤波算法。它是基于无迹卡尔曼滤波&#xff08;Unscented Kalman Filter&…

LLM应用-prompt提示:RAG query重写、相似query生成 加强检索准确率

参考&#xff1a; https://zhuanlan.zhihu.com/p/719510286 1、query重写 你是一名AI助手&#xff0c;负责在RAG&#xff08;知识库&#xff09;系统中通过重构用户查询来提高检索效果。根据原始查询&#xff0c;将其重写得更具体、详细&#xff0c;以便更有可能检索到相关信…

Spring Boot 与 Spring Cloud Alibaba 版本兼容对照

版本选择要点 Spring Boot 3.x 与 Spring Cloud Alibaba 2022.0.x Spring Boot 3.x 基于 Jakarta EE&#xff0c;javax.* 更换为 jakarta.*。 需要使用 Spring Cloud 2022.0.x 和 Spring Cloud Alibaba 2022.0.x。 Alibaba 2022.0.x 对 Spring Boot 3.x 的支持在其发行说明中…

如何通过PHP爬虫模拟表单提交,抓取隐藏数据

引言 在网络爬虫技术中&#xff0c;模拟表单提交是一项常见的任务&#xff0c;特别是对于需要动态请求才能获取的隐藏数据。在电商双十一、双十二等促销活动期间&#xff0c;商品信息的实时获取尤为重要&#xff0c;特别是针对不断变化的价格和库存动态。为了满足这种需求&…

嵌入式Qt使用ffmpeg视频开发记录

在此记录一下Qt下视频应用开发的自学历程&#xff0c;可供初学者参考和避雷。 了解常用音频格式yuv420p、h264等了解QML&#xff0c;了解QVideoOutput类的使用&#xff0c;实现播放yuv420p流参考ffmpeg官方例程&#xff0c;调用解码器实现h264解码播放 不需要手动分帧。ffmpeg…

Java设计模式笔记(一)

Java设计模式笔记&#xff08;一&#xff09; &#xff08;23种设计模式由于篇幅较大分为两篇展示&#xff09; 一、设计模式介绍 1、设计模式的目的 让程序具有更好的&#xff1a; 代码重用性可读性可扩展性可靠性高内聚&#xff0c;低耦合 2、设计模式的七大原则 单一职…

dns 服务器简单介绍

dns 服务器分类&#xff1a; 根域名服务器顶级域名服务器权威域名服务器本地域名服务器 dns 的查询过程 国内优秀公共域名 腾讯&#xff1a;DNSPod-免费智能DNS解析服务商-电信_网通_教育网,智能DNS-烟台帝思普网络科技有限公司 119.29.29.29 和 182.254.118.118 阿里&#xf…

vscode中json文件的注释飘红

vscode的json文件 添加注释&#xff0c;提示json中不允许有注释&#xff0c;点编辑器最下面的json&#xff0c;如下图 然后选择如上图的json with comments就好了

AI PAC!PLC与AIPC通过微定制深度融合助力工业场景下人工智能的落地!

一&#xff0c;前言 科技日益发展&#xff0c;总是会诞生出一些新应用和新场景&#xff0c;而这些场景一开始可能并没有对应的解决方案&#xff0c;这个时候就需要定制化的开发来适应新需求&#xff0c;而硬件的定制开发更为头疼&#xff0c;硬件开发设计到外观设计、结构设计、…

Python多进程/多线程通信实例

Python多进程/多线程通信实例 1. 多进程/多线程 多线程的定义 多线程&#xff08;Multithreading&#xff09; 是一种并发执行的编程技术&#xff0c;在一个进程内创建和管理多个线程&#xff0c;每个线程可以独立执行任务。线程是进程中的一个执行单元&#xff0c;多个线程共…

数据结构(Java)—— ArrayList

1.线性表 线性表&#xff08; linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。但是在…

【Qt】重写QComboBox下拉展示多列数据

需求 点击QComboBox时&#xff0c;下拉列表以多行多列的表格展示出来。 实现 直接上代码&#xff1a; #include <QComboBox> #include <QTableWidget> #include <QVBoxLayout> #include <QWidget> #include <QEvent> #include <QMouseEve…

NVR录像机汇聚管理EasyNVR多个NVR同时管理基于B/S架构的技术特点与能力应用

EasyNVR视频融合平台基于云边端协同设计&#xff0c;能够轻松接入并管理海量的视频数据。该平台兼容性强、拓展灵活&#xff0c;提供了视频监控直播、录像存储、云存储服务、回放检索以及平台级联等一系列功能。B/S架构使得EasyNVR实现了视频监控的多元化兼容与高效管理。 其采…

了解网络威胁情报:全面概述

网络威胁情报 CTI 是指系统地收集和分析与威胁相关的数据&#xff0c;以提供可操作的见解&#xff0c;从而增强组织的网络安全防御和决策过程。 在数字威胁不断演变的时代&#xff0c;了解网络威胁情报对于组织来说至关重要。复杂网络攻击的兴起凸显了制定强有力的策略以保护敏…

linux运行vue编译后的项目

如果你的 Vue 项目使用了 history 模式&#xff08;而非默认的 hash 模式&#xff09;&#xff0c;在纯静态服务器中会出现类似的问题。因为 Vue Router 的 history 模式要求所有未匹配的路径都重定向到 index.html&#xff0c;以便 Vue 前端处理路径。 首先在本地执行npm run…

基础入门-Web应用架构类别源码类别镜像容器建站模版编译封装前后端分离

知识点&#xff1a; 1、基础入门-Web应用-搭建架构上的技术要点 2、基础入门-Web应用-源码类别上的技术要点 一、演示案例-架构类别-模版&分离&集成&容器&镜像 1、套用模版型 csdn / cnblog / github / 建站系统等 安全测试思路上的不同&#xff1a; 一般…