video.js 视频截图、录制、自定义全屏,hls、flv、mp4视频播放 您所在的位置:网站首页 下载flv文件 video.js 视频截图、录制、自定义全屏,hls、flv、mp4视频播放

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

2024-02-06 16:39| 来源: 网络整理| 查看: 265

功能 video.js内嵌 截图、录制功能 (图片、视频会下载到本地)自定义全屏播放hls、flv、mp4功能集合成Vue组件 参考 video.js componentsRecordRTC demovideo 截图并下载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

no video

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

import Player from './components/Player.vue' export default { name: 'App', components: { Player }, data: { // flv nowPlayVideoUrl: "//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", } ... }

加入自定义全屏

在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); }; }

修改父组件引入

效果

自定义全屏

加入截图、录制功能

安装

// 录制所需插件 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: ` 截图 录像 ` }) 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 = { // 截图、录制Bar customBar: { screenshot: true, recorder: false } .... }

customBar加入截图、录制逻辑

... constructor: function (player, options) { // Equivalent of `super(this, arguments)` Component.apply(this, arguments); // player 实列 this.player = player // 录像所需要的 canvas this.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: ` 截图 录像 ` }) 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中取一帧图片并转成dataURL let 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.isRecorder if (this.isRecorder) { recordDom.innerHTML = `结束` if (!this.canvas) this.canvas = document.createElement("canvas"); this.recorder = RecordRTC(this.canvas, { type: "canvas", }); this.recorder.startRecording(); this.drawMedia(); } else { // recordDom.innerHTML = `录像` recordDom.innerHTML = `录像` this.recorder.stopRecording(() => { const url = window.URL.createObjectURL(this.recorder.getBlob()); this.downloadFile(url, "mp4"); cancelAnimationFrame(this.animationFrame); this.canvas = null; this.animationFrame = null; }); } }, // 刷新canvas drawMedia() { 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引入该文件

效果

截图和视频录制

其中使用到的图片

图片1 图片1 图片2 图片2

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有