音频和视频传输

我们可以在网络上以多种方式交付音频和视频,从“静态”媒体文件到自适应直播流。本文旨在作为一个起点,探索基于网络的媒体的各种交付机制以及与流行浏览器的兼容性。

音频和视频 HTML 元素

无论是预录制的音频文件还是直播流,通过浏览器的 <audio><video> 元素使其可用的机制基本相同。目前,为了支持所有浏览器,我们需要指定两种格式,尽管随着 MP3 和 MP4 格式在 Firefox 和 Opera 中的采用,这种情况正在迅速改变。您可以在网络媒体类型和格式指南中找到兼容性信息。

要交付视频和音频,通常的工作流程如下:

  1. 通过功能检测检查浏览器支持哪种格式(通常如上所述,有两种选择)。
  2. 如果浏览器原生不支持任何提供的格式的播放,则显示静止图像或使用备用技术来呈现视频。
  3. 确定您希望如何播放/实例化媒体(例如,一个 <video> 元素,或者 document.createElement('video') 怎么样?)。
  4. 将媒体文件交付给播放器。

HTML 音频

html
<audio controls preload="auto">
  <source src="audio-file.mp3" type="audio/mpeg" />

  <!-- fallback for browsers that don't support mp3 -->
  <source src="audio-file.ogg" type="audio/ogg" />

  <!-- fallback for browsers that don't support audio element -->
  <a href="audio-file.mp3">download audio</a>
</audio>

上面的代码将创建一个音频播放器,该播放器会尝试尽可能多地预加载音频以实现流畅播放。

注意: preload 属性可能会被某些移动浏览器忽略。

有关更多信息,请参阅跨浏览器音频基础 (HTML 音频详解)

HTML 视频

html
<video
  controls
  width="640"
  height="480"
  poster="initial-image.png"
  autoplay
  muted>
  <source src="video-file.mp4" type="video/mp4" />

  <!-- fallback for browsers that don't support mp4 -->
  <source src="video-file.webm" type="video/webm" />

  <!-- specifying subtitle files -->
  <track src="subtitles_en.vtt" kind="subtitles" srclang="en" label="English" />
  <track
    src="subtitles_no.vtt"
    kind="subtitles"
    srclang="no"
    label="Norwegian" />

  <!-- fallback for browsers that don't support video element -->
  <a href="video-file.mp4">download video</a>
</video>

上面的代码创建了一个尺寸为 640x480 像素的视频播放器,在视频播放之前显示海报图像。我们指示视频自动播放但默认静音。

注意: autoplay 属性可能会被某些移动浏览器忽略。此外,自动播放功能如果滥用可能会引起争议。强烈建议您阅读媒体和 Web 音频 API 自动播放指南,以了解如何明智地使用自动播放。

有关更多信息,请参阅<video> 元素创建跨浏览器视频播放器

JavaScript 音频

js
const myAudio = document.createElement("audio");

if (myAudio.canPlayType("audio/mpeg")) {
  myAudio.setAttribute("src", "audio-file.mp3");
} else if (myAudio.canPlayType("audio/ogg")) {
  myAudio.setAttribute("src", "audio-file.ogg");
}

myAudio.currentTime = 5;
myAudio.play();

我们根据浏览器支持的音频文件类型设置音频源,然后将播放头设置在 5 秒处并尝试播放它。

注意: 除非由用户启动的事件触发,否则大多数浏览器将忽略播放。

还可以向 <audio> 元素提供 Base64 编码的 WAV 文件,从而能够即时生成音频。

html
<audio id="player" src="data:audio/x-wav;base64,UklGRvC…"></audio>

Speak.js 采用了这种技术。

JavaScript 视频

js
const myVideo = document.createElement("video");

if (myVideo.canPlayType("video/mp4")) {
  myVideo.setAttribute("src", "video-file.mp4");
} else if (myVideo.canPlayType("video/webm")) {
  myVideo.setAttribute("src", "video-file.webm");
}

myVideo.width = 480;
myVideo.height = 320;

我们根据浏览器支持的视频文件类型设置视频源,然后设置视频的宽度和高度。

Web Audio API

在此示例中,我们使用 fetch() API 检索 MP3 文件,将其加载到源中,然后播放。

js
let audioCtx;
let buffer;
let source;

async function loadAudio() {
  try {
    // Load an audio file
    const response = await fetch("viper.mp3");
    // Decode it
    buffer = await audioCtx.decodeAudioData(await response.arrayBuffer());
  } catch (err) {
    console.error(`Unable to fetch the audio file. Error: ${err.message}`);
  }
}

const play = document.getElementById("play");
play.addEventListener("click", async () => {
  if (!audioCtx) {
    audioCtx = new AudioContext();
    await loadAudio();
  }
  source = audioCtx.createBufferSource();
  source.buffer = buffer;
  source.connect(audioCtx.destination);
  source.start();
  play.disabled = true;
});

您可以在线运行完整示例,或查看源代码

使用 Web Audio API中查找有关 Web Audio API 基础知识的更多信息。

getUserMedia / Stream API

还可以使用 getUserMedia 和 Stream API 从网络摄像头和/或麦克风获取直播流。这是 WebRTC(Web 实时通信)这项更广泛技术的一部分,并与最新版本的 Chrome、Firefox 和 Opera 兼容。

要从网络摄像头获取流,首先设置一个 <video> 元素

html
<video id="webcam" width="480" height="360"></video>

接下来,如果支持,将网络摄像头源连接到视频元素

js
if (navigator.mediaDevices) {
  navigator.mediaDevices
    .getUserMedia({ video: true, audio: false })
    .then((stream) => {
      const video = document.getElementById("webcam");
      video.autoplay = true;
      video.srcObject = stream;
    })
    .catch(() => {
      alert(
        "There has been a problem retrieving the streams - are you running on file:/// or did you disallow access?",
      );
    });
} else {
  alert("getUserMedia is not supported in this browser.");
}

要了解更多信息,请阅读我们的 MediaDevices.getUserMedia 页面。

MediaStream Recording

正在推出新标准,允许您的浏览器使用 getUserMedia 从麦克风或摄像头获取媒体,并使用新的 MediaStream Recording API 立即录制。您从 getUserMedia 接收到的流,将其传递给 MediaRecorder 对象,获取结果输出并将其馈送到您的音频或视频源*。

主要机制如下所述

js
navigator.mediaDevices
  .getUserMedia({ audio: true })
  .then((stream) => {
    const recorder = new MediaRecorder(stream);

    const data = [];
    recorder.ondataavailable = (e) => {
      data.push(e.data);
    };
    recorder.start();
    recorder.onerror = (e) => {
      throw e.error || new Error(e.name); // e.name is FF non-spec
    };
    recorder.onstop = (e) => {
      const audio = document.createElement("audio");
      audio.src = window.URL.createObjectURL(new Blob(data));
    };
    setTimeout(() => {
      rec.stop();
    }, 5000);
  })
  .catch((error) => {
    console.log(error.message);
  });

有关更多详细信息,请参阅MediaStream Recording API

媒体源扩展 (MSE)

媒体源扩展 (Media Source Extensions) 是 W3C 的一个工作草案,旨在扩展 HTMLMediaElement,允许 JavaScript 生成媒体流进行播放。允许 JavaScript 生成流有助于实现各种用例,例如自适应流媒体和实时流媒体的时间平移。

加密媒体扩展 (EME)

加密媒体扩展 (Encrypted Media Extensions) 是 W3C 提出的一个提案,旨在扩展 HTMLMediaElement,提供 API 来控制受保护内容的播放。

该 API 支持从基本明文密钥解密到高价值视频的各种用例(如果用户代理实现得当)。许可证/密钥交换由应用程序控制,有助于开发支持各种内容解密和保护技术的健壮播放应用程序。

EME 的主要用途之一是允许浏览器实施 DRM (数字版权管理),这有助于防止基于网络的内容(尤其是视频)被复制。

自适应流媒体

正在推出新的格式和协议以促进自适应流媒体。自适应流媒体意味着流的带宽和通常的质量可以实时变化,以响应用户的可用带宽。自适应流媒体通常与直播流媒体结合使用,其中音频或视频的流畅交付至关重要。

用于自适应流媒体的主要格式是 HLSMPEG-DASH。MSE 的设计考虑了 DASH。MSE 根据 ISOBMFFM2TS 定义字节流(两者都受 DASH 支持,后者受 HLS 支持)。一般来说,如果您对标准感兴趣,正在寻找灵活性,或者希望支持大多数现代浏览器,那么使用 DASH 可能更好。

注意: 目前 Safari 不支持 DASH,尽管 dash.js 将在计划与 OS X Yosemite 一起发布的新版本 Safari 上运行。

DASH 还提供了许多配置文件,包括不需要预处理和拆分媒体文件的点播配置文件。还有许多基于云的服务可以将您的媒体转换为 HLS 和 DASH。

有关更多信息,请参阅直播网络音频和视频

自定义您的媒体播放器

您可能希望您的音频或视频播放器在所有浏览器中都具有一致的外观,或者只是希望对其进行调整以匹配您的网站。实现这一目标的通用技术是省略 controls 属性,以便不显示默认浏览器控件,使用 HTML 和 CSS 创建自定义控件,然后使用 JavaScript 将您的控件链接到音频/视频 API。

如果您需要额外功能,可以添加默认播放器中目前不存在的功能,例如播放速率、质量流切换甚至音频频谱。您还可以选择如何使播放器响应式——例如,您可以在某些条件下移除进度条。

您可以检测点击、触摸和/或键盘事件来触发诸如播放、暂停和擦洗等操作。为了方便用户和可访问性,记住键盘控制通常很重要。

一个快速示例——首先在 HTML 中设置您的音频和自定义控件

html
<audio id="my-audio" src="/shared-assets/audio/guitar.mp3"></audio>
<button id="my-control">play</button>

添加一些 JavaScript 来检测播放和暂停音频的事件

js
const myAudio = document.getElementById("my-audio");
const myControl = document.getElementById("my-control");

function switchState() {
  if (myAudio.paused) {
    myAudio.play();
    myControl.textContent = "pause";
  } else {
    myAudio.pause();
    myControl.textContent = "play";
  }
}

function checkKey(e) {
  if (e.code === "Space") {
    // space bar
    switchState();
  }
}

myControl.addEventListener("click", () => {
  switchState();
});

window.addEventListener("keypress", checkKey);

有关更多信息,请参阅创建您自己的自定义音频播放器

音频/视频的其他技巧

停止媒体下载

停止媒体播放就像调用元素的 pause() 方法一样简单,但浏览器会继续下载媒体,直到通过垃圾回收处理掉媒体元素。

这里有一个技巧可以立即停止下载

js
const mediaElement = document.querySelector("#myMediaElementID");
mediaElement.removeAttribute("src");
mediaElement.load();

通过删除媒体元素的 src 属性并调用 load() 方法,您可以释放与视频相关的资源,从而停止网络下载。您必须在删除属性后调用 load(),因为仅仅删除 src 属性不会调用加载算法。如果 <video> 元素还有 <source> 元素后代,则在调用 load() 之前也应将其删除。

请注意,仅仅将 src 属性设置为空字符串实际上会导致浏览器将其视为您正在将视频源设置为相对路径。这会导致浏览器尝试另一次下载可能不是有效视频的内容。

在媒体中搜索

媒体元素支持将当前播放位置移动到媒体内容的特定点。这是通过设置元素上的 currentTime 属性值来完成的;有关元素属性的更多详细信息,请参阅 HTMLMediaElement。将值设置为您希望播放继续的秒数。

您可以使用元素的 seekable 属性来确定当前可供查找的媒体范围。这会返回一个 TimeRanges 对象,其中列出了您可以查找的时间范围。

js
const mediaElement = document.querySelector("#mediaElementID");
mediaElement.seekable.start(0); // Returns the starting time (in seconds)
mediaElement.seekable.end(0); // Returns the ending time (in seconds)
mediaElement.currentTime = 122; // Seek to 122 seconds
mediaElement.played.end(0); // Returns the number of seconds the browser has played

指定播放范围

当为 <audio><video> 元素指定媒体 URI 时,您可以选择包含附加信息以指定要播放的媒体部分。为此,请附加一个哈希标记 ("#"),后跟媒体片段描述。

时间范围使用以下语法指定

#t=[starttime][,endtime]

时间可以指定为秒数(浮点值)或用冒号分隔的小时/分钟/秒时间(例如,2:05:01 表示 2 小时 5 分钟 1 秒)。

几个例子

http://example.com/video.ogv#t=10,20

指定视频应播放 10 秒到 20 秒的范围。

http://example.com/video.ogv#t=,10.5

指定视频应从头开始播放到 10.5 秒。

http://example.com/video.ogv#t=,02:00:00

指定视频应从头开始播放到两小时。

http://example.com/video.ogv#t=60

指定视频应从 60 秒开始播放,并播放到视频结束。

错误处理

错误会传递给导致错误的子 <source> 元素对应的源。

这让您可以检测哪些源加载失败,这可能很有用。考虑以下 HTML

html
<video>
  <source
    id="mp4_src"
    src="video.mp4"
    type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
  <source
    id="3gp_src"
    src="video.3gp"
    type='video/3gpp; codecs="mp4v.20.8, samr"' />
  <source
    id="ogg_src"
    src="video.ogv"
    type='video/ogv; codecs="theora, vorbis"' />
</video>

由于 Firefox 在某些平台上由于专利受限的性质不支持 MP4 和 3GP,ID 为“mp4_src”和“3gp_src”的 <source> 元素将在 Ogg 资源加载之前接收 error 事件。源按它们出现的顺序尝试,一旦一个成功加载,其余的源根本不会尝试。

检查浏览器是否支持所提供的格式

媒体格式的支持可在Can I Use上找到。

您还可以搜索其他媒体格式

如果媒体格式应该支持但您提供的文件无法播放,则可能存在两个问题

1. 媒体服务器未随文件提供正确的 MIME 类型

尽管这通常受支持,但您可能需要将以下内容添加到媒体服务器的 .htaccess 文件中。

# AddType TYPE/SUBTYPE EXTENSION

AddType audio/mpeg mp3
AddType audio/mp4 m4a
AddType audio/ogg ogg
AddType audio/ogg oga

AddType video/mp4 mp4
AddType video/mp4 m4v
AddType video/ogg ogv
AddType video/webm webm
AddType video/webm webmv

2. 您的文件编码不正确

您的文件可能编码不正确——尝试使用以下工具之一进行编码,它们已被证明相当可靠

  • Audacity — 免费音频编辑器和录音机
  • Miro — 免费开源音乐和视频播放器
  • Handbrake — 开源视频转码器
  • Firefogg — Firefox 的视频和音频编码
  • FFmpeg2 — 综合命令行编码器
  • Vid.ly — 视频播放器、转码和交付
  • Internet Archive — 免费转码和存储

检测何时未加载任何源

要检测所有子 <source> 元素是否都加载失败,请检查媒体元素的 networkState 属性的值。如果这是 HTMLMediaElement.NETWORK_NO_SOURCE,您就知道所有源都加载失败了。

此时,如果您通过将新的 <source> 元素作为媒体元素的子元素插入来添加另一个源,Gecko 会尝试加载指定的资源。

当无法解码任何源时显示备用内容

在当前浏览器中无法解码任何源时显示视频备用内容的另一种方法是在最后一个源元素上添加一个错误处理程序。然后,您可以将视频替换为备用内容

html
<video controls>
  <source src="dynamicsearch.mp4" type="video/mp4" />
  <a href="dynamicsearch.mp4">
    <img src="dynamicsearch.jpg" alt="Dynamic app search in Firefox OS" />
  </a>
  <p>Click image to play a video demo of dynamic app search</p>
</video>
js
const v = document.querySelector("video");
const sources = v.querySelectorAll("source");
const lastSource = sources[sources.length - 1];
lastSource.addEventListener("error", (ev) => {
  const d = document.createElement("div");
  d.innerHTML = v.innerHTML;
  v.parentNode.replaceChild(d, v);
});

音频/视频 JavaScript 库

存在许多音频和视频 JavaScript 库。最流行的库允许您在所有浏览器中选择一致的播放器设计,并为不支持音频和视频的浏览器提供备用方案。备用方案历来使用现在已过时的插件,如 Adobe Flash 或 Microsoft Silverlight 插件,以在不支持的浏览器中提供媒体播放器,尽管这些插件在现代计算机上不再受支持。字幕的 <track> 元素等其他功能也可以通过媒体库提供。

仅音频

仅视频

  • flowplayer:免费提供 flowplayer 徽标水印。开源(GPL 许可)。
  • JWPlayer:需要注册才能下载。开源版(Creative Commons 许可)。
  • SublimeVideo:需要注册。基于表单设置,带有特定域链接到 CDN 托管库。
  • Video.js:免费和开源(Apache 2 许可)。

音频和视频

Web Audio API

指南

创建跨浏览器视频播放器

使用 <video> 元素创建基本跨浏览器视频播放器的指南。

视频播放器样式基础

在前一篇文章中放置了跨浏览器视频播放器之后,本文现在着眼于为播放器提供一些基本的响应式样式。

为 HTML 视频添加字幕和副标题

本文解释了如何使用 Web_Video_Text_Tracks_Format<track> 元素为 HTML <video> 添加字幕和副标题。

跨浏览器音频基础

本文提供了一份创建跨浏览器 HTML 音频播放器的基本指南,其中解释了所有相关的属性、特性和事件,并提供了使用媒体 API 创建自定义控件的快速指南。

媒体缓冲、查找和时间范围

有时了解 <audio><video> 已下载或可以无延迟播放多少内容会很有用——一个很好的例子是音频或视频播放器的缓冲进度条。本文讨论了如何使用 TimeRanges 以及媒体 API 的其他功能来构建缓冲/查找条。

HTML playbackRate 详解

playbackRate 属性允许我们改变网络音频或视频播放的速度或速率。本文详细解释了它。

使用 Web Audio API

解释了使用 Web Audio API 获取、操作和播放音频源的基础知识。

流媒体

直播网络音频和视频

直播流技术通常用于转播体育赛事、音乐会以及更普遍的电视和广播节目的直播。通常简称为流媒体,直播流是将媒体“实时”传输到计算机和设备的过程。这是一个相当复杂且新兴的主题,有很多变量,因此在本文中,我们将向您介绍该主题,并让您了解如何入门。

设置自适应流媒体源

假设您想在服务器上设置自适应流媒体源,以便在 HTML 媒体元素中进行消费。您将如何做到这一点?本文将解释如何实现,并着眼于两种最常见的格式:MPEG-DASH 和 HLS(HTTP Live Streaming)。

适用于 HTML 5 视频的 DASH 自适应流媒体

详细说明如何使用 DASH 和 WebM 设置自适应流媒体。

高级主题

Web Audio API 跨浏览器支持

编写跨浏览器 Web Audio API 代码的指南。

使用 MediaRecorder API 轻松捕获音频

解释了使用 MediaStream Recording API 直接录制媒体流的基础知识。

参考