詳解js的視頻和音頻采集
今天要寫(xiě)的,不是大家平時(shí)會(huì)用到的東西。因?yàn)榧嫒菪詫?shí)在不行,只是為了說(shuō)明下前端原來(lái)還能干這些事。
大家能想象前端是能將攝像頭和麥克風(fēng)的視頻流和音頻流提取出來(lái),再為所欲為的么?;蛘哒f(shuō)我想把我canvas畫(huà)板的內(nèi)容錄制成一個(gè)視頻,這些看似js應(yīng)該做不到的事情,其實(shí)都是可以做到的,不過(guò)兼容性不好。我在這里都是以chrome瀏覽器舉的例子。
這里先把用到的api列一下:
- getUserMedia:打開(kāi)攝像頭和麥克風(fēng)的接口(文檔鏈接)
- MediaRecorder:采集音視頻流(文檔鏈接)
- srcObject:video標(biāo)簽可直接播放視頻流,這是一個(gè)大家應(yīng)該很少用到其實(shí)兼容性很好的屬性,推薦大家了解(文檔鏈接)
- captureStream:可以將canvas輸出流,其實(shí)不單單是canvas這里只是舉有這個(gè)功能,具體的可以看文檔(文檔鏈接)
1、從攝像頭展示視頻
一、打開(kāi)攝像頭
// 這里是打開(kāi)攝像頭和麥克設(shè)備(會(huì)返回一個(gè)Promise對(duì)象)
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(stream => {
console.log(stream) // 放回音視頻流
}).catch(err => {
console.log(err) // 錯(cuò)誤回調(diào)
})
上面我們成功打開(kāi)了攝像頭和麥克風(fēng),并獲取到視頻流。那接下來(lái)就是要把流呈現(xiàn)到交互界面中了。
二、展示視頻
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<video id="video" width="500" height="500" autoplay></video>
</body>
<script>
var video = document.getElementById('video')
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(stream => {
// 這里就要用到srcObject屬性了,可以直接播放流資源
video.srcObject = stream
}).catch(err => {
console.log(err) // 錯(cuò)誤回調(diào)
})
</script>
效果如下圖:

到這里為止我們已經(jīng)成功的將我們的攝像頭在頁(yè)面展示了。下一步就是如何將采集視頻,并下載視頻文件。
2、從攝像頭采集視頻
這里用到的是MediaRecorder對(duì)象:
創(chuàng)建一個(gè)新的MediaRecorder對(duì)象,返回一個(gè)MediaStream 對(duì)象用來(lái)進(jìn)行錄制操作,支持配置項(xiàng)配置容器的MIME type (例如"video/webm" or "video/mp4")或者音頻的碼率視頻碼率
MediaRecorder接收兩個(gè)參數(shù)第一個(gè)是stream音視頻流,第二個(gè)是option配置參數(shù)。下面我們可以把上面攝像頭獲取的流加入MediaRecorder中。
var video = document.getElementById('video')
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(stream => {
// 這里就要用到srcObject屬性了,可以直接播放流資源
video.srcObject = stream
var mediaRecorder = new MediaRecorder(stream, {
audioBitsPerSecond : 128000, // 音頻碼率
videoBitsPerSecond : 100000, // 視頻碼率
mimeType : 'video/webm;codecs=h264' // 編碼格式
})
}).catch(err => {
console.log(err) // 錯(cuò)誤回調(diào)
})
在上面我們創(chuàng)建了MediaRecorder的實(shí)例mediaRecorder。接下來(lái)就是控制mediaRecorder的開(kāi)始采集和停止采集的方法了。
MediaRecorder提供了一些方法和事件供我們使用:
- MediaRecorder.start(): 開(kāi)始錄制媒體,這個(gè)方法調(diào)用時(shí)可以通過(guò)給timeslice參數(shù)設(shè)置一個(gè)毫秒值,如果設(shè)置這個(gè)毫秒值,那么錄制的媒體會(huì)按照你設(shè)置的值進(jìn)行分割成一個(gè)個(gè)單獨(dú)的區(qū)塊, 而不是以默認(rèn)的方式錄制一個(gè)非常大的整塊內(nèi)容.
- MediaRecorder.stop(): 停止錄制. 同時(shí)觸發(fā)dataavailable事件,返回一個(gè)存儲(chǔ)Blob內(nèi)容的錄制數(shù)據(jù).之后不再記錄
- ondataavailable事件: MediaRecorder.stop觸發(fā)該事件,該事件可用于獲取記錄的媒體(Blob在事件的data屬性中可用作對(duì)象)
// 這里我們?cè)黾觾蓚€(gè)按鈕控制采集的開(kāi)始和結(jié)束
var start = document.getElementById('start')
var stop = document.getElementById('stop')
var video = document.getElementById('video')
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(stream => {
// 這里就要用到srcObject屬性了,可以直接播放流資源
video.srcObject = stream
var mediaRecorder = new MediaRecorder(stream, {
audioBitsPerSecond : 128000, // 音頻碼率
videoBitsPerSecond : 100000, // 視頻碼率
mimeType : 'video/webm;codecs=h264' // 編碼格式
})
// 開(kāi)始采集
start.onclick = function () {
mediaRecorder.start()
console.log('開(kāi)始采集')
}
// 停止采集
stop.onclick = function () {
mediaRecorder.stop()
console.log('停止采集')
}
// 事件
mediaRecorder.ondataavailable = function (e) {
console.log(e)
// 下載視頻
var blob = new Blob([e.data], { 'type' : 'video/mp4' })
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = `test.mp4`
a.click()
}
}).catch(err => {
console.log(err) // 錯(cuò)誤回調(diào)
})
ok,現(xiàn)在執(zhí)行一波操作;

上圖可以看到結(jié)束采集后ondataavailable事件返回的數(shù)據(jù)中有一個(gè)Blob對(duì)象,這就是視頻資源了,再接下來(lái)我們就可以通過(guò)URL.createObjectURL()方法將Blob為url下載到本地了。視頻的采集到下載就結(jié)束了,很簡(jiǎn)單粗暴。
上面是視頻采集下載的例子,如果只要音頻采集的,同樣道理的設(shè)置“mimeType”就好了。這里我就不舉例了。下面我在介紹將canvas錄制為一個(gè)視頻文件
2、canvas輸出視頻流
這里用到的是captureStream方法,將canvas輸出流,再用video展現(xiàn),或者用MediaRecorder采集資源也是可以的。
// 這里就閑話少說(shuō)直接上重點(diǎn)了因?yàn)楹蜕厦嬉曨l采集的是一樣的道理的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<canvas width="500" height="500" id="canvas"></canvas>
<video id="video" width="500" height="500" autoplay></video>
</body>
<script>
var video = document.getElementById('video')
var canvas = document.getElementById('canvas')
var stream = $canvas.captureStream(); // 這里獲取canvas流對(duì)象
// 接下來(lái)你先為所欲為都可以了,可以參考上面的我就不寫(xiě)了。
</script>
下面我再貼一個(gè)gif(這是結(jié)合我上次寫(xiě)的canvas事件的demo結(jié)合這次視頻采集的結(jié)合)傳送門(mén)(Canvas事件綁定)
希望大家可以實(shí)現(xiàn)下面的效果,其實(shí)還可以在canvas視頻里插入背景音樂(lè)什么的,這些都比較簡(jiǎn)單。

相關(guān)文章
微信小程序基于movable-view實(shí)現(xiàn)滑動(dòng)刪除效果
這篇文章主要介紹了微信小程序基于movable-view實(shí)現(xiàn)滑動(dòng)刪除效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
javascript自定義startWith()和endWith()的兩種方法
js中自定義startWith()和endWith()方法有兩種,在本文將為大家詳細(xì)介紹下,感興趣的朋友不要錯(cuò)過(guò)2013-11-11
深入理解JavaScript 中的執(zhí)行上下文和執(zhí)行棧
這篇文章主要介紹了JavaScript 中的執(zhí)行上下文和執(zhí)行棧的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10
淺析JavaScript中l(wèi)et與const命令的區(qū)別
這篇文章主要為大家詳細(xì)介紹了JavaScript中l(wèi)et命令與const命令的用法及區(qū)別,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考下2023-09-09
Express框架中_router?對(duì)象數(shù)據(jù)結(jié)構(gòu)使用詳解
這篇文章主要為大家介紹了Express框架中_router的對(duì)象數(shù)據(jù)結(jié)構(gòu)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
微信小程序?qū)崙?zhàn)篇之購(gòu)物車(chē)的實(shí)現(xiàn)代碼示例
本篇文章主要介紹了微信小程序?qū)崙?zhàn)篇之購(gòu)物車(chē)的實(shí)現(xiàn)代碼示例,詳細(xì)的介紹了購(gòu)物車(chē)的功能實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解一下2017-11-11
uni-app和web-view頁(yè)面相互傳參方法實(shí)例
web-view是一個(gè)web瀏覽器組件,可以用來(lái)承載網(wǎng)頁(yè)的容器,會(huì)自動(dòng)鋪滿整個(gè)頁(yè)面,下面這篇文章主要給大家介紹了關(guān)于uni-app和web-view頁(yè)面相互傳參的相關(guān)資料,需要的朋友可以參考下2023-06-06

