Hls.js播放m3u8视频 DPlayer视频播放器(easypan) MSE简介
文章目录
- 学习链接
- hls.js播放m3u8视频
- 效果
- 代码
- 前端代码
- 安装hls.js
- App.vue
- 后台代码
- 准备文件
- mp4文件切片java实现
- TsController
- TsService
- DPlayer播放m3u8视频
- 效果
- 扩展内容:MSE(Media Source Extensions)介绍
- 1 概述
- 2 why MSE
- 代码
- 安装依赖
- App.vue
学习链接
vue3项目实战 仿百度网盘
hls的github文档中的api详细说明
hlsjs-dev官方的demo演示
hls播放m3u8 添加header请求头,在请求ts的url上添加参数
Vue 之 视频流 - Hls.js
hls.js如何播放m3u8文件(实例)
网页前端video播放m3u8(HLS)
ffmpeg 视频ts切片生成m3u8
mp4视频分片生成m3u8流文件并加密,
Java使用FFmpeg(自定义cmd)系列之官方API获取视频/音频信息(URL方式)
Java使用FFmpeg(自定义cmd)系列之MP4 转码 HLS m3u8 AES128 加密(源码已保存在gitee上)
这个加密后面可以试一下,因为分片完,前端随便拿一个分片,这个分片单独保存下来使用vlc播放器也是可以播放的
Spring boot视频播放(解决MP4大文件无法播放),整合ffmpeg,用m3u8切片播放。(包含加密方式)
Java使用ffmpeg进行视频格式转换、音视频合并、播放、截图
DPlayer官网文档
vue使用dplayer 播放m3u8格式的视频——播放m3u8格式视频(三)
vue使用vue-dplayer播放m3u8格式的视频——播放m3u8格式视频(二)
vue使用原生videojs 播放m3u8格式的视频——播放m3u8格式视频(一)
MSE(Media Source Extensions)介绍
hls.js播放m3u8视频
HLS (HTTP Live Streaming)是Apple公司研发的流媒体传输技术,包括一个m3u8的索引文件、多个ts分片文件和key加密串文件。这项技术主要应用于点播和直播领域。
效果
- 发送的请求有2个相同的是因为第一个是预检请求
- 请求中可以携带自定义请求头,因此在后台可以校验这个请求头,从而验证用户,才允许播放,但不能防止用户获取视频数据合并下载
- api可以参考hls的github上的地址
代码
前端代码
安装hls.js
npm install --save hls.js
App.vue
<template><div style="text-align: center;"><!-- 仅一个video元素 --><video id="video" ref="videoRef" width="800" height="400" controls></video><p><!-- 点击触发播放视频 --><button @click="playVideo">播放视频</button> <button @click="pauseVideo">暂停视频</button></p></div>
</template><script setup>
import { ref, reactive, onMounted } from 'vue'
import Hls from 'hls.js';const videoRef = ref()var videoSrc = 'http://127.0.0.1:8085/ts/video/playM3U8video/YsIlFSjnlh'; // 用于获取m3u8文件的地址, 后端处理跨域function playVideo() {videoRef.value.play()
}function pauseVideo() {videoRef.value.pause()
}function loadVideo() {if (Hls.isSupported()) {// 组件挂载完成, 才能获取到video元素var video = document.getElementById('video');// 可参考: // 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; // 会携带cookiexhr.setRequestHeader('token',"my-token")},}var hls = new Hls(config);hls.on(Hls.Events.MEDIA_ATTACHED, function () {console.log('video and hls.js are now bound together !');});hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {console.log('manifest loaded, found ' + data.levels.length + ' quality level');// video.play() // 不能在这里就播放, 需要用于与dom元素有交互才可以播放, 否则浏览器会报错});hls.loadSource(videoSrc);// bind them togetherhls.attachMedia(video);}
}onMounted(() => {loadVideo()
})</script><style scoped>
p {margin: 0;
}
</style>
后台代码
准备文件
其中index.m3u8文件
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:30
#EXTINF:30.000000,
YsIlFSjnlh_0000.ts
#EXTINF:30.000000,
YsIlFSjnlh_0001.ts
#EXTINF:30.000000,
YsIlFSjnlh_0002.ts
#EXTINF:30.000000,
YsIlFSjnlh_0003.ts
#EXTINF:30.000000,
YsIlFSjnlh_0004.ts
#EXTINF:30.000000,
YsIlFSjnlh_0005.ts
#EXTINF:30.000000,
YsIlFSjnlh_0006.ts
#EXTINF:30.000000,
YsIlFSjnlh_0007.ts
#EXTINF:30.000000,
YsIlFSjnlh_0008.ts
#EXTINF:30.000000,
YsIlFSjnlh_0009.ts
#EXTINF:30.000000,
YsIlFSjnlh_0010.ts
#EXTINF:30.000000,
YsIlFSjnlh_0011.ts
#EXTINF:30.000000,
YsIlFSjnlh_0012.ts
#EXTINF:30.000000,
YsIlFSjnlh_0013.ts
#EXTINF:30.000000,
YsIlFSjnlh_0014.ts
#EXTINF:30.000000,
YsIlFSjnlh_0015.ts
#EXTINF:30.000000,
YsIlFSjnlh_0016.ts
#EXTINF:30.000000,
YsIlFSjnlh_0017.ts
#EXTINF:5.400000,
YsIlFSjnlh_0018.ts
#EXT-X-ENDLIST
mp4文件切片java实现
摘自 B站程序员老罗网盘项目代码
cutFile4Video
private void cutFile4Video(String fileId, String videoFilePath) {// videoFilePath 如: D:/document/easypan/easypan-java/file//202305/{userId}{fileId}.mp4//创建同名切片目录,// tsFolder 与 视频文件在同一目录下,并且tsFolder是以视频真实文件名(不带后缀)作为文件夹名// tsFolder 如: D:/document/easypan/easypan-java/file//202305/{userId}{fileId} - 这是个文件夹File tsFolder = new File(videoFilePath.substring(0, videoFilePath.lastIndexOf(".")));if (!tsFolder.exists()) {tsFolder.mkdirs();}// 这里也尝试过直接对mp4文件直接转为.m3u8 + ts分段视频文件,但转的速度比较慢,不知道是不是参数设置的原因,ffmpeg不是很清楚它的命令// 命令如:ffmpeg -i ./jvm.mp4 -c:v h264 -flags +cgop -g 30 -hls_time 60 -hls_list_size 0 -hls_segment_filename index%3d.ts index.m3u8// 这个命令,会将执行命令时所在的当前目录下的jvm.mp4文件按照视频的每60s切割成一个ts文件 和 .m3u8索引文件 到 当前目录// 这里先转为ts文件,然后,再切割这个ts文件,生成.m3u8索引文件(速度比上面快)// 1. 将 整个视频文件 转成ts文件:index.ts// ffmpeg -y -i {mp4视频文件路径} -vcodec copy -acodec copy -vbsf h264_mp4toannexb {放入到哪一个文件位置}// 如:ffmpeg -y -i D:/test/jvm.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb D:/test/jvm/index.ts// 这个命令会将 第一个 所指向的mp4视频文件 转成 ts文件 存储到 D:/test/jvm/index.ts,注意第二个文件路径在执行命令前必须要存在// 2. 将index.ts文件进行分片// ffmpeg -i {index文件的文件路径} -c copy -map 0 -f segment -segment_list {要生成的m3u8索引文件路径} -segment_time 30 {生成的ts切片路径}/{文件名前面部分}_%4d.ts// 生成的ts文件路径%%4d,写了2个百分号是为了防止jdk的MessageFormat处理// 如:ffmpeg -i D:/test/jvm/index.ts -c copy -map 0 -f segment -segment_list D:/test/jvm/index.m3u8 -segment_time 30 D:/test/jvm/jjvvmm_%4d.ts// 这个 命令会将 第一个 所指向的ts视频文件 按照 每30s 切割成一个小的ts视频文件,放入到指定的文件夹中,并且有指定格式的文件名(占4位,递增),并且会生成一个m3u8的索引文件// mp4转ts文件的ffmpeg命令// 如:ffmpeg -y -i D:/document/easypan/easypan-java/file//202305/{userId}{fileId}.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb D:/document/easypan/easypan-java/file//202305/{userId}{fileId}/index.tsfinal String CMD_TRANSFER_2TS = "ffmpeg -y -i %s -vcodec copy -acodec copy -vbsf h264_mp4toannexb %s";// ts文件拆分成小的ts文件 和 生成一个.m3u8文件// 如:ffmpeg -i D:/document/easypan/easypan-java/file//202305/{userId}{fileId}/index.ts -c copy -map 0 -f segment -segment_list D:/document/easypan/easypan-java/file//202305/{userId}{fileId}/index.m3u8 -segment_time 30 D:/document/easypan/easypan-java/file//202305/{userId}{fileId}/{fileId}_%%4d.tsfinal String CMD_CUT_TS = "ffmpeg -i %s -c copy -map 0 -f segment -segment_list %s -segment_time 30 %s/%s_%%4d.ts";// 转成的ts文件所在路径:D:/document/easypan/easypan-java/file//202305/{userId}{fileId}/index.tsString tsPath = tsFolder + "/" + Constants.TS_NAME;String cmd = String.format(CMD_TRANSFER_2TS, videoFilePath, tsPath);ProcessUtils.executeCommand(cmd, false);//生成索引文件.m3u8 和切片.tscmd = String.format(CMD_CUT_TS, tsPath, tsFolder.getPath() + "/" + Constants.M3U8_NAME, tsFolder.getPath(), fileId);ProcessUtils.executeCommand(cmd, false);//删除index.tsnew File(tsPath).delete();
}
ProcessUtils 工具类
package com.easypan.utils;import com.easypan.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;public class ProcessUtils {private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class);public static String executeCommand(String cmd, Boolean outprintLog) throws BusinessException {if (StringTools.isEmpty(cmd)) {logger.error("--- 指令执行失败,因为要执行的FFmpeg指令为空! ---");return null;}Runtime runtime = Runtime.getRuntime();Process process = null;try {process = Runtime.getRuntime().exec(cmd);// 执行ffmpeg指令// 取出输出流和错误流的信息// 注意:必须要取出ffmpeg在执行命令过程中产生的输出信息,如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时,线程就回阻塞住PrintStream errorStream = new PrintStream(process.getErrorStream());PrintStream inputStream = new PrintStream(process.getInputStream());errorStream.start();inputStream.start();// 等待ffmpeg命令执行完process.waitFor();// 获取执行结果字符串String result = errorStream.stringBuffer.append(inputStream.stringBuffer + "\n").toString();// 输出执行的命令信息if (outprintLog) {logger.info("执行命令:{},已执行完毕,执行结果:{}", cmd, result);} else {logger.info("执行命令:{},已执行完毕", cmd);}return result;} catch (Exception e) {// logger.error("执行命令失败:{} ", e.getMessage());e.printStackTrace();throw new BusinessException("视频转换失败");} finally {if (null != process) {ProcessKiller ffmpegKiller = new ProcessKiller(process);runtime.addShutdownHook(ffmpegKiller);}}}/*** 在程序退出前结束已有的FFmpeg进程*/private static class ProcessKiller extends Thread {private Process process;public ProcessKiller(Process process) {this.process = process;}@Overridepublic void run() {this.process.destroy();}}/*** 用于取出ffmpeg线程执行过程中产生的各种输出和错误流的信息*/static class PrintStream extends Thread {InputStream inputStream = null;BufferedReader bufferedReader = null;StringBuffer stringBuffer = new StringBuffer();public PrintStream(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic void run() {try {if (null == inputStream) {return;}bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {stringBuffer.append(line);}} catch (Exception e) {logger.error("读取输入流出错了!错误信息:" + e.getMessage());} finally {try {if (null != bufferedReader) {bufferedReader.close();}if (null != inputStream) {inputStream.close();}} catch (IOException e) {logger.error("调用PrintStream读取输出流后,关闭流时出错!");}}}}
}
TsController
@RestController
@RequestMapping("ts/video")
public class TsController {@Autowiredprivate TsService tsService;@GetMapping("playM3U8video/{fileId}")public void playM3U8video(@PathVariable("fileId") String fileId) {tsService.playM3U8video(fileId);}
}
TsService
@Slf4j
@Service
public class TsService {private static final String VIDEO_ROOT_PATH = "d:\\test";@Autowired@SuppressWarnings("all")private HttpServletResponse response;// 可参考:ffmpeg 视频ts切片生成m3u8// 网页前端video播放m3u8(HLS) https://www.cnblogs.com/fieldtianye/p/13166957.html// https://www.cnblogs.com/fieldtianye/category/1789297.htmlpublic void playM3U8video(String fileId) {FileSystemResourceLoader fileResourceLoader = new FileSystemResourceLoader();// 先获取m3u8文件if (!fileId.endsWith("ts")) {Resource resource = fileResourceLoader.getResource(VIDEO_ROOT_PATH + File.separator + fileId + "/index.m3u8");try {StreamUtils.copy(resource.getInputStream(), response.getOutputStream());} catch (IOException e) {log.error("写出m3u8文件流失败:{}",e);}} else {// 请求以ts结尾,则获取ts分段文件Resource resource = fileResourceLoader.getResource(VIDEO_ROOT_PATH + File.separator + fileId.split("_")[0] + File.separator +fileId);try {StreamUtils.copy(resource.getInputStream(), response.getOutputStream());} catch (IOException e) {log.error("写出m3u8文件流失败:{}",e);}}}
}
DPlayer播放m3u8视频
效果
效果与直接使用hls效果一致,但是优点是它还支持其它的
MSE(Media Source Extensions)
携带了自定义的请求头
扩展内容:MSE(Media Source Extensions)介绍
摘自:MSE(Media Source Extensions)介绍
本文介绍 MSE(Media Source Extensions) 的相关知识。
1 概述
MSE(Media Source Extensions),即媒体源扩展,可以理解为一种API,其提供了实现无插件(js插件外的插件)且基于 Web 的流媒体的功能。通过 MSE,媒体串流能够通过 JavaScript 创建,并且可以使用 HTML5 的 <audio>
和 <video>
标签进行播放。
2 why MSE
以前,用户在通过Web浏览器浏览网页内容,尤其是视频内容时,需要使用诸如 Adobe Flash或是微软的 Silverlight 等类似的插件,才能播放视音频内容
,这些插件对于Web浏览器来说,扮演着媒体播放器角色。但是,在浏览器中使用插件是不便捷并且不安全的(不法分子会在插件上动手脚),因此,最新的HTML5标准中,定义了一系列新的元素来避免使用插件,其中就包含了大名鼎鼎的 <video> 标签
。
有了<video>标签,支持 HTML5 的Web浏览器就能够实现无需插件播放媒体内容了
,但是 HTML5 的 <video> 标签对媒体的格式有所限制(在 Windows 电脑上只支持 mp4、webm、ogg 等格式)。这里简单介绍一下媒体格式,媒体的格式分为“编码格式
”和“封装格式
”,原视频数据通过编码来压缩视频数据大小,这里用到的格式为编码格式(如常见的H.264编码),再通过封装将压缩后的视音频、字幕组合到一个容器中,这里用到的格式为封装格式(如常见的mp4格式)
。
我们可以把 <video> 标签看做是浏览器自带的、具有解封和解码功能的视频播放器。但是,随着视频点播、直播等视频业务
的兴起,视频数据会通过流媒体传输协议(目前常用的 MPEG-DASH 和 Apple 的 HLS)从服务端分发给客户端
,在这种情况下,媒体内容就被包含在传输协议中了,此时 HTML5 的 <video> 标签就无法识别并播放媒体内容了
。以 HLS 协议为例。HLS 将视频源文件的内容分散地封装到一个个TS文件中,此时仅靠 <video> 标签是无法识别这些TS文件的,所以,我们就需要引入了 MSE 来帮助Web浏览器识别并处理TS文件,将其变回Web浏览器可识别的媒体容器格式(mp4格式),经过 MSE 的处理,<video> 标签就可以识别并播放视频源文件了
。例如,hls.js
中就利用 MSE 将视频分片内容进行合流,并组成 HTML5 的 <video> 标签可播放的媒体资源文件。再比如,flv.js
通过 MSE 播放 HTTP-FLV 协议的视频直播流。简单总结一下,引入 MSE 之后,支持 HTML5 的Web浏览器就变成了能够解析流协议的播放器了
。
从另外一个角度来说,通过引入 MSE,HTML5 的<video> 标签不仅可以直接播放其默认支持的 mp4、m3u8、webm、ogg 等格式,还可以支持能够被 (具备MSE功能的)JS 处理的视频流格式
。如此一来,我们就可以通过 (具备MSE功能的)JS,把一些 标签原本不支持的视频流格式,转化为其支持的格式(如 H.264 的 mp4)。B站开源的 flv.js 就是此技术的一个典型应用场景,B站的HTML5播放器,通过使用 MSE 技术,将FLV源用 JS(flv.js) 实时转码成 HTML5 支持的视频流编码格式,提供给 HTML5 播放器播放。
代码
后端代码不变,修改前端代码即可。
安装依赖
npm i dplayer -S // 视频播放器插件
npm i hls.js -S // 播放hls流插件
App.vue
<template><!-- 只写宽度,高度会自适应 --><div id="dplayer" style="width: 400px;"></div><p><!-- 点击触发播放视频 --><button @click="playVideo">播放视频</button> <button @click="pauseVideo">暂停视频</button></p>
</template><script setup>import { ref, reactive, onMounted } from 'vue'import Hls from 'hls.js';
import DPlayer from 'dplayer';console.log(DPlayer);let dpInstance = nullfunction playVideo() {console.log(dpInstance.play);dpInstance.play()
}function pauseVideo() {dpInstance.pause()
}onMounted(() => {// 另一种方式,使用 customTypeconst dp = new DPlayer({container: document.getElementById('dplayer'),video: {url: 'http://127.0.0.1:8085/ts/video/playM3U8video/YsIlFSjnlh',type: 'customHls',customType: {customHls: function (video, player) {let config = {xhrSetup: function (xhr, url) {xhr.withCredentials = true; // 会携带cookiexhr.setRequestHeader('token', "my-token")},}const hls = new Hls(config);hls.loadSource(video.src);hls.attachMedia(video);},},},});window.dp = dpdpInstance = dp})</script><style lang="scss"></style>
Hls.js播放m3u8视频 DPlayer视频播放器(easypan) MSE简介相关推荐
- m3u8.php怎么调用,怎样使用Vue结合Video.js播放m3u8视频
这次给大家带来怎样使用Vue结合Video.js播放m3u8视频,使用Vue结合Video.js播放m3u8视频的注意事项有哪些,下面就是实战案例,一起来看一下. 首先,我们需要在vue工程中安装vi ...
- video.js播放m3u8视频
m3u8 是一种基于HTTP Live Streaming(HLS)文件视频格式,它主要是存放整个视频的基本信息和分片(Segment)组成.目前 由 Apple.inc 率先提出的 HLS 协议在 ...
- 使用hls.js播放m3u8视频流
1.安装hls.js npm install hls.js -S 2.使用 <template><div class="video_con"><vid ...
- 360极速浏览器不能添加hls插件,怎样播放m3u8视频?
谷歌和火狐浏览器都可以在扩展程序添加Native HLS Playback插件播放m3u8视频,但是360搜了一下没有类似的插件. 那怎么办呢,有个好办法就是大家可以简单粗暴直接换成Chrome浏览器 ...
- video.js兼容微信浏览器,(播放.m3u8视频源)解决微信浏览器黑屏问题
video.js兼容微信浏览器,(播放.m3u8视频源)解决微信浏览器黑屏问题 一.问题描述: 在h5做根据视频源直播功能时,在浏览器能打开视频,但是在部分安卓机和苹果机在微信浏览器打开会出现黑屏的状 ...
- 怎么播放m3u8视频
为了播放 m3u8 视频,你需要有一个支持 m3u8 格式的视频播放器.常用的视频播放器有 VLC.Potplayer 等. 你需要在这些视频播放器中打开 m3u8 文件,即可播放视频. 你也可以使用 ...
- Web端直接播放 .ts 视频及mux.js播放ts视频没有声音
最近项目中需要前端播放 .ts 格式视频,捣鼓了几天学习到很多知识,也发掘了一种优秀的解决方案,分享给有同样需求的同学. 常见方案 在网上查找的大部分解决方案都是用诸如videojs等网页播放器,接收 ...
- vue中DPlayer视频播放器使用方法
vue中DPlayer视频播放器使用方法 1通过npm下载 npm install dplayer - s 2在需要使用的组件中导入 import Dplayer from 'Dplayer' 3页面 ...
- android 3.0 m3u8,在Android中播放m3u8视频
我想直播视频,并且它采用m3u8格式.所以,我想下面的代码在Android中播放m3u8视频 public class StreamingPlayer extends Activity impleme ...
最新文章
- jmeter启动警告项解决方案
- 沉浸式小说App获得200万美元投资
- java calendar与date_java---Calendar与Date
- 记录下openstack部署和使用时遇到的一些问题
- Jquery Table 的基本操作
- 异步执行和多线程编程的关系
- slider获取点击 unity_Unity基础 | 70分钟带你轻松入门
- 这就是八成女性不爱用刷脸支付的原因!支付宝:一周内给安排上
- Java Design Pattern(Factory,Singleton,Prototype,Proxy)
- 用友套打的打印机型号
- Android 如何反编译apk查看源码
- a 标签 jq js 打开新页面跳转
- win10计算机方差,标准差计算工具
- andriod 连接数据库(MySQL)
- PS制作心跳二维码动画 学会后能增加粉丝关注率哦
- 戴尔390计算机电源问题,DELL笔记本电脑电源适配器无电压输出故障
- 强制在线带修区间LCM(线段树+质因子状压)
- Adobe25年软件精华CS3中文版发布.
- java医院挂号代码_基于SSM开发的Java医院预约挂号系统 源码下载
- 【H.264/AVC视频编解码技术详解】十七:帧内预测编码的预测实现方法
热门文章
- Lazada精细化店铺运营数据分析工具用什么?店梯erp告诉你
- 浅析领导力和执行力在企业管理中的运用
- [vue-demo]实时时间转换 v-time
- 单例模式多线程环境实现之几句呢喃
- 高中学历学Java能找到工作吗?
- bootstrap.min.css.map
- 小张学算法之音视频算法:2.jpeg图像压缩算法
- ECC内存和普通内存有什么不同?为什么对金融和医疗业务至关重要?
- VC(VISUAL_C++)虚拟键VK值列表
- 华为od机试真题 JS 实现【热点网站统计】