功能

  • video.js内嵌 截图、录制功能 (图片、视频会下载到本地)
  • 自定义全屏
  • 播放hls、flv、mp4
  • 功能集合成Vue组件

参考

  • video.js components
  • RecordRTC demo
  • video 截图并下载
  • video.js添加自定义组件的方法
  • 使用RecordRTC对video视频进行录制

播放hls、flv、mp4

安装

// video.js
npm install video.js
// 播放hls
npm install  videojs-contrib-hls
// 播放flv
npm install videojs-flvjs-es6
npm install flv.js

引入

import "videojs-contrib-hls";
import "videojs-flvjs-es6";
import videojs from "video.js";
import video_zhCN from "video.js/dist/lang/zh-CN.json";
videojs.addLanguage("zh-CN", video_zhCN);export default {props: {name: {type: String,default: "my-video",},// 视频地址videoUrl: {type: String,default: "",},//视频宽度videoWidth: {type: String,default: "100%",},//视频高度videoHeight: {type: String,default: "100%",},},data() {const options = {// 封面图poster: '',language: "zh-CN",// 设置自动播放autoplay: true,// 设置了它为true,才可实现自动播放,同时视频也被静音 (Chrome66及以上版本,禁止音视频的自动播放)muted: true,// 预加载preload: "none",// 显示播放的控件controls: true,// 进度条liveui: true,notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息。// 播放速率playbackRates: [0.5, 1, 2, 4, 8, 16],controlBar: {// 画中画pictureInPictureToggle: false,// 当前时间和持续时间的分隔符timeDivider: true,// 显示持续时间durationDisplay: true,// 是否显示剩余时间功能remainingTimeDisplay: true,// 是否显示全屏按钮fullscreenToggle: true,},}return {options,// videoUrl 从无到有时会显示一会视频错误信息// 使用该字段判断 no-video 来避免显示错误信息hasVideoUrl: false,// 视频流类型videoTypeObj: {mp4: 'video/mp4',flv: 'video/x-flv',m3u8: 'application/x-mpegURL'}};},methods: {getVideo(nowPlayVideoUrl) {if (!nowPlayVideoUrl) this.hasVideoUrl = false;if (!this.player) {this.player = videojs(this.$refs.player, this.options);}this.player.src([{src: nowPlayVideoUrl,type: this.videoUrl?this.videoTypeObj[this.videoUrl.split('.').slice(-1)]:''},]);setTimeout(() => {this.hasVideoUrl = !!nowPlayVideoUrl;}, 100);}},watch: {//监听视频地址、video的id值videoUrl: {deep: true,immediate: true,handler(val) {this.$nextTick(() => {this.getVideo(val);});},},},beforeDestroy() {// 组件销毁时,清除播放器if (this.player) this.player.dispose();},
};

html

  <div:style="{ width: videoWidth, height: videoHeight, position: 'relative' }"class="display"><videostyle="width: 100%; height: 100%"class="video-js"ref="player"v-show="videoUrl"></video><!-- 视频路径为空时 --><divv-show="!hasVideoUrl":style="{height: videoWidth,width: videoHeight,position: 'absolute',left: 0,top: 0,zIndex: 2,background: '#000',}">no video</div></div>

引入组件(视频地址使用的时西瓜的测试视频)


import Player from './components/Player.vue'export default {name: 'App',components: {Player},data: {// flvnowPlayVideoUrl: "//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv",// mp4// nowPlayVideoUrl: "//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-360p.mp4",// hls// nowPlayVideoUrl: "//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/hls/xgplayer-demo.m3u8",}
...
}
<template><div style="height:400px;width:600px"><Player :videoUrl="nowPlayVideoUrl"/></div>
</template>

加入自定义全屏

在props中加入 name 、fullscreenType、fullscreenChange属性

  props:{...// 当存在多个直播时,用于判断是哪个直播需要全屏name: {type: String,default: "my-video",},// 全屏类型fullscreenType: {type: String,default: "initial",validator: function (value) {// 这个值必须匹配下列字符串中的一个return ["none", "DIY", "initial"].indexOf(value) !== -1;},// 全屏状态改变 当fullscreenType为DIY时有效fullscreenChange: {type: Function,default: () => {},},
}

修改options

   const options= {...controlBar: {// 画中画pictureInPictureToggle: false,// 当前时间和持续时间的分隔符timeDivider: true,// 显示持续时间durationDisplay: true,// 是否显示剩余时间功能remainingTimeDisplay: true,// 是否显示全屏按钮fullscreenToggle: this.fullscreenType === "initial" ? true : false,},
}     

修改getVideo方法

if (!nowPlayVideoUrl) this.hasVideoUrl = false;if (!this.player) {this.player = videojs(this.$refs.player, this.options);// 自定义全屏功能if (this.fullscreenType === "DIY") this.setDIYFullscreen();}...
}

编写setDIYFullscreen方法

setDIYFullscreen() {const fullscreenButton = this.player.controlBar.addChild("button");fullscreenButton.controlText("全屏");fullscreenButton.addClass("vjs-fullscreen-control");const fullscreenButtonDom = fullscreenButton.el();fullscreenButtonDom.onclick = () => {this.isDIYFullscreen = !this.isDIYFullscreen;if (this.isDIYFullscreen) {this.player.addClass("vjs-fullscreen");fullscreenButton.controlText("退出全屏");console.log('全屏');} else {this.player.removeClass("vjs-fullscreen");fullscreenButton.controlText("全屏");console.log('退出全屏');}// 父组件回调this.fullscreenChange(this.isDIYFullscreen, this.name);};}

修改父组件引入

<template><div style="height:400px;width:600px"><Player fullscreenType="DIY" :videoUrl="nowPlayVideoUrl"/></div>
</template>

效果

自定义全屏

加入截图、录制功能

安装

// 录制所需插件
npm i recordrtc

创建video.js文件,将video.js相关引入、逻辑都放整合放在这里(自定义全屏除外)

import videojs from "video.js";
import video_zhCN from "video.js/dist/lang/zh-CN.json";
import RecordRTC from "recordrtc";
import "videojs-contrib-hls";
import "videojs-flvjs-es6";
// 截图图片
import cameraImg from '../assets/images/camera.png'
// 录像图片
import monitorImg from '../assets/images/monitor.png'
videojs.addLanguage("zh-CN", video_zhCN);// 创建 截图、录像
var Component = videojs.getComponent("Component");
var CustomBar = videojs.extend(Component, {constructor: function (player, options) {},createEl: function () {return videojs.dom.createEl('div', {innerHTML: `这是一个自定义组件`})}
})// 注册 截图、录像组件
videojs.registerComponent('CustomBar', CustomBar);export default videojs

创建custom-video.css文件,video相关css放在这里

@import "video.js/dist/video-js.css";

更改组件引入,以及在options中加入customBar

import videojs from '../utils/video'
import '../assets/css/custom-video.css'
....
options = {customBar: {}...
}

效果

修改CustomBar,界面显示

...
// 截图图片
import cameraImg from '../assets/images/camera.png'
// 录制图片
import monitorImg from '../assets/images/monitor.png'var CustomBar = videojs.extend(Component, {...createEl: function () {const divDom = videojs.dom.createEl('div', {className: 'vjs-custom-bar',innerHTML: `<div  class="vjs-custom-control-bar vjs-button ac"><img src="${cameraImg}" style="width:13px" /><span class="ml10">截图</span></div><div class="mt10 vjs-custom-control-bar ac" ><img src="${monitorImg}" style="width:13px" /><span class="ml10">录像</span></div>`})return divDom}
}

修改custom-video.css

customBar位于右侧中间显示,鼠标活动以及悬浮在customBar显示customBar,不活动时隐藏

录制中时红点闪烁

@import "video.js/dist/video-js.css";
.vjs-custom-bar {position: absolute;color: #fff;right: 10px;transform: translateY(-50%);top: 50%;
}
.vjs-custom-bar:hover {opacity: 1 !important;
}
.vjs-custom-control-bar {padding: 10px;background: rgba(43, 51, 63, 0.7);border-radius: 5px;cursor: pointer;
}
/* 开始录制 闪烁 */
.record-procees {display: inline-block;height: 10px;width: 10px;background: red;border-radius: 8px;animation: blings 1s linear infinite;
}
.mt10 {margin-top: 10px;
}
.ml10 {margin-left: 10px;
}
.ac {display: flex;align-items: center;
}
@keyframes blings {0% {opacity: 0.1;}100% {opacity: 1;}
}
.video-js .vjs-custom-bar {color: white;/* font-size: 2em; */padding: .5em;}.vjs-has-started .vjs-custom-bar {/* display: flex; */visibility: visible;opacity: 1;transition: visibility 0.1s, opacity 0.1s;}/* 用户不活动时设计title bar自动隐藏 */.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-custom-bar {visibility: visible;/*visibility: hidden;*/opacity: 0;transition: visibility 1s, opacity 1s;}.vjs-controls-disabled .vjs-custom-bar,.vjs-using-native-controls .vjs-custom-bar,.vjs-error .vjs-custom-bar {display: none !important;}.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-custom-bar {opacity: 0;visibility: visible;/*visibility: hidden;*/}.vjs-has-started.vjs-no-flex .vjs-custom-bar {display: table;}

CustomBar加入隐藏逻辑

...
constructor: function (player, options) {// Equivalent of `super(this, arguments)`Component.apply(this, arguments);// 隐藏截图if (options.screenshot === false) this.hiddenEl(0)// 隐藏录像if (options.recorder === false) this.hiddenEl(1)
},
createEl: function () {
...
}hiddenEl (index) {const myDom = this.el().querySelectorAll('div')[index]myDom.setAttribute('style', 'display:none')}

当需要隐藏录像时,修改options中customBar属性

options = {// 截图、录制BarcustomBar: {screenshot: true,recorder: false}....
}

customBar加入截图、录制逻辑

...
constructor: function (player, options) {// Equivalent of `super(this, arguments)`Component.apply(this, arguments);// player 实列this.player = player// 录像所需要的 canvasthis.canvas = null// 录像实列this.recorder = null// 停止循环帧 需要用到的参数this.animationFrame = null// 录像状态 false 未录像 true 录像中this.isRecorder = false// 隐藏截图if (options.screenshot === false) this.hiddenEl(0)// 隐藏录像if (options.recorder === false) this.hiddenEl(1)
},
createEl: function () {const divDom = videojs.dom.createEl('div', {className: 'vjs-custom-bar',innerHTML: `<div  class="vjs-custom-control-bar vjs-button ac"><img src="${cameraImg}" style="width:13px" /><span class="ml10">截图</span></div><div class="mt10 vjs-custom-control-bar ac" ><img src="${monitorImg}" style="width:13px" /><span class="ml10">录像</span></div>`})const [screenshotDom, recordDom] = divDom.querySelectorAll('div')screenshotDom.onclick = () => this.screenshotHandle()recordDom.onclick = () => this.recordHandle(recordDom)return divDom},
...

截图 screenshotHandle方法

  // 截图screenshotHandle() {const fileType = "png";// 找到需要截图的video标签// video 实列const video = this.player.el().querySelector('video')// const video = this.video;console.log(video, 'video');const canvas = document.createElement("canvas");canvas.width = video.videoWidth;canvas.height = video.videoHeight;console.log(canvas, 'canvas')canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height); // 图片大小和视频分辨率一致const strDataURL = canvas.toDataURL("image/" + fileType); // canvas中video中取一帧图片并转成dataURLlet arr = strDataURL.split(","),mime = arr[0].match(/:(.*?);/)[1],bstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}const blob = new Blob([u8arr], {type: mime,});const url = window.URL.createObjectURL(blob);this.downloadFile(url, "png");},

录制 recordHandle方法,

  // 录像recordHandle (recordDom) {this.isRecorder = !this.isRecorderif (this.isRecorder) {recordDom.innerHTML = `<i class="record-procees"></i><span class="ml10">结束</span>`if (!this.canvas) this.canvas = document.createElement("canvas");this.recorder = RecordRTC(this.canvas, {type: "canvas",});this.recorder.startRecording();this.drawMedia();} else {// recordDom.innerHTML = `<i class="el-icon-video-camera-solid"></i><span class="ml10">录像</span>`recordDom.innerHTML = `<img src="${monitorImg}" style="width:13px" /><span class="ml10">录像</span>`this.recorder.stopRecording(() => {const url = window.URL.createObjectURL(this.recorder.getBlob());this.downloadFile(url, "mp4");cancelAnimationFrame(this.animationFrame);this.canvas = null;this.animationFrame = null;});}},// 刷新canvasdrawMedia() {const ctx = this.canvas.getContext("2d");// 找到需要截图的video标签const video = this.player.el().querySelector('video')this.canvas.setAttribute("width", video.videoWidth);this.canvas.setAttribute("height", video.videoHeight);ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);// requestAnimationFrame 根据电脑显示帧数进行循环this.animationFrame = requestAnimationFrame(() => this.drawMedia());},

文件下载downloadFile

  // 下载downloadFile: function (blob, fileType) {const a = document.createElement("a");a.style.display = "none";a.href = blob;// const time = this.parseTime(new Date())const time = new Date().getTime();a.download = `${time}.${fileType}`;document.body.appendChild(a);a.click();setTimeout(function () {document.body.removeChild(a);window.URL.revokeObjectURL(blob);}, 1000);},

解决RecordRTC录制报错

在public下index.html引入该文件

    <!-- 下载到本地引入 --><script src="screenshot.js"></script><!-- 官方路径引入 --><!-- <script src="https://www.webrtc-experiment.com/screenshot.js"></script> -->

效果

截图和视频录制

其中使用到的图片

图片1

图片2

video.js 视频截图、录制、自定义全屏,hls、flv、mp4视频播放相关推荐

  1. jquery video全屏_用videojs让HTML5视频在移动端全屏的方法

    用videojs让HTML5视频在移动端全屏的方法 文章标签: 视频 : 04-10 19:23 : 1859次 : 0条 1赞 点赞 简介在使用videojs插件时,如何让HTML5的视频在移动端里 ...

  2. 【videojs】videojs自定义全屏按钮 | videojs全屏移动端弊端 | 创建videojs菜单

    videojs全屏弊端 在移动端全屏播放9:16的视频效果不好 ,如下图 9:16的视频全屏播放合适竖屏 16:9的视频全屏播放合适横屏 移动端9:16我想要的效果如下图↓,全屏播放时铺满竖屏 需求 ...

  3. canvas+html实现视频弹幕,可以全屏实现

    前几天突然想做一个像BiliBIli的弹幕系统,原来想法是视频外套一个div,然后div创建弹幕元素P标签飘过实现,后来发现太卡了,就用canvas实现,后来发现一个问题, 我的实现原理就是id为co ...

  4. 电脑分屏软件_Fcpx分屏插件 41组视频分割可自定义分屏动画效果插件 可分9屏 Split Pop...

    Fcpx分屏插件 41组视频分割可自定义分屏动画效果插件 这是一套目前小编感觉最好用的Fcpx分屏插件,一.支持4K.二.最多可分9屏.三.可微调参数调整最佳展示.四.41种效果简洁大方,涵盖各类流行 ...

  5. [html] 如何解决微信浏览器视频点击自动全屏的问题?

    [html] 如何解决微信浏览器视频点击自动全屏的问题? 1.1 页面内播放 X5内核视频在用户点击后默认会进入全屏播放,前端可以设置video的x5-playsinline属性来将视频限定于网页内部 ...

  6. [html]HTML5如何隐藏video元素的控制栏、全屏按钮?

    [html]HTML5如何隐藏video元素的控制栏.全屏按钮? 将<video width="800px" height="400px" id=&quo ...

  7. html 全屏显示某个区域,JS实现指定区域的全屏显示功能示例

    本文实例讲述了JS实现指定区域的全屏显示功能.分享给大家供大家参考,具体如下: www.jb51.net js指定区域全屏 #fulldiv { background: #fff; width: 10 ...

  8. video.js视频高度自适应解决方法

    video.js视频高度自适应解决方法 1.引入两个外部文件,或者下载到本地 <link href="https://unpkg.com/video.js/dist/video-js. ...

  9. 简黑时钟AClock 2.3 Mac (Mac自定义全屏时钟软件)

    简黑时钟 Mac是一款极致省电,自定义全屏时钟辅助工具,可以满足你对一款时钟app的所有设想,可以做床头电子表,办公桌电子表.横屏超大字体,精确到秒的电子表.简黑时钟大小仅几十kb,占用内存空间完全可 ...

最新文章

  1. 软工专硕考研_分析|华北电力(北京)大学20计算机考研报录分析!电子信息复试狂刷114人,软工专硕复试录取高达1:4.7!...
  2. nginx之Geoip读取地域信息模块
  3. SAP UI5应用Opportunity S5 formatter issue
  4. 分享一个点赞超过100的漂亮ASP.NET MVC蓝色界面框架
  5. leetcode816. 模糊坐标
  6. myeclipse 8.5 安装jbpm3.2开发插件
  7. 路由总结之静态、RIP、OSPF、IS-IS、BGP和策略路由
  8. html简单弹窗代码_真的!!!两行css代码实现瀑布流,html,css最简单的瀑布流实现方式且没有缺点!...
  9. 和付费网盘说再见,自己起个网盘不香吗?| Java 开源项目
  10. angularjs源码笔记(4)--scope
  11. VS2010调用python编写的代码error:cannot open file 'python27_d.lib'.
  12. 算法,PHP取数据库中百万条数据中随机20条记录
  13. webpack在内存生成html,Vue学习之Webpack基本使用小结(十三)
  14. 海南大学信号与系统838考研经验(3)
  15. abaqus算出来的转角单位是什么_ABAQUS中的单位制是如何规定的;
  16. maccms10自动播放下一集
  17. php完美导出word,使用phpword插件实现word文档导出
  18. HTML5 水平线标签 hr
  19. 谷歌开源!一个格式化 Python 代码的好帮手!
  20. Ubuntu20.04安装cuda10.1

热门文章

  1. 关于Cool Compiler
  2. Java+Swing实现医院管理系统
  3. 《Android系统源代码情景分析》一书勘误
  4. 未能加载文件或程序集 Renci.SshNet, Version=2016.1.0.0, Culture=neutral, PublicKeyToken= 1cee9f8bde3db106或它的某
  5. thinksns源码_看移动社交引擎ThinkSNS如何帮助企业和创业者快速搭建理想的社交产品?...
  6. 【转】 中兴OLT-C300常用命令
  7. C语言中printf打印形式(%02X, %2X, %-2X, %.nf, %m.nf, %e, %m.ne, %2d, %-2d, %02d, %.2d)
  8. 三份适合工薪族的作业,抄完走向财务自由
  9. linux环境下常用的打包、压缩、解压命令(tar、gzip、bzip2、zip)
  10. HBuilderX 百度网盘下载链接