Open lostvita opened 4 years ago
请使用该Token:1563266971025访问本文Demo,或者点击这里访问。
说起web前端录像📹网页内容,,我们的反映可能是先给页面截屏,再将一帧帧的图像合成视频,截屏的操作则是通过html 2 canvas的方式实现。 如果想要合成流畅的视频,那么就必须截出密集帧图像,这无疑是很消耗性能的。如果有一个原生的API,支持对网页录像就好了!!!
本文介绍的内容包括:
MediaRecoder
Canvas
MediaRecoder提供了一系列用于录制媒体(视频音频等)的接口,通过调用其构造函数可以创建一个MediaRecoder实例对象,在new实例对象时传入媒体对象参数,则可以实现对该媒体对象的录音/像。
new
其中, 媒体对象的来源有两类, 一类是当前网页上的媒体, 可以是video、audio或者canvas元素; 另一类是用户的桌面设备, 通过navigator.mediaDevices.getUserMedia()可以取得用户的桌面录像录音权限, 这一类技术的应用场景有web RTC. 这里讨论的是第一类: 针对网页内容的录像.
navigator.mediaDevices.getUserMedia()
const mediaStream = $video.captureStream(10) // 获取媒体元素的媒体流对象 mediaRecord = new MediaRecorder(mediaStream, { // 实例化录制对象 videoBitsPerSecond: 8500000, // 比特率 mimeType: 'video/mp4' // 录屏媒体流文件类型 }) mediaRecord.ondataavailable = (e) => { // 接收媒体流数据: Blob类型 this.chunks.add(e.data) }
以上仅仅是初始化一个媒体录像实例对象, 我们还需要手动启动录制或停止:
mediaRecord.start() // 开始录制 mediaRecord.stop() // 停止录制
实例化过程的mimeType参数在使用上有一定的限制,需要预先检测当前浏览器是否支持该类型:
mimeType
MediaRecorder.isTypeSupported('video/mp4') // true or false
MediaRecorder.mimeType
video/webm;codecs=vp8
video/webm
MediaRecorder.state
MediaRecorder
inactive
recording
paused
MediaRecorder.stream
MediaRecorder.ignoreMutedMedia
MediaRecorder.start(timeslice)
timeslice
MediaRecorder.pause()
MediaRecorder.resume()
MediaRecorder.stop()
MediaRecoder.ondataavailable
const chunks = new Set() mediaRecord.ondataavailable = (e) => { chunks.add(e.data) }
如果在start()中设置了timeslice,那么该事件每隔timeslice时间会触发一次;否则只在录制结束时触发。
start()
MediaRecoder.onstart
onpause
onresume
onstop
MediaRecoder.onerror
在前面的举例中我们用到了captureStream这个方法,该方法用于获取媒体流。在H5里面,有两个对象实现了这个API,分别是HTMLMediaElement和HTMLCanvasElement。前面示例中我们使用$video.captureStream(),就是应用了HTMLMediaElement元素的接口(audio元素也支持),canvas元素则可以通过HTMLCanvasElement访问该接口。
captureStream
HTMLMediaElement
HTMLCanvasElement
$video.captureStream()
audio
canvas
HTMLMediaElement提供这个接口有什么作用呢?我目前想到的一个应用场景是媒体资源的下载。如果我们需要下载某个视频,通常的做法可能是需要后端提供一个接口返回二进制内容,有了这个API,前端就可以自己实现下载了。
接下来主要介绍HTMLCanvasElement的captureStream:通过录屏实现对canvas内容的监控。
HTMLCanvasElement的captureStream
Step 1:来,左边画个圆
// 参数分别为画布上下文对象、横纵坐标、填充颜色 function drawCircle (ctx, x=100, y=100, color) { const radius = 20 ctx.clearRect(0, 0, 600, 300) ctx.beginPath() ctx.arc(x, y, radius, 0, 2 * Math.PI, false) ctx.lineWidth = 0 ctx.closePath() ctx.fillStyle = color ctx.fill() ctx.strokeStyle = color ctx.stroke() }
Step 2:右边铺块布
// 初始化画布 function initCanvas () { const $circle = $('#circle') $circle.width = 600 $circle.height = 300 const ctx = $circle.getContext('2d') drawCircle(ctx, x, y, color) }
Step 3:诶,加个动画
canvas动画的核心就是:重复绘制!
function initCanvas () { // ...省略初始化 const cTimer = new Timer(5000) // 动画周期5s let color = colors[parseInt(Math.random() * 6)] // 随机颜色 cTimer.onProgress = (p) => { const x = Math.cos(p * 2 * Math.PI) * 50 + 300 const y = Math.sin(p * 2 * Math.PI) * 50 + 150 if(x < 300 && y > 150 || x > 300 && y < 150) color = colors[parseInt(Math.random() * 6)] drawCircle(ctx, x, y, color) // 5s内不断画圆 } cTimer.onFinished = () => { cTimer.start() // 动画结束之后重新开始 } cTimer.start() // 动起来 }
Step 1:初始化录屏实例
const chunks = new Set() function createRecord () { const mediaStream = $canvas.captureStream(10) // 设置帧频率(FPS) mediaRecord = new MediaRecorder(mediaStream, { videoBitsPerSecond: 8500000 }) mediaRecord.ondataavailable = (e) => { // 接收数据 chunks.add(e.data) } }
Step 2:控制录屏
mediaRecord.start() // 开始录屏 this.mediaRecord.stop() // 结束录屏
Step 3:下载录屏
const videoBlob = new Blob(chunks, { 'type' : 'video/mp4' }) videoUrl = window.URL.createObjectURL(videoBlob)
chunks是元素为Blob类型的列表,可能只有一个元素,可能是多个元素,取决于start()中是否设置了timeslice,将这些片段blob重新封装为一个完整的blob数据,并且可以指定数据类型。然后根据blob数据生成一条blob URL。关于blob和createObjectURL的介绍可以移步这里。
chunks
Blob
blob
blob URL
createObjectURL
最后,借助a标签下载视频:
a
function download () { var a = document.createElement('a') a.href = this.videoUrl a.download = 'record-canvas.mp4' a.style.display = 'none' document.body.appendChild(a) a.click() }
以上,戳Demo
前言
说起web前端录像📹网页内容,,我们的反映可能是先给页面截屏,再将一帧帧的图像合成视频,截屏的操作则是通过html 2 canvas的方式实现。 如果想要合成流畅的视频,那么就必须截出密集帧图像,这无疑是很消耗性能的。如果有一个原生的API,支持对网页录像就好了!!!
本文介绍的内容包括:
MediaRecoder
录制媒体流Canvas
绘制动画MediaRecoder
MediaRecoder
提供了一系列用于录制媒体(视频音频等)的接口,通过调用其构造函数可以创建一个MediaRecoder
实例对象,在new
实例对象时传入媒体对象参数,则可以实现对该媒体对象的录音/像。其中, 媒体对象的来源有两类, 一类是当前网页上的媒体, 可以是video、audio或者canvas元素; 另一类是用户的桌面设备, 通过
navigator.mediaDevices.getUserMedia()
可以取得用户的桌面录像录音权限, 这一类技术的应用场景有web RTC. 这里讨论的是第一类: 针对网页内容的录像.举个例子: 录制video元素的媒体
以上仅仅是初始化一个媒体录像实例对象, 我们还需要手动启动录制或停止:
实例化过程的
mimeType
参数在使用上有一定的限制,需要预先检测当前浏览器是否支持该类型:常用属性与方法
MediaRecorder.mimeType
[只读]:返回实例化过程设置的媒体文件类型。笔者设备测试,如果未设置,默认返回:Chrome ->video/webm;codecs=vp8
,Firefox ->video/webm
;MediaRecorder.state
[只读]:返回当前MediaRecorder
实例的工作状态,可选值有:inactive
、recording
和paused
;MediaRecorder.stream
[只读]:返回当前媒体流,亦即实例化过程传入的媒体流对象MediaRecorder.ignoreMutedMedia
:是否静音模式录制;MediaRecorder.start(timeslice)
:开始录制。timeslice
参数可选,表示以该持续时间切片媒体数据;MediaRecorder.pause()
:暂停录制;MediaRecorder.resume()
:继续录制;MediaRecorder.stop()
:停止录制。事件处理器
MediaRecoder.ondataavailable
:在该事件中接收媒体录制数据如果在
start()
中设置了timeslice
,那么该事件每隔timeslice
时间会触发一次;否则只在录制结束时触发。MediaRecoder.onstart
:在调用start()
时触发,类似的还有onpause
、onresume
、onstop
MediaRecoder.onerror
:捕获错误异常。captureStream
在前面的举例中我们用到了
captureStream
这个方法,该方法用于获取媒体流。在H5里面,有两个对象实现了这个API,分别是HTMLMediaElement
和HTMLCanvasElement
。前面示例中我们使用$video.captureStream()
,就是应用了HTMLMediaElement
元素的接口(audio
元素也支持),canvas
元素则可以通过HTMLCanvasElement
访问该接口。HTMLMediaElement
提供这个接口有什么作用呢?我目前想到的一个应用场景是媒体资源的下载。如果我们需要下载某个视频,通常的做法可能是需要后端提供一个接口返回二进制内容,有了这个API,前端就可以自己实现下载了。接下来主要介绍
HTMLCanvasElement的captureStream
:通过录屏实现对canvas
内容的监控。canvas绘制圆周运动
Step 1:来,左边画个圆
Step 2:右边铺块布
Step 3:诶,加个动画
canvas动画的核心就是:重复绘制!
录频并下载
Step 1:初始化录屏实例
Step 2:控制录屏
Step 3:下载录屏
chunks
是元素为Blob
类型的列表,可能只有一个元素,可能是多个元素,取决于start()
中是否设置了timeslice
,将这些片段blob
重新封装为一个完整的blob
数据,并且可以指定数据类型。然后根据blob
数据生成一条blob URL
。关于blob
和createObjectURL
的介绍可以移步这里。最后,借助
a
标签下载视频:以上,戳Demo