音訊和影片處理
Web 的魅力在於您可以將技術結合起來建立新形式。在瀏覽器中擁有原生音訊和影片意味著我們可以將這些資料流與 <canvas>、WebGL 或 Web 音訊 API 等技術結合起來,直接修改音訊和影片,例如,向音訊新增混響/壓縮效果,或向影片新增灰度/棕褐色濾鏡。本文提供一個參考來解釋您需要做什麼。
影片處理
能夠讀取影片每幀的畫素值非常有用。
影片和畫布
<canvas> 元素提供了一個在網頁上繪製圖形的表面;它功能強大,可以與影片緊密結合。
一般技術是
- 將來自
<video>元素的一幀寫入<canvas>元素。 - 讀取
<canvas>元素中的資料並進行操作。 - 將操作後的資料寫入您的“顯示”
<canvas>(實際上可以是同一個元素)。 - 暫停並重復。
例如,讓我們處理一個影片以將其以灰度顯示。在這種情況下,我們將同時顯示源影片和輸出灰度幀。通常,如果您要實現“以灰度播放影片”功能,您可能會將 display: none 新增到 <video> 元素的樣式中,以防止源影片在顯示更改後的幀時被繪製到螢幕上。
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();
},
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;
},
};
頁面載入後,您可以呼叫
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
<video
id="my-video"
controls
src="https://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"></video>
JavaScript
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
<video id="my-video" controls src="myvideo.mp4" type="video/mp4"></video>
JavaScript
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 將脈衝響應應用於音訊。脈衝響應是在短暫的脈衝聲音(如拍手聲)後產生的聲音。脈衝響應將表示產生脈衝的環境(例如,在隧道中拍手產生的回聲)。
示例
const convolver = context.createConvolver();
convolver.buffer = this.impulseResponseBuffer;
// Connect the graph.
source.connect(convolver);
convolver.connect(context.destination);
請參閱此 Codepen 以檢視應用的(但非常非常愚蠢;就像小孩子會咯咯的笑那樣愚蠢)示例。
空間音訊
我們還可以使用聲像節點來定位音訊。聲像節點——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 儲存庫上找到一個示例(即時檢視)。
JavaScript 編解碼器
示例
另請參閱
教程
參考
<audio>和<video>元素HTMLMediaElementAPI<canvas>元素- Web Audio API
- AudioContext
- 有關空間音訊的更多資訊
- Web 媒體技術