3┃音視頻直播系統之瀏覽器中通過 WebRTC 直播視頻實時錄製回放下載
- 2022 年 5 月 12 日
- 筆記
- 萬人在線音視頻直播系統, 音視頻直播系統
一、錄製分類
-
在音視頻會議、在線教育等系統中,錄製是一個特別重要的功能
-
錄製一般分為服務端錄製和客戶端錄製
-
服務端錄製:優點是不用擔心客戶因自身電腦問題造成錄製失敗(如磁盤空間不足),也不會因錄製時搶佔資源(CPU 佔用率過高)而導致其他應用出現問題等;缺點是實現的複雜度很高。
-
客戶端錄製:優點是方便錄製方(如老師)操控,並且所錄製的視頻清晰度高,實現相對簡單。但是它對內存、硬盤的要求 比較高
-
它們各有優劣,因此大系統一般會同時支持客戶端錄製與服務端錄製。
二、錄製思考
-
第一:錄製後音視頻流的存儲格式是什麼呢?是直接錄製原始數據,還是錄製成某種多媒體格式(如 MP4 )
-
第二:錄製下來的音視頻流如何播放?是使用普通的播放器播放,還是使用私有播放器,如果你的業務是多人互動類型,且回放時也要和直播時一樣,那麼你就必須使用私有播放器,因為普通播放器是不支持同時播放多路視頻的
-
第三:啟動錄製後多久可以回放呢?錄製完立即回放?邊錄邊看?錄完後過一段時間可觀看?
-
錄製完立即回放當然體驗性最好,但是清晰度卻不行,在平時的直播中應該有所體驗;錄完一段時間再觀看,可以對視頻進行轉碼獲得更好的清晰度,但是對用戶的體驗卻不好,不能實時觀看。
三、錄製音視頻
-
WebRTC 錄製音視頻流之後,最終是通過 Blob 對象將數據保存成多媒體文件的
-
Blob(Binary Large Object)是 JavaScript 的大型二進制對象類型
var aBlob = new Blob(array, options);
-
WebRTC 中提供了
MediaRecorder
類去錄製本地音視頻var mediaRecorder = new MediaRecorder(stream[, options]);
-
stream:通過 getUserMedia 獲取的本地視頻流或通過
RTCPeerConnection
獲取的遠程視頻流 -
options:可選項,指定視頻格式、編解碼器、碼率等相關信息,如
mimeType: 'video/webm;codecs=vp8'
-
MediaRecorder 對象還有一個特別重要的事件,即 ondataavailable 事件。當 MediaRecoder 捕獲到數據時就會觸發該事件。通過它,我們才能將音視頻數據錄製下來
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>video of WebRTC</title>
</head>
<body>
<button onclick="startRecord()">Start Record</button>
</body>
<script>
var buffer;
function startRecord() {
buffer = [];
// 設置錄製下來的多媒體格式
var options = {
mimeType: 'video/webm;codecs=vp8'
}
// 判斷瀏覽器是否支持錄製
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not supported!`);
return;
}
try {
// 創建錄製對象
mediaRecorder = new MediaRecorder(window.stream, options);
} catch (e) {
console.error('Failed to create MediaRecorder:', e);
return;
}
// 當有音視頻數據來了之後觸發該事件
mediaRecorder.ondataavailable = handleDataAvailable;
// 開始錄製
// 在開啟錄製時,可以設置一個毫秒級的時間片,這樣錄製的媒體數據會按照你設置的
// 值分割成一個個單獨的區塊,否則默認的方式是錄製一個非常大的整塊內容。
// 分成一塊一塊的區塊會提高效率和可靠性,如果是一整塊數據,隨着時間的推移,數據塊越來越大
// 讀寫效率就會變差,而且增加了寫入文件的失敗率
mediaRecorder.start(10);
}
// 當該函數被觸發後,將數據壓入到 blob 中
function handleDataAvailable(e) {
if (e && e.data && e.data.size > 0) {
buffer.push(e.data);
}
}
</script>
</html>
四、回放錄製視頻
-
通過上面的方法錄製好內容 壓入到 blob 以後
-
首先根據 buffer 生成 Blob 對象
-
然後,根據 Blob 對象生成 URL,並通過 <video> 標籤將錄製的內容播放出來了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>video of WebRTC</title>
</head>
<body>
<video id="recvideo"></video>
<button onclick="recplay()" disabled>Play</button>
</body>
<script>
var buffer;
function recplay() {
var blob = new Blob(buffer, {type: 'video/webm'});
recvideo.src = window.URL.createObjectURL(blob);
recvideo.srcObject = null;
recvideo.controls = true;
recvideo.play();
}
</script>
</html>
五、下載錄製視頻
-
也是先創建一個 Blob 對象,並根據 Blob 對象創建 URL;
-
然後再創建一個 <a> 標籤,設置 a 標籤的 href 和 download 屬性
-
這樣當用戶點擊該標籤之後,錄製好的文件就下載下來了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>video of WebRTC</title>
</head>
<body>
<button onclick="download()" disabled>Download</button>
</body>
<script>
var buffer;
function download() {
var blob = new Blob(buffer, {type: 'video/webm'});
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.style.display = 'none';
a.download = '下載的視頻.webm';
a.click();
}
</script>
</html>