iT邦幫忙

2024 iThome 鐵人賽

DAY 6
1

為什麼要錄影

在互動性高的應用程式中,讓使用者可以自由紀錄畫面,是必備的元素之一。這不僅提供了用戶便捷的錄影功能,也讓開發者可以輕鬆製作展示影片。無論是創建教學影片還是捕捉用戶操作、上傳到Youtube,錄影功能都能大大提升應用的靈活性和實用性。這篇文章將展示如何在 React 應用中實現一個簡單而功能強大的錄影按鈕。

功能概述

我們將實現一個 RecordBtn 元件,這個元件提供了開始和停止錄影的功能。該按鈕會在點擊時切換錄影狀態,並能捕捉畫面和音訊流。最後生成 MP4 格式的影片並下載。

核心功能實現:

  1. 捕捉畫面:錄影時,我們從 捕捉畫面流。
  2. 加入音訊:若有提供,則同時捕捉音訊流。
  3. 處理與下載錄影資料:錄影結束後,我們將錄影資料組合成影片檔案,並觸發下載動作。

在使用這個元件時,把想要錄影的 canvas 和 audio 對象,作為參數傳入:

const canvas = useRef(null);
const audio = useRef(null);

return (
    <section className="section" id={uniqueID}>
        <canvas ref={canvas} 
            width={min * ratio}
            height={ratio * min * ratio}>
        </canvas>
        {/* ...... */}
        <RecordBtn canvas={canvas} audio={audio}></RecordBtn>
    </section>
)

初始化

import downloadMedia from '../js/downloadMedia';

const media = {};
  • downloadMedia 是一個自定義的函數,用於處理錄影結束後的數據下載。
  • media 物件,用來儲存錄影所需的媒體流和錄影器實例。

捕捉串流

這個方法其實也適用於 audio 或 video 元素,可以根據需求擴展,讓它不只串流canvas的內容。

const chunks = [];
media.stream = canvas.current.captureStream(60); // 設定為 60 fps
  • chunks 是一個陣列,用來儲存錄影過程中產生的數據片段。
  • media.stream 是從畫布捕捉到的媒體流,captureStream 方法的參數是每秒幀數(fps)。

加入音訊片段

我們嘗試裁剪原本的串流,只保留視訊,這會導致原本的音訊丟失,不過,canvas本來就沒有音頻,所以可以放心的創建一個新的 MediaStream,用來合併音訊、視訊。

if(audio?.current){
    media.audio = audio.current;
    media.audio.play();
    media.audioStream = media.audio.captureStream();
    media.stream = new MediaStream([
        ...media.stream.getVideoTracks(),
        ...media.audioStream.getAudioTracks()
    ]);
}
  • 如果提供了 audio,則從音頻元素捕捉音頻流,並開始播放。
  • media.audioStream 是從音頻元素捕捉到的音頻,並將其與畫布的視訊合併成一個新的媒體流 media.stream。

創建和設置錄影功能

media.recorder = new MediaRecorder(media.stream, { mimeType: "video/mp4; codecs=vp9" });
media.recorder.ondataavailable = (evt) => { chunks.push(evt.data); };
media.recorder.onstop = () => { downloadMedia(chunks); };
media.recorder.start(1000);
  • 創建 media.recorder 並為它設定事件:
    • 當錄影過程中有新數據可用時,ondataavailable 事件會被觸發,將數據片段推入 chunks 陣列中。
    • 當錄影停止時,onstop 事件會觸發 downloadMedia 函數,處理錄影數據的下載。
  • start(1000) 方法啟動錄影,每 1000 毫秒收集一次數據。

下載連結

還記得我們最初提到的 downloadMedia 函式嗎?讓我們把它完成:

function downloadMedia(data){
    const blob = new Blob(data, {type: "video/mp4" });
    const recording_url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = recording_url;
    a.download = "video.mp4";
    a.click();
}
  • 首先把 data 轉換成 blob 對象
  • 接著,創建一個隱藏的 元素,設置下載鏈接並觸發下載

不過,考慮到相容性,可能還需要加上特殊作法,詳細可以參考我查到的stackoverflow討論串

//......
a.style = "display: none;";
document.body.appendChild(a);
a.click();
setTimeout(() => {
    URL.revokeObjectURL(recording_url);
    document.body.removeChild(a);
}, 0);

結語

這樣的設計讓用戶可以方便地錄製畫面和音訊,並將錄製的內容保存到本地,進一步增強了應用程式的互動性和展示效果。

如果感興趣,可以參考 Github 上的原始碼:
RecordBtn.jsx

這次也留給大家一個問題:你會如何擴展這個錄影功能,例如加入更多的錄影選項或提高錄影品質?


上一篇
A4 面板元件-靈活的收納按鈕設計
下一篇
A6 React 和 Vue 實作表格元件:排序、搜尋與分頁功能詳解
系列文
讓演算法起舞:前端特效應用的探索之旅23
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言