音訊和影片處理

Web 的魅力在於您可以將技術結合起來建立新形式。在瀏覽器中擁有原生音訊和影片意味著我們可以將這些資料流與 <canvas>WebGLWeb 音訊 API 等技術結合起來,直接修改音訊和影片,例如,向音訊新增混響/壓縮效果,或向影片新增灰度/棕褐色濾鏡。本文提供一個參考來解釋您需要做什麼。

影片處理

能夠讀取影片每幀的畫素值非常有用。

影片和畫布

<canvas> 元素提供了一個在網頁上繪製圖形的表面;它功能強大,可以與影片緊密結合。

一般技術是

  1. 將來自 <video> 元素的一幀寫入 <canvas> 元素。
  2. 讀取 <canvas> 元素中的資料並進行操作。
  3. 將操作後的資料寫入您的“顯示”<canvas>(實際上可以是同一個元素)。
  4. 暫停並重復。

例如,讓我們處理一個影片以將其以灰度顯示。在這種情況下,我們將同時顯示源影片和輸出灰度幀。通常,如果您要實現“以灰度播放影片”功能,您可能會將 display: none 新增到 <video> 元素的樣式中,以防止源影片在顯示更改後的幀時被繪製到螢幕上。

HTML

我們可以這樣設定我們的影片播放器和 <canvas> 元素

html
<video id="my-video" controls width="480" height="270" crossorigin="anonymous">
  <source
    src="https://jplayer.org/video/webm/Big_Buck_Bunny_Trailer.webm"
    type="video/webm" />
  <source
    src="https://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"
    type="video/mp4" />
</video>

<canvas id="my-canvas" width="480" height="270"></canvas>

JavaScript

此程式碼處理更改幀。

js
const processor = {
  timerCallback() {
    if (this.video.paused || this.video.ended) {
      return;
    }
    this.computeFrame();
    setTimeout(() => {
      this.timerCallback();
    }, 16); // roughly 60 frames per second
  },

  doLoad() {
    this.video = document.getElementById("my-video");
    this.c1 = document.getElementById("my-canvas");
    this.ctx1 = this.c1.getContext("2d");

    this.video.addEventListener(
      "play",
      () => {
        this.width = this.video.width;
        this.height = this.video.height;
        this.timerCallback();
      },
      false,
    );
  },

  computeFrame() {
    this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
    const frame = this.ctx1.getImageData(0, 0, this.width, this.height);
    const l = frame.data.length / 4;

    for (let i = 0; i < l; i++) {
      const grey =
        (frame.data[i * 4 + 0] +
          frame.data[i * 4 + 1] +
          frame.data[i * 4 + 2]) /
        3;

      frame.data[i * 4 + 0] = grey;
      frame.data[i * 4 + 1] = grey;
      frame.data[i * 4 + 2] = grey;
    }
    this.ctx1.putImageData(frame, 0, 0);

    return;
  },
};

頁面載入後,您可以呼叫

js
processor.doLoad();

結果

這是一個非常簡單的示例,展示瞭如何使用畫布操作影片幀。為了提高效率,您應該考慮在支援的瀏覽器上使用 requestAnimationFrame() 而不是 setTimeout()

您也可以透過將 grayscale() CSS 函式應用於源 <video> 元素來實現相同的結果。

注意:由於如果您的影片與您的程式碼不在同一個域中,則可能存在潛在的安全問題,因此您需要在您的影片伺服器上啟用 CORS(跨域資源共享)

影片和 WebGL

WebGL 是一個強大的 API,它使用畫布來繪製硬體加速的 3D 或 2D 場景。您可以將 WebGL 與 <video> 元素結合起來建立影片紋理,這意味著您可以將影片放入 3D 場景中。

注意:您可以在 GitHub 上找到此演示的原始碼即時檢視)。

播放速率

我們還可以使用 <audio><video> 元素稱為 playbackRate 的屬性來調整音訊和影片的播放速率。playbackRate 是一個表示要應用於播放速率的倍數的數字,例如 0.5 表示半速,而 2 表示雙速。

請注意,playbackRate 屬性同時適用於 <audio><video>,但在這兩種情況下,它都會改變播放速度,但不會改變音調。要操作音訊的音調,您需要使用 Web 音訊 API。請參閱 AudioBufferSourceNode.playbackRate 屬性。

HTML

html
<video
  id="my-video"
  controls
  src="https://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"></video>

JavaScript

js
const myVideo = document.getElementById("my-video");
myVideo.playbackRate = 2;

可編輯的示例

注意:嘗試 即時播放速率示例

音訊處理

除了 playbackRate,要操作音訊,您通常會使用 Web 音訊 API

選擇音訊源

Web 音訊 API 可以接收來自各種來源的音訊,然後對其進行處理,並將其傳送回一個表示輸出裝置的 AudioDestinationNode,聲音在處理後會傳送到該裝置。

如果音訊源是… 使用此 Web 音訊節點型別
來自 HTML <audio><video> 元素的音訊軌道 MediaElementAudioSourceNode
記憶體中一個簡單的原始音訊資料緩衝區 AudioBufferSourceNode
一個生成正弦波或其他計算波形的振盪器 OscillatorNode
來自 WebRTC 的音訊軌道(例如,您可以使用 getUserMedia() 獲取的麥克風輸入)。 MediaStreamAudioSourceNode

音訊濾鏡

Web 音訊 API 有許多不同的濾鏡/效果,例如,可以使用 BiquadFilterNode 應用於音訊。

HTML

html
<video id="my-video" controls src="myvideo.mp4" type="video/mp4"></video>

JavaScript

js
const context = new AudioContext();
const audioSource = context.createMediaElementSource(
  document.getElementById("my-video"),
);
const filter = context.createBiquadFilter();
audioSource.connect(filter);
filter.connect(context.destination);

// Configure filter
filter.type = "lowshelf";
filter.frequency.value = 1000;
filter.gain.value = 25;

可編輯的示例

注意:除非您啟用了 CORS,否則為了避免安全問題,您的影片應與您的程式碼位於同一個域中。

常見音訊濾鏡

以下是一些您可以應用的常見音訊濾鏡型別

  • 低通:允許低於截止頻率的頻率透過,並衰減高於截止頻率的頻率。
  • 高通:允許高於截止頻率的頻率透過,並衰減低於截止頻率的頻率。
  • 帶通:允許一定範圍內的頻率透過,並衰減此頻率範圍以下和以上的頻率。
  • 低架:允許所有頻率透過,但會增強(或衰減)低頻。
  • 高架:允許所有頻率透過,但會增強(或衰減)高頻。
  • 峰值:允許所有頻率透過,但會增強(或衰減)一定範圍內的頻率。
  • 陷波:允許所有頻率透過,除了設定的一組頻率。
  • 全通:允許所有頻率透過,但會改變各種頻率之間的相位關係。

注意:有關更多資訊,請參閱 BiquadFilterNode

卷積和脈衝

也可以使用 ConvolverNode 將脈衝響應應用於音訊。脈衝響應是在短暫的脈衝聲音(如拍手聲)後產生的聲音。脈衝響應將表示產生脈衝的環境(例如,在隧道中拍手產生的回聲)。

示例

js
const convolver = context.createConvolver();
convolver.buffer = this.impulseResponseBuffer;
// Connect the graph.
source.connect(convolver);
convolver.connect(context.destination);

請參閱此 Codepen 以檢視應用的(但非常非常愚蠢;就像小孩子會咯咯的笑那樣愚蠢)示例。

空間音訊

我們還可以使用聲像節點來定位音訊。聲像節點——PannerNode——允許我們定義一個源錐以及位置和方向元素,所有這些都在使用 3D 笛卡爾座標定義的 3D 空間中。

示例

js
const panner = context.createPanner();
panner.coneOuterGain = 0.2;
panner.coneOuterAngle = 120;
panner.coneInnerAngle = 0;

panner.connect(context.destination);
source.connect(panner);
source.start(0);

// Position the listener at the origin.
context.listener.setPosition(0, 0, 0);

JavaScript 編解碼器

也可以使用 JavaScript 在低級別操作音訊。如果您想建立音訊編解碼器,這將很有用。

目前存在以下格式的庫

注意:在 Audiocogs,您可以 試用一些演示;Audiocogs 還提供了一個框架,Aurora.js,旨在幫助您使用 JavaScript 編寫自己的編解碼器。

示例

另請參閱

教程

參考