文章目录
- 学习链接
- 步骤
- 安装openssl
- 生成一个enc.key文件
- 生成加密串
- 创建enc.keyinfo文件
- 视频切分
- m3u8文件
- web前端查看m3u8视频
- 后台返回enc.key的接口
- videojs播放m3u8视频
- 其它
- videojs切换播放视频
- hls.js切换播放视频
- dplayer切换播放视频(弹幕)
学习链接
Java实现视频加密及播放
使用ffmpeg视频切片并加密
mp4视频分片生成m3u8流文件并加密
html中 videojs 播放m3u8文件【方式一】
html中 DPlayer 播放m3u8文件【方式二】
vue播放播放M3U8格式——HLS的直播流
Vue Video.js播放m3u8视频流格式(video+videojs-contrib-hl)
vue中使用video标签播放MP4,m3u8格式视频
步骤
安装openssl
参考:Security OAuth2 授权 & JWT 中安装openssl部分、安装OpenSSL
下载 openssl安装包,一般下载列表第1个EXE即可(不带light的是完整功能的安装包,我们用不到),下载完成后双击安装一直点下一步就行了。
配置环境变量,老生常谈,openssl的默认安装路径为C:\Program Files\OpenSSL-Win64\bin,这里有windows配置环境变量的通用教程,最后我们验证下是否配置成功openssl -v 或者 openssl version。
centos7安装openssl:sudo yum install pcre-devel openssl openssl-devel -y
生成一个enc.key文件
生成一个enc.key文件,license与windows指令相同
生成加密串
生成加密串(b6dc7333568a0deef8e6b331b9725264
),记下来
创建enc.keyinfo文件
新建一个文件 enc.keyinfo 内容格式如下:
Key URI # enc.key的路径,使用http形式
Path to key file # enc.key文件
IV # 上面生成的iv
示例
http://localhost/video/enc.key
enc.key
b6dc7333568a0deef8e6b331b9725264
视频切分
视频切分,传一个test.mp4到enc.key路径下,通过黑窗口执行下面的指令
ffmpeg -y -i test.mp4 -hls_time 12 -hls_key_info_file enc.keyinfo -hls_playlist_type vod -hls_segment_filename "file%d.ts" playlist.m3u8
- 解释
ffmpeg -y \ -i test.mp4 \ -hls_time 12 \ # 将test.mp4分割成每个小段多少秒 -hls_key_info_file enc.keyinfo \ -hls_playlist_type vod \ # vod 是点播,表示PlayList不会变 -hls_segment_filename "file%d.ts" \ # 每个小段的文件名 playlist.m3u8 # 生成的m3u8文件
m3u8文件
这个URI路径可以修改,只要能返回enc.key的数据就行了
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:50
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-KEY:METHOD=AES-128,URI="http://localhost/video/enc.key",IV=0xb6dc7333568a0deef8e6b331b9725264
#EXTINF:50.000000,
file0.ts
#EXTINF:50.000000,
file1.ts
#EXTINF:14.600000,
file2.ts
#EXT-X-ENDLIST
web前端查看m3u8视频
后台返回enc.key的接口
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.maxAge(3600)
.allowCredentials(true)
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.exposedHeaders("token","Authorization")
;
}
}
videojs播放m3u8视频
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>videojs-contrib-hls embed</title>
<!--
Uses the latest versions of video.js and videojs-contrib-hls.
To use specific versions, please change the URLs to the form:
-->
<link href="https://unpkg.com/video.js@5.16.0/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@5.16.0/dist/video.js"></script>
<script src="https://unpkg.com/videojs-contrib-hls@4.1.1/dist/videojs-contrib-hls.js"></script>
</head>
<body>
<h1>Video.js Example Embed</h1>
<video id="my_video_1"
class="video-js vjs-default-skin"
controls preload="auto" width="640" height="268"
data-setup='{}'>
<source
src="./video/playlist.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>
当未提供enc.key的文件时,报错
直接修改m3u8的URI也是没问题的,只要后台改了就行
其它
videojs切换播放视频
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>videojs-contrib-hls embed</title>
<!--
Uses the latest versions of video.js and videojs-contrib-hls.
To use specific versions, please change the URLs to the form:
-->
<link href="https://unpkg.com/video.js@5.16.0/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@5.16.0/dist/video.js"></script>
<script src="https://unpkg.com/videojs-contrib-hls@4.1.1/dist/videojs-contrib-hls.js"></script>
</head>
<body>
<h1>Video.js Example Embed</h1>
<video id="my_video_1"
class="video-js vjs-default-skin"
controls preload="auto" width="640" height="268"
data-setup='{}'>
<source src="./video1/playlist.m3u8" type="application/x-mpegURL">
</video>
<hr>
<button id="video1" onclick="videoHandler(event)" data-videourl="./video1/playlist.m3u8">视频1</button>
<button id="video2" onclick="videoHandler(event)" data-videourl="./video2/index.m3u8">视频2</button>
<button id="video3" onclick="videoHandler(event)" data-videourl="http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8">失效的url</button>
<button onclick="pause()">暂停</button>
<button onclick="play()">播放</button>
<button onclick="destroy()">关闭</button>
<script>
const playerOptions = {
autoplay: false, // 自动播放
controls: true, // 显示控制条
errorDisplay: false, // 隐藏错误提示
muted: true, // 静音
sources: [
{
// src: "./video1/playlist.m3u8",
src: "./video2/index.m3u8",
type: "application/x-mpegURL",
},
],
};
var player = videojs(document.querySelector('#my_video_1'), playerOptions, () => {
console.log("Video.js player is ready");
})
function videoHandler(e) {
const videoUrl = e.target.dataset.videourl;
player.src({
src: videoUrl,
type: "application/x-mpegURL",
});
player.load(); // 重新加载视频
// player.play(); //
}
player.on("error", (event) => {
console.error("Error:", event.error);
player.src({
src: './video2/index.m3u8',
type: "application/x-mpegURL",
});
});
player.on("play", (event) => {
console.log('play', event); // 开始播放和每次点击播放进度条时都会触发
});
player.on("ended", (event) => {
console.log('ended', event); // 播放结束
});
function pause() {
player.pause(); // 暂停
}
function play() {
player.play(); // 继续播放
}
function destroy() {
player.dispose(); // 关闭 , video这个dom都被删除了
player = null
}
</script>
</body>
</html>
hls.js切换播放视频
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="video" width="640" height="268" controls></video>
<hr />
<button id="video1" onclick="videoHandler(event)" data-videourl="./video1/playlist.m3u8">视频1</button>
<button id="video2" onclick="videoHandler(event)" data-videourl="./video2/index.m3u8">视频2</button>
<button onclick="playVideo()">播放</button>
<button onclick="pauseVideo()">暂停</button>
</body>
<script>
var video = document.getElementById('video');
if (Hls.isSupported()) {
// 可参考:
// hls的github文档中的api:(https://github.com/video-dev/hls.js/blob/master/docs/API.md)
// hls.js如何播放m3u8文件(实例)?(https://blog.csdn.net/ffffffff8/article/details/129314268)
// Vue 之 视频流 - Hls.js(https://blog.csdn.net/a15297701931/article/details/115478652)
let config = {
xhrSetup: function (xhr, url) {
xhr.withCredentials = true; // 会携带cookie
// 在请求http://127.0.0.1:5500/video2/index.m3u8时会携带token请求头
// 在请求http://127.0.0.1:5500/video2/index000.ts时会携带token请求头
xhr.setRequestHeader('token', "my-token")
},
}
var hls = new Hls(config);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
console.log('MANIFEST_PARSED');
// video.play(); // Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD
});
hls.loadSource('./video2/index.m3u8');
hls.attachMedia(video);
function playVideo() {
video.play()
}
function pauseVideo() {
video.pause()
}
function videoHandler(e) {
console.log(e.target.dataset.videourl);
hls.loadSource(e.target.dataset.videourl);
hls.attachMedia(video);
}
}
// HLS.js is not supported on platforms that do not have Media Source
// Extensions (MSE) enabled.
//
// When the browser has built-in HLS support (check using `canPlayType`),
// we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video
// element through the `src` property. This is using the built-in support
// of the plain video element, without using HLS.js.
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
}
</script>
</html>
dplayer切换播放视频(弹幕)
-
可以切换视频,可以发送弹幕(发送完弹幕后,可以在本地显示,可以调用dp.danmaku.send(danmaku, callback: function): 提交一个新弹幕,后面可以使用websoket将代码发到其它观看此视频的用户)
-
必须引入DPlayer.min.css,否则弹幕无法正常显示
-
有个问题:按照官网设置的danmaku的token,但是在请求弹幕接口的时候没有携带这个请求头,不知道该问题的原因(哦,原来是发送弹幕的时候,会携带这个danmaku.token参数到Request Payload中,我还以为请求弹幕的时候,也得带呢)
-
弹幕的格式:每条弹幕都是1个数组,数组中按顺序依次是:time-时间,type-类型,color-颜色,author-发送者,text-内容
-
弹幕返回的示例可以参考,
https://s-sh-17-dplayercdn.oss.dogecdn.com/1678963.json
:{ "code": 0, "data": [ [ 230.523, 0, 16777215, "618c713c", "键盘妹子挺好看?" ], [ 25.837, 0, 16777215, "6b2884ac", "Goose house炒鸡棒!!! 银之匙种草他们组合" ], [ 235.243, 1, 16707842, "929815d3", "刚才说比其他翻唱都好听的你是认真的么,这。就是原唱" ], [ 86.841, 0, 16777215, "6f30afd1", "喜欢短发的" ] ] }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
margin: 0;
}
.dplayer-container {
width: 800px;
height: 500px;
border: 5px solid red;
display: flex;
align-items: center;
justify-content: center;
}
#dplayer {
width: 100%;
height: 100%;
object-fit: cover;
border: 5px solid black;
}
</style>
<!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/npm/dplayer@1.27.1/dist/DPlayer.min.js"></script> -->
<link rel="stylesheet" href="./css/DPlayer.min.css">
<script src="./js/hls.js"></script>
<script src="./js/dplayer.js"></script>
</head>
<body>
<div class="dplayer-container">
<div id="dplayer"></div>
</div>
<hr />
<button id="video1" onclick="videoHandler(event)" data-videourl="./video1/playlist.m3u8">视频1</button>
<button id="video2" onclick="videoHandler(event)" data-videourl="./video2/index.m3u8">视频2</button>
<button onclick="playVideo()">播放</button>
<button onclick="pauseVideo()">暂停</button>
<script>
// 另一种方式,使用 customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
autoplay: false, // 自动播放
video: {
url: './video1/playlist.m3u8',
type: 'customHls',
pic: './soft-dev.png', // video的poster属性, 视频封面
customType: {
customHls: function (video, player) {
let config = {
xhrSetup: function (xhr, url) {
xhr.withCredentials = true; // 会携带cookie
xhr.setRequestHeader('token', "my-token")
},
}
const hls = new Hls(config);
hls.loadSource(video.src);
hls.attachMedia(video);
},
},
/* quality: [ // 清晰度
{
name: '标清哦',
url: './video1/playlist.m3u8',
type: 'customHls',
},
{
name: '高清哦',
url: './video2/index.m3u8',
type: 'customHls',
},
],
defaultQuality: 0, */
},
volume: 1, // 默认音量
playbackSpeed: [0.5, 1, 1.25, 1.5, 2], // 可选的播放速率,可以设置成自定义的数组
lang: 'zh-cn', // 显示为中文
loop: true, // 是否循环播放
hotkey: true, // 开启热键,支持快进、快退、音量控制、播放暂停
screenshot: true, // 开启截图功能
theme: 'orange', // 进度条颜色
logo: 'naughty.gif', // 左上角logo
preventClickToggle: false, // 阻止点击播放器时候自动切换播放/暂停
contextmenu: [ // 右键视频时的菜单
{
text: 'custom1',
link: 'https://github.com/DIYgod/DPlayer',
},
{
text: 'custom2',
click: (player) => {
console.log(player);
},
},
],
highlight: [ // 视频进度条上的高亮点
{
time: 20,
text: '这是第 20 秒',
},
{
time: 60,
text: '这是 1 分钟',
},
],
danmaku: {
id: './video1/playlist.m3u8',
user: 'user1',
token: 'tokendemo',
// 这个api会发送1个请求: http://localhost:82/barrage/v3/?id=./video1/playlist.m3u8
api: 'http://localhost:82/barrage/', //这里填写弹幕地址 liveweb
addition: ['https://s-sh-17-dplayercdn.oss.dogecdn.com/1678963.json']
}
});
dp.danmaku.token = 'tokendemo';
// 视频切换
function videoHandler(e) {
console.log(e.target.dataset.videourl);
dp.switchVideo(
// 指定视频设置
{
url: e.target.dataset.videourl,
pic: '',
},
// 指定弹幕设置
{
id: e.target.dataset.videourl,
api: 'http://localhost:82/barrage/',
maximum: 3000,
user: 'DIYgod',
}
)
}
function playVideo() {
dp.play()
}
function pauseVideo() {
dp.pause()
}
Window.dp = dp;
</script>
</body>
</html>