音視訊混流
阿新 • • 發佈:2019-01-06
音視訊混流
之前講過一篇如何通過攝像頭獲取音視訊流並匯出的文章。這次要講的是如何將多個音視訊流混合後匯出。
主要用的API有:
- MediaRecorder(提供的用來進行媒體輕鬆錄製的介面)
- getUserMedia(捕獲攝像頭、麥克音視訊流)
- getAudioTracks(從stream流中獲取音訊流集合)
- addTrack(往stream流中增加媒體流)
- AudioContext(AudioContext物件,可對音訊進行處理)
- createBufferSource(該介面是一個音訊源,它由儲存在一個儲存器中的記憶體中音訊資料組成)
- createMediaStreamDestination(建立一個媒體流的節點)
- decodeAudioData(可用於非同步解碼音訊檔案中的 ArrayBuffer)
1、建立一個BGM音訊流
- 用的到介面:AudioContext、createBufferSource、createMediaStreamDestination、decodeAudioData
// 建立AudioContext例項 var audioCtx = new AudioContext() // 建立一個音訊源 var source = audioCtx.createBufferSource() // 建立一個媒體流節點 var track = audioCtx.createMediaStreamDestination()
ok,到這裡為止,我們BGM的關鍵物件都齊全了,不過這些只有容器,沒有最重要的內容。剛剛我們說了decodeAudioData這個api,這個api可以將資料解碼音訊中的ArrayBuffer。
// 獲取BGM的檔案的arraybuffer var request = new XMLHttpRequest(); request.open('GET', './music/test.mp3', true); request.responseType = 'arraybuffer'; request.onload = function() { // 這裡我們通過ajax請求將檔案轉arraybuffer格式 var audioData = request.response; audioCtx.decodeAudioData(audioData, function(buffer) { // 這裡的buffer就是解碼過的arraybuffer // 將buffer加入音訊源裡 source.buffer = buffer // 將音訊輸出到一個媒體流節點上 source.connect(track) // 重複播放BGM source.loop = true; // 播放緩衝區的音訊資料 source.start(0) }) } request.send();
到這裡為止,我們已經將BGM的音訊捕獲到了,接下來就是將其合進攝像頭和麥克捕獲的音視訊流內。
2、捕獲攝像頭音視訊流(這個在之前講過傳送)
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).then(function(stream) {
// stream這裡就是我們捕獲的攝像頭音視訊流
// 將BGM內的音訊流提取出來
var bgmAudioTrack = track.stream.getAudioTracks()[0]
// 這裡track.stream是重媒體流節點裡的媒體流,getAudioTracks這才是從流內獲取音訊流集合
// stream新增音訊流
stream.addTrack(bgmAudioTrack)
})
現在我們獲取到的就是混音之後的音視訊了,之後就是將媒體匯出本地了
3、下載多媒體(這個在之前講過傳送)
var start = document.getElementById('start')
var stop = document.getElementById('stop')
const chunks = null
// 建立MediaRecorder例項(這裡可以看之前的文章)
var mediaRecorder = new MediaRecorder(stream, {
audioBitsPerSecond : 128000,
videoBitsPerSecond : 100000,
mimeType : 'video/webm;codecs=h264'
})
start.onclick = function () {
mediaRecorder.start()
console.log('開始採集')
}
stop.onclick = function () {
mediaRecorder.stop()
console.log('停止採集')
}
mediaRecorder.onstop = function (e) {
var blob = new Blob([chunks], { 'type' : 'video/mp4' })
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = `test.mp4`
a.click()
}
mediaRecorder.ondataavailable = function(e) {
chunks = e.data
}
ok,這下就大功告成了。下面我是我的demo,不過因為獲取攝像頭需要https,所以要本地用http://localhost跑才能呼叫
<!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>音視訊混流</title>
</head>
<body>
<button id="button">開啟攝像頭</button>
<button id="start">開始採集</button>
<button id="stop">停止採集</button>
</body>
<script>
var button = document.getElementById('button')
var start = document.getElementById('start')
var stop = document.getElementById('stop')
var audioDom2 = document.querySelector('#audio2')
var audioCtx = new AudioContext();
var source = audioCtx.createBufferSource()
var track = audioCtx.createMediaStreamDestination();
button.onclick = function () {
navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
stream.addTrack(track.stream.getAudioTracks()[0])
/* 使用這個stream stream */
var mediaRecorder = new MediaRecorder(stream, {
audioBitsPerSecond : 128000,
videoBitsPerSecond : 100000,
mimeType : 'video/webm;codecs=h264'
})
start.onclick = function () {
mediaRecorder.start()
console.log('開始採集')
}
stop.onclick = function () {
mediaRecorder.stop()
console.log('停止採集')
}
mediaRecorder.onstop = function (e) {
var blob = new Blob([chunks], { 'type' : 'video/mp4' })
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = `test.mp4`
a.click()
}
mediaRecorder.ondataavailable = function(e) {
console.log(e)
chunks = e.data
}
})
.catch(function(err) {
console.log(err)
/* 處理error */
});
}
function getData() {
var request = new XMLHttpRequest();
request.open('GET', './music/test.mp3', true);
request.responseType = 'arraybuffer';
request.onload = function() {
var audioData = request.response;
audioCtx.decodeAudioData(audioData, function(buffer) {
source.buffer = buffer;
source.connect(track)
source.loop = true;
source.start(0)
},
function(e){"Error with decoding audio data" + e.err});
}
request.send();
}
getData()
</script>
</html>
不過我發現有的電腦開啟採集麥克聲音時,背景音不能合成進去。