3┃音視頻直播系統之瀏覽器中通過 WebRTC 直播視頻實時錄製回放下載

一、錄製分類

  • 在音視頻會議、在線教育等系統中,錄製是一個特別重要的功能

  • 錄製一般分為服務端錄製和客戶端錄製

  • 服務端錄製:優點是不用擔心客戶因自身電腦問題造成錄製失敗(如磁盤空間不足),也不會因錄製時搶佔資源(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>