使用 Media Capabilities API
Baseline 广泛可用 *
媒体能力 API(Media Capabilities API)提供了几个关键功能,可以帮助您更好地决定如何处理媒体,以及实时确定媒体的处理效果。
这些功能包括:
- 能够查询浏览器,以确定在给定一组特定的编码参数(可能包括编解码器、分辨率、比特率、帧率等)的情况下,浏览器编码或解码媒体的能力。借助媒体能力 API,您不仅可以确定浏览器是否支持某种格式,还可以确定它是否能高效、流畅地支持。
- 更精细、更详细的显示器属性信息,以便在为用户设备选择最佳播放格式时做出明智的决策。例如,您可以使用该 API 来确保您不会尝试在标准动态范围(SDR)屏幕上播放高动态范围(HDR)内容。
- 支持获取媒体播放的实时反馈,以便您的代码可以根据此信息调整流的质量或其他设置,从而管理用户感知到的媒体性能和质量。其中一项功能是能够检测设备何时切换 GPU,以便您可以根据新 GPU 的能力进行相应调整。
注意: 上述第三点中提到的显示器能力功能尚未在任何浏览器中实现。一旦可用,它们将成为该 API 的有用功能,但在此功能在浏览器中实现之前,很可能会发生很大变化。
MediaCapabilities 接口
可以使用 `navigator` 对象和 `WorkerNavigator` 对象提供的 `mediaCapabilities` 属性来访问 MediaCapabilities。换句话说,媒体能力 API 既可以在主线程中使用,也可以在 worker 中使用。
如果该对象存在,则媒体能力 API 可用。因此,您可以像这样测试 API 的存在性:
if ("mediaCapabilities" in navigator) {
// mediaCapabilities is available
} else {
// mediaCapabilities IS NOT available
}
以视频为例,要获取有关视频解码能力的信息,您需要创建一个视频解码配置,并将其作为参数传递给 MediaCapabilities.decodingInfo() 方法。该方法返回一个 Promise,该 Promise 会解析出关于媒体能力的以下信息:视频是否可以解码,以及解码是否会流畅且节能。您也可以测试音频解码以及视频和音频编码。
创建视频解码配置
MediaCapabilities.decodingInfo() 方法接受一个媒体解码配置作为参数。
在我们的示例中,我们正在测试视频配置的解码能力。该配置需要被测试媒体的类型——例如,一个普通的 `file` 或 `MediaSource` —以及一个视频配置对象,该对象包含 `contentType`、`width`、`height`、`bitrate` 和 `framerate` 等值。
- `contentType` 必须是一个指定 有效视频 MIME 类型的字符串。
- `width` 和 `height` 是视频的水平和垂直尺寸;它们也用于确定 纵横比。
- `bitrate` 是编码一秒钟视频所使用的比特数。
- `framerate` 是播放视频时每秒钟播放的帧数。
const videoConfiguration = {
type: "file",
video: {
contentType: "video/webm;codecs=vp8",
width: 800,
height: 600,
bitrate: 10000,
framerate: 15,
},
};
如果我们查询的是音频文件的可解码性,我们将创建一个包含声道数和采样率的音频配置,并省略仅适用于视频的属性——即尺寸和帧率。
const audioConfiguration = {
type: "file",
audio: {
contentType: "audio/ogg",
channels: 2,
bitrate: 132700,
samplerate: 5200,
},
};
如果我们测试的是编码能力,我们将创建一个略有不同的配置。在这种情况下,被测试媒体的类型是 `record`(用于录制媒体,即 MediaRecorder 对象)或 `transmission`(用于通过电子方式传输的媒体,如 RTCPeerConnection)—再加上一个音频或视频配置,如上所述。
查询浏览器关于解码能力的信息
现在我们已经创建了一个视频解码配置,我们可以将其作为参数传递给 decodingInfo() 方法,以确定是否可以解码符合此配置的视频,以及播放是否流畅且节能。
let promise = navigator.mediaCapabilities.decodingInfo(videoConfiguration);
`decodingInfo()` 和 `encodingInfo()` 方法都返回 Promise。一旦 Promise 状态 fulfilled(已完成),您就可以从返回的对象中访问 `supported`、`smooth` 和 `powerEfficient` 属性。
处理响应
我们可以将 Promise 返回的值输出到控制台,而不是将 Promise 分配给一个变量:
navigator.mediaCapabilities.decodingInfo(videoConfiguration).then((result) => {
console.log(
`This configuration is ${result.supported ? "" : "not "}supported,`,
);
console.log(`${result.smooth ? "" : "not "}smooth, and`);
console.log(`${result.powerEfficient ? "" : "not "}power efficient.`);
});
处理错误
在我们的视频解码示例中,如果传递给 decodingInfo() 方法的媒体配置无效,将会引发 `TypeError`。发生错误可能有几个原因,包括:
- 指定的 `type` 不是两个允许值之一:`file` 或 `media-source`。
- 提供的 `contentType` 是:
错误可能是由于 `type` 不是两个可能值之一,`contentType` 不是有效的编解码器 MIME 类型,或者视频配置对象中缺少无效或省略的定义。
navigator.mediaCapabilities
.decodingInfo(videoConfiguration)
.then(() => console.log("It worked"))
.catch((error) => console.error(`It failed: ${error}`));
媒体能力实时示例
CSS
li {
margin: 1em;
}
HTML
<form>
<p>
Select your video configuration and find out if this browser supports the
codec, and whether decoding will be smooth and power efficient:
</p>
<ul>
<li>
<label for="codec">Select a codec</label>
<select id="codec">
<option>video/webm; codecs=vp8</option>
<option>video/webm; codecs=vp9</option>
<option>video/mp4; codecs=avc1</option>
<option>video/mp4; codecs=avc1.420034</option>
<option>invalid</option>
</select>
</li>
<li>
<label for="size">Select a size</label>
<select id="size">
<option>7680x4320</option>
<option>3840x2160</option>
<option>2560x1440</option>
<option>1920x1080</option>
<option>1280x720</option>
<option selected>800x600</option>
<option>640x480</option>
<option>320x240</option>
<option value=" x ">none</option>
</select>
</li>
<li>
<label for="framerate">Select a framerate</label>
<select id="framerate">
<option>60</option>
<option>50</option>
<option>30</option>
<option>24</option>
<option selected>15</option>
</select>
</li>
<li>
<label for="bitrate">Select a bitrate</label>
<select id="bitrate">
<option>4000</option>
<option>2500</option>
<option>800</option>
</select>
</li>
</ul>
<p>
<input type="button" value="Test this Video Configuration" id="try-it" />
</p>
</form>
<ul id="results"></ul>
JavaScript
let mc = {
videoConfiguration: {},
tryIt() {
mc.createConfiguration();
mc.testIt();
},
createConfiguration() {
const size = document.getElementById("size").value.split("x");
mc.videoConfiguration = {
type: "file",
video: {
contentType: document.getElementById("codec").value,
width: size[0],
height: size[1],
bitrate: document.getElementById("bitrate").value,
framerate: document.getElementById("framerate").value,
},
};
},
testIt() {
let content = "";
navigator.mediaCapabilities
.decodingInfo(mc.videoConfiguration)
.then((result) => {
const li = document.createElement("li"),
mcv = mc.videoConfiguration.video;
content = `A ${mcv.width}x${mcv.height}, ${mcv.contentType} at ${
mcv.framerate
}fps and ${mcv.bitrate} bps video ${
result.supported ? " IS " : "IS NOT "
} supported,`;
content += `${result.smooth ? " IS " : " is NOT "} smooth, and`;
content += `${
result.powerEfficient ? " IS " : " IS NOT "
}power efficient.`;
const ul = document.getElementById("results");
li.textContent = content;
ul.appendChild(li);
})
.catch((error) => {
const li = document.createElement("li"),
ul = document.getElementById("results");
li.textContent = `Codec ${mc.videoConfiguration.video.contentType} threw an error: ${error}`;
ul.appendChild(li);
});
},
};
document.getElementById("try-it").addEventListener("click", mc.tryIt);
实时结果
浏览器兼容性
加载中…