如果您正在寻找播放受DRM保护内容的库,传播直播或将内容货币化,则 shaka Player 可以做到所有这些,等等! Shaka Player是一个开源库,是媒体播放的第二大图书馆。该库使用本机浏览器API,例如MediaSource和Encrypted Media Extensions。本文将帮助您实施Shaka Player的基本实施,描述其功能并提出其优势和劣势。
一点介绍
Shaka Player的核心使用引擎盖下的一些本机浏览器API:
- 加密的媒体扩展( eme )API,当浏览器接收视频并发射“加密”的侦听器时。 This Google article在解释它的“下层”工作以及如何以及何时使用它方面做得很棒。
-
媒体源扩展 API,可帮助创建和将视频段组合在一起,插入广告并根据设备功能和性能更改视频分辨率。 Another Google article以可访问的方式更详细地解释了这些概念。
-
MediaCapabilities API确定您的设备是否支持您要播放的媒体,并可以告诉您您的媒体配置功能是否允许光滑且有效的播放。
-
IndexedDB API用于缓存下载的视频,然后允许脱机播放。
shaka播放器通常与后端与Shaka Packager结合使用,以添加内容保护,文本流,将媒体文件分解为流段以进行流并创建DASH的元数据或为HLS创建相应的包装。 p>
基本用法
出于本文的目的,我们将使用免费的Dash清单from here
要在您的项目中下载并使用Shaka Player,您可以通过两种方式进行操作:
npm install --save shaka-player
或
yarn add shaka-player
注意:如果您在项目中使用Typescript,则需要在项目中的d.ts
文件中声明类型,例如:
declare module 'shaka-player' {
export = shaka;
}
declare module 'shaka-player/dist/shaka-player.compiled' {
export = shaka;
}
Shaka将开始支持V5中的类型,如here
为了启动播放器实例,您需要html中的<video>
元素,您可以附加到:
<!DOCTYPE html>
<html>
<head>
<title>Basic Shaka implementation</title>
<meta charset="UTF-8" />
</head>
<body>
<video id="video" width="640" height="480" controls></video>
<script src="index.js"></script>
</body>
</html>
现在,在index.js
中:
import shaka from "shaka-player";
const exampleManifestUri =
"https://bitmovin-a.akamaihd.net
/content/MI201109210084_1
/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd";
async function initPlayer() {
// Install polyfills to patch out browser incompatibilities
shaka.polyfill.installAll();
// Check if your browser supports Shaka at all
if (!shaka.Player.isBrowserSupported()) {
console.error("Browser not supported!");
return;
}
//Search for available video element and attach the player to it
const video = document.getElementById("video");
const player = new shaka.Player(video);
// listen for errors for further error handling
player.addEventListener("error", console.error);
try {
await player.load(exampleManifestUri);
console.log("player has loaded the video, you can play it now");
} catch (error) {
console.log(error);
}
}
document.addEventListener("DOMContentLoaded", initPlayer);
使用控制
Shaka Player有自己的控件UI,您可以在播放器启动之前添加。为此,我们需要更新我们的HTML和JavaScript代码。
在我们的html中,我们必须添加样式和一个容器元素:
<!DOCTYPE html>
<html>
<head>
<title>Shaka player built-in UI example</title>
<meta charset="UTF-8" />
<!-- for the sake of this article we
use a sandbox path to shaka styles -->
<link
rel="stylesheet"
type="text/css"
href="node_modules/shaka-player/dist/controls.css"
/>
<link rel="stylesheet" type="text/css" href="src/styles.css" />
</head>
<body>
<!-- We need a container to build the UI on top of it -->
<div id="container" style="width: 100%; height: 100%;">
<video autoplay id="video"></video>
</div>
<script src="src/index.js"></script>
</body>
</html>
在我们的JavaScript代码中,我们更改导入源并添加更多逻辑:
/* we need to import the shaka ui module instead of
the regular module to gain access to the Overlay constructor */
import shaka from "shaka-player/dist/shaka-player.ui.js";
const manifestUri =
"https://bitmovin-a.akamaihd.net/content
/MI201109210084_1
/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd";
async function init() {
const video = document.getElementById("video");
const container = document.getElementById("container");
const player = new shaka.Player(video);
// initialize the UI instance onto the HTML element we created
const ui = new shaka.ui.Overlay(player, container, video);
const controls = ui.getControls();
// Listen for error events for possible error handling.
player.addEventListener("error", console.error);
controls.addEventListener("error", console.error);
try {
await player.load(manifestUri);
} catch (e) {
console.error(e);
}
}
/* Listen to the custom shaka-ui-loaded event,
to wait until the UI is loaded. */
document.addEventListener("shaka-ui-loaded", init);
现在,玩家控件应在您的播放器覆盖中可见。
注意:如果您想脱颖而出,可以使用custom shaka styles !
添加配置
shaka播放器使您可以配置播放器实例及其控件。想象一下,您在内容中添加了DRM保护,或者想缓存视频,或者想在控件中添加更多功能。所有这些都是可能的configure
方法。
让我们从第二个10开始我们的视频,然后在我们的控件中添加工具提示:
async function init() {
const video = document.getElementById("video");
const container = document.getElementById("container");
const player = new shaka.Player(video);
// initialize the UI instance onto the HTML element we created
const ui = new shaka.ui.Overlay(player, container, video);
player.configure({
playRangeStart: 10
});
ui.configure({
enableTooltips: true
});
const controls = ui.getControls();
// Listen for error events for possible error handling.
player.addEventListener("error", console.error);
controls.addEventListener("error", console.error);
try {
await player.load(manifestUri);
} catch (e) {
console.error(e);
}
}
使用player config和UI config您可以做更多的事情 - 添加自定义DRM源,切换媒体自动改编,添加更多UI功能等。
离线播放
shaka允许我们下载资产并将其存储在浏览器数据库中(从上方索引了DB API)。下图中的代码可能更复杂,但是其中一些已经看起来很熟悉。
import shaka from "shaka-player/dist/shaka-player.ui.js";
const exampleManifestUri =
"https://bitmovin-a.akamaihd.net
/content/MI201109210084_1/mpds
/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd";
function initApp() {
// Install built-in polyfills to patch browser incompatibilities.
shaka.polyfill.installAll();
/* Check to see if the browser supports
the basic APIs Shaka needs.*/
if (!shaka.Player.isBrowserSupported()) {
// This browser does not have the minimum set of APIs we need.
console.error("Browser not supported!");
}
addNetworkListeners();
}
// this function initializes the player and adds the event listeners
async function initPlayer() {
const video = document.getElementById("video");
const container = document.getElementById("container");
const player = new shaka.Player(video);
/* we will need this in other functions
so we assign it to the window object */
window.player = player;
const ui = new shaka.ui.Overlay(player, container, video);
const controls = ui.getControls();
controls.addEventListener("error", console.error);
player.addEventListener("error", console.error);
initOfflineStorage(player);
const downloadButton = document.getElementById("download-button");
downloadButton.addEventListener("click", downloadContent);
try {
await player.load(exampleManifestUri);
} catch (error) {
console.error(error);
}
}
/* Update the online status and add listeners so that we can display
the network state to the user. */
function addNetworkListeners() {
updateOnlineStatus();
window.addEventListener("online", updateOnlineStatus);
window.addEventListener("offline", updateOnlineStatus);
}
/* grabs an HTML element and modifies it
depending on your network status */
function updateOnlineStatus() {
const signal = document.getElementById("online-indicator");
if (navigator.onLine) {
signal.innerHTML = "You are ONLINE";
signal.style.background = "green";
} else {
signal.innerHTML = "You are OFFLINE";
signal.style.background = "black";
}
}
// downloads the content and stores it in the browser
async function downloadContent(event) {
event.target.disabled = true;
try {
const metadata = {
title: "Test content",
downloaded: new Date(),
};
// use shaka.offline.Storage to download the content
console.log("Downloading content...");
await window.storage.store(exampleManifestUri, metadata);
console.log("Content downloaded!");
} catch (error) {
console.error(error);
}
}
function initOfflineStorage(player) {
/* assign the storage object to the window so that we can
access it later */
window.storage = new shaka.offline.Storage(player);
window.storage.configure({
offline: {
progressCallback: setDownloadProgress,
},
});
refreshDownloads();
}
// updates the progress number in the HTML
function setDownloadProgress(_, progress) {
const progressElement = document.getElementById("download-progress");
const progressInPercent = progress.toFixed(2) * 100;
progressElement.setAttribute("value", progressInPercent);
progressElement.innerText = `${Math.floor(progressInPercent)}%`;
if (progress === 1) {
// refresh the download list when the download is finished
refreshDownloads();
}
}
// fetches list of downloaded files in indexedDB
async function refreshDownloads() {
const downloadList = document.getElementById("downloaded-content");
const content = await window.storage.list();
downloadList.innerHTML = "";
if (content.length === 0) {
const listItem = document.createElement("li");
listItem.innerText = "No downloads yet";
downloadList.appendChild(listItem);
return;
}
/* list content from indexedDB and
add buttons to play and remove content */
content.forEach((item) => {
const listItem = document.createElement("li");
const playButton = document.createElement("button");
playButton.className = "play-button";
playButton.innerText = "Play";
playButton.addEventListener("click", () => {
window.player.load(item.offlineUri);
});
const removeButton = document.createElement("button");
removeButton.className = "remove-button";
removeButton.innerText = "Remove";
removeButton.addEventListener("click", async () => {
await window.storage.remove(item.offlineUri);
refreshDownloads();
});
listItem.innerText = item.appMetadata.title;
listItem.appendChild(playButton);
listItem.appendChild(removeButton);
downloadList.appendChild(listItem);
const downloadButton = document.getElementById("download-button");
downloadButton.disabled = false;
});
}
document.addEventListener("DOMContentLoaded", initApp);
document.addEventListener("shaka-ui-loaded", initPlayer);
indexedDB在CodeSandbox中不起作用,因此我创建了一个小的git repository with the working feature供您在本地进行测试。
集成广告
如果您正在阅读本文,那么您会经历最困难的部分 - 将广告整合到Shaka中很轻松!让我们从头开始:
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>Shaka player built-in UI example</title>
<meta charset="UTF-8" />
<!-- for the sake of this article
we use a sandbox path to shaka styles -->
<link
rel="stylesheet"
type="text/css"
href="node_modules/shaka-player/dist/controls.css"
/>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<!-- We need a container to build the UI on top of it -->
<div id="container" style="width: 100%; height: 100%">
<video autoplay id="video"></video>
</div>
<!-- add client-side IMA SDK -->
<script
type="text/javascript"
src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"
></script>
<script type="module" src="src/index.js"></script>
</body>
</html>
在我们的JS文件中,我们将在播放器初始化之后初始化广告管理器:
import shaka from "shaka-player/dist/shaka-player.ui.js";
const exampleManifestUri =
"https://bitmovin-a.akamaihd.net/content/
MI201109210084_1/mpds
/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd";
function initApp() {
// Install built-in polyfills to patch browser incompatibilities.
shaka.polyfill.installAll();
// Check to see if the browser supports the basic APIs Shaka needs.
if (!shaka.Player.isBrowserSupported()) {
// This browser does not have the minimum set of APIs we need.
console.error("Browser not supported!");
return;
}
}
/* This function initializes the player
and adds the event listeners */
async function initPlayer() {
const video = document.getElementById("video");
const container = document.getElementById("container");
const player = new shaka.Player(video);
/* we will need this in other functions
so we assign it to the window object */
window.player = player;
const ui = new shaka.ui.Overlay(player, container, video);
const controls = ui.getControls();
controls.addEventListener("error", console.error);
player.addEventListener("error", console.error);
/* Initiates the client-side ad manager
and attaches it to the player */
const adManager = player.getAdManager();
const adContainer = video.ui
.getControls()
.getClientSideAdContainer();
adManager.initClientSide(adContainer, video);
runSampleAd();
try {
await player.load(exampleManifestUri);
} catch (error) {
console.error(error);
}
}
function runSampleAd() {
/* the script we added to index.html
adds the google object to the window */
const google = window.google;
const adUrl =
"https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923
/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3D
linear&ciu_szs=300x250%2C728x90&gdfp_req=1
&output=vast&unviewed_position_start=1
&env=vp&impl=s&correlator=";
const adsRequest = new google.ima.AdsRequest();
adsRequest.adTagUrl = adUrl;
const adManager = player.getAdManager();
adManager.requestClientSideAds(adsRequest);
}
document.addEventListener("DOMContentLoaded", initApp);
document.addEventListener("shaka-ui-loaded", initPlayer);
This GitHub repo是此功能的一个工作示例,因为Codesandbox不允许第三方脚本提出请求。
利弊
,由于它是一个多功能的图书馆,因此很难不偏向Shaka Player,但我会尽力保持客观。
为什么shaka是好:
- 令人惊叹的社区支持,尤其是维护者。
- 您的大部分视频流有关功能都可以从包装盒中
- 高度配置
- 非常简单的基本实现
Shaka可以在哪里改善:
- 打字稿支持
- 图书馆不可摇晃 - 无论您使用多少部分
- 许多带有可疑支持的设备/引擎
- Chromecast问题
结论
总的来说,Shaka Player是一个很棒的图书馆,可以立即将视频播放相关功能的生态系统带入您的项目。借助社区支持和相对简单的实施,Shaka生态系统可以使网络上的内容更加顺畅,并且更容易访问。本文刮了Shaka可以做的事情的表面,并提供了一些工作代码示例。如果您有任何内容可以关注此内容,请自由!