前端实现监控视频播放-截图-图片编辑全过程。

934 阅读2分钟

前期准备

项目新需求:播放接入的hls流视频监控(后缀为.m3u8),点击实现截图抓拍,并对截图进行编辑。 技术&插件:视频播放插件video.js,图片编辑我选用的是tui-image-editor插件。

视频播放

html5的video标签无法直接播放流媒体视频,所以要借助插件。

安装video.js

npm install video.js --save // 视频播放器插件
npm install videojs-contrib-hls  --save // 播放hls流插件 需要时安装

在main.js引入全局样式文件

import 'video.js/dist/video-js.css'

在项目内引入

import videojs from 'video.js'
import 'videojs-contrib-hls'

应用

data.filter((item, index) => {
  let temp = '#video' + index
  let temp1 = 'video' + index
  let player = 'player' + index
  let b = $('.video-box')
  if (this[player]) {
    this[player].dispose()
  }
  $.each(b, (e, l) => {
    if (e === index) {
      $(l).empty()
      $(l).append(
        `<video id="${temp1}" width=200 height=150 class="video-js vjs-default-skin" autoplay muted>
        <source src="${item.video_url}"
                type="application/x-mpegURL">
      </video>
      )
    }
  })
  _this[player] = new videojs(temp)
  this[player].src({
    src: item.video_url,
    type: 'application/x-mpegURL'
  })
})

因为项目要求在列表页展示所有从接口获取的监控视频,所以video标签是动态插入的。其实最佳的情况是一个页面只播放一个流媒体视频监控,流媒体视频是不断发送请求获取数据的,所以多个流媒体视频同时播放是非常影响性能的,如果一定要一个页面同时展示多个时一定要在关闭页面或跳转其他页面是将视频销毁,这样就不会继续发送请求了。

视频销毁

data.filter((item, index) => {
  let player = 'player' + index
  if (this[player]) {
    this[player].dispose()
    this[player] = null
  }
})

视频截图

截图的实现主要是依靠canvas的drawImage方法

var canvas = document.createElement('canvas')
var video = this.player1.el().querySelector('video')
let imgWidth = video.offsetWidth
let imgheight = video.offsetHeight
canvas.width = imgWidth
canvas.height = imgheight
var canvasCtx = canvas.getContext('2d')
// 坐原图像的x,y轴坐标,大小,目标图像的x,y轴标,大小。
canvasCtx.drawImage(video, 0, 0, imgWidth, imgheight)
// 把图标base64编码后变成一段url字符串
var dataUrl = canvas.toDataURL('image/png')

图片编辑

安装插件:

npm install tui-image-editor --save

页面内引用:

import 'tui-image-editor/dist/tui-image-editor.css'
import 'tui-color-picker/dist/tui-color-picker.css'
import ImageEditor from 'tui-image-editor'

使用:

this.instance = new ImageEditor(
  document.querySelector('#img-editor'),
  {
    includeUI: {
      loadImage: {
        path: this.imgUrl,
        name: 'image'
      },
      initMenu: 'draw', // 默认打开的菜单项
      menuBarPosition: 'right', // 菜单所在的位置
    },
    cssMaxWidth: 1000, // canvas 最大宽度
    cssMaxHeight: 1000 // canvas 最大高度
  }
)
document.getElementsByClassName('tui-image-editor-main')[0].style.top = '30px' // 图片距顶部工具栏的距离

//获取编辑后图片base64文件
this.instance.toDataURL()

一些编辑起的配置可以参考文章www.jianshu.com/p/ba00b5c08…

或者访问官方文档nhn.github.io/tui.image-e…

图片格式转换

编辑后的图片需要通过接口传给后端,后端只接收file文件格式的文件,所以我做了一下base64到file文件的转换,并放入formdata对象传给后端。

const base64String = this.instance.toDataURL() // base64 文件
const data = window.atob(base64String.split(',')[1])
const u8a = new Uint8Array(data.length)
for (let i = 0; i < data.length; i++) {
  ia[i] = data.charCodeAt(i)
}
let filename = new Date().getTime() + '.png'
const file = new File([u8a], filename, {
  type: 'image/png'
})
let form = new FormData()
form.append('file', file)
//在此处console.log(form)得到的可能是一个空对象,但其实file已经append进去了。

一定要注意,filename的前面是可以随便命名的,但是后面一定要加图片的格式后缀。