音訊和影片操作
Web的美妙之處在於您可以將多種技術結合起來創造新的形式。瀏覽器原生支援音訊和影片,這意味著我們可以使用這些資料流結合諸如 <canvas>、WebGL 或 Web Audio API 等技術來直接修改音訊和影片。例如,為音訊新增混響/壓縮效果,或為影片新增灰度/硒色濾鏡。本文提供了一份參考指南,解釋您需要做什麼。
影片操作
能夠讀取影片每一幀的畫素值非常有用。
影片和 Canvas
<canvas> 元素為在網頁上繪製圖形提供了一個表面;它功能強大,並且可以與影片緊密結合。
通用技術是
- 將
<video>元素的幀寫入<canvas>元素。 - 讀取
<canvas>元素的資料並進行操作。 - 將操作後的資料寫入您的“顯示”
<canvas>(實際上可以是同一個元素)。 - 暫停並重復。
例如,我們來處理一個影片以灰度顯示它。在這種情況下,我們將同時顯示源影片和輸出的灰度幀。通常情況下,如果您要實現“以灰度播放影片”的功能,您可能會為 <video> 元素新增 display: none 樣式,以避免在顯示僅顯示經過修改幀的 Canvas 時,源影片也顯示在螢幕上。
HTML
我們可以這樣設定我們的影片播放器和 <canvas> 元素
<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
此程式碼處理幀的修改。
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();
});
},
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);
},
};
頁面載入完成後,您可以呼叫
processor.doLoad();
結果
這是一個使用 Canvas 操作影片幀的示例。為了提高效率,您應該考慮在支援 requestAnimationFrame() 的瀏覽器上使用它,而不是 setTimeout()。
您可以透過將 <video> 元素的 grayscale() CSS 函式應用於源 <video> 元素來實現相同的結果。
注意: 由於潛在的安全問題(如果您的影片與您的程式碼不在同一個域),您需要在您的影片伺服器上啟用 CORS(跨源資源共享)。
影片和 WebGL
WebGL 是一個強大的 API,它使用 Canvas 繪製硬體加速的 3D 或 2D 場景。您可以將 WebGL 與 <video> 元素結合起來建立影片紋理,這意味著您可以在 3D 場景中嵌入影片。
注意: 您可以在 GitHub 上找到此演示的原始碼(也可以 線上檢視)。
播放速率
我們還可以透過 <audio> 和 <video> 元素的 playbackRate 屬性來調整音訊和影片的播放速率。playbackRate 是一個數字,表示應用於播放速率的倍數,例如 0.5 表示半速,2 表示雙速。
請注意,playbackRate 屬性同時適用於 <audio> 和 <video>,但在這兩種情況下,它都只改變播放速度,而不改變音調。要操作音訊的音調,您需要使用 Web Audio API。請參閱 AudioBufferSourceNode.playbackRate 屬性。
<video id="my-video" controls loop>
<source src="/shared-assets/videos/flower.mp4" type="video/mp4" />
<source src="/shared-assets/videos/flower.webm" type="video/webm" />
</video>
<label for="rate">Playback rate <output id="rate-value">1.0</output></label>
<input type="range" id="rate" name="rate" min="0" max="4" value="1" step=".2" />
const rateSlider = document.getElementById("rate");
const rateValue = document.getElementById("rate-value");
const myVideo = document.getElementById("my-video");
rateSlider.addEventListener("input", () => {
myVideo.playbackRate = rateSlider.value;
rateValue.textContent = parseFloat(rateSlider.value);
});
開始播放影片,然後調整滑塊以更改媒體的播放速率
音訊操作
除了 playbackRate 之外,要操作音訊,您通常會使用 Web Audio API。
選擇音訊源
Web Audio API 可以從各種來源接收音訊,然後對其進行處理,並將其傳送回一個 AudioDestinationNode,該節點代表處理後傳送聲音的輸出裝置。
| 如果音訊源是… | 使用此 Web Audio 節點型別 |
|---|---|
來自 HTML <audio> 或 <video> 元素的音訊軌道 |
MediaElementAudioSourceNode |
| 記憶體中的純原始音訊資料緩衝區 | AudioBufferSourceNode |
| 生成正弦波或其他計算波形的振盪器 | OscillatorNode |
來自 WebRTC 的音訊軌道(例如,您可以使用 getUserMedia() 獲取的麥克風輸入)。 |
MediaStreamAudioSourceNode |
音訊濾波器
Web Audio API 提供了許多不同的濾波器/效果,可以使用 BiquadFilterNode 等進行應用,例如。
<video id="my-video" controls loop>
<source src="/shared-assets/videos/friday.mp4" type="video/mp4" />
</video>
<label for="freq">Filter freq. <output id="freq-value">1.0</output>hz</label>
<input type="range" id="freq" name="freq" max="20000" value="1000" step="100" />
const freqSlider = document.getElementById("freq");
const freqValue = document.getElementById("freq-value");
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 = 20;
freqSlider.addEventListener("input", () => {
filter.frequency.value = freqSlider.value;
freqValue.textContent = parseFloat(freqSlider.value);
});
注意: 除非您啟用了 CORS,否則為了避免安全問題,您的影片應與您的程式碼在同一域上。
常用音訊濾波器
以下是一些您可以應用的常見音訊濾波器型別
- 低通:允許低於截止頻率的頻率透過,並衰減高於截止頻率的頻率。
- 高通:允許高於截止頻率的頻率透過,並衰減低於截止頻率的頻率。
- 帶通:允許一定範圍的頻率透過,並衰減此頻率範圍之外的頻率。
- 低架:允許所有頻率透過,但對較低頻率進行增強(或衰減)。
- 高架:允許所有頻率透過,但對較高頻率進行增強(或衰減)。
- 峰值:允許所有頻率透過,但對一定範圍的頻率進行增強(或衰減)。
- 陷波:允許所有頻率透過,除了特定頻率範圍。
- 全通:允許所有頻率透過,但改變了各個頻率之間的相位關係。
注意: 有關更多資訊,請參閱 BiquadFilterNode。
卷積和衝激
還可以使用 ConvolverNode 將衝激響應應用於音訊。衝激響應是指在短暫的聲音脈衝(如拍手聲)之後產生的聲音。衝激響應將指示脈衝產生的環境(例如,在隧道中拍手產生的回聲)。
示例
const convolver = context.createConvolver();
convolver.buffer = this.impulseResponseBuffer;
// Connect the graph.
source.connect(convolver);
convolver.connect(context.destination);
請參閱我們的 HolySpaceCow 示例,這是一個應用(但非常非常愚蠢)的示例。
空間音訊
我們還可以使用聲像節點來定位音訊。聲像節點—PannerNode—允許我們定義一個聲源錐體以及位置和方向元素,所有這些都以 3D 笛卡爾座標定義的 3D 空間中的。
示例
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);
注意: 您可以在 我們的 GitHub 儲存庫中找到一個示例(也可以 線上檢視)。
示例
另見
指南
參考
<audio>和<video>元素HTMLMediaElementAPI<canvas>元素- Web Audio API
- AudioContext
- 關於 空間音訊的更多資訊
- Web 媒體技術