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

autofelix發表於2022-05-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>

 

相關文章