音频和视频处理

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 编写自己的编解码器。

示例

另请参阅

教程

参考