音频和视频操作
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>
元素HTMLMediaElement
API<canvas>
元素- Web Audio API
- AudioContext
- 关于 空间音频的更多信息
- Web 媒体技术