Files
shaka-player/tutorials/offline.html
T
Joey Parrish 139e722ce2 Use https in all tutorials
This is in preparation for a future in which SSL is required by EME.

Change-Id: I82ef395197e27fa5cc9bcaf1afa25e27b9710935
2015-09-03 14:00:08 -07:00

452 lines
14 KiB
HTML

<!--
Copyright 2015 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<h3 class="tutorial-heading">
Offline Playback
</h3>
<p>
Shaka Player supports offline playback since v1.3.0. Offline streams are handled
by {@link shaka.player.OfflineVideoSource}. The offline API works similarily to
the other video source APIs, but adds the functionality to store a group,
retrieve a list of all stored groups and to delete a group from storage.
</p>
<p>
A group refers to one video stream and one audio stream, if present, from
a DASH MPD. Storage of text content is not yet supported. Each group will
have a unique ID, which should be persisted by the application for later
playback.
</p>
<h3 class="tutorial-heading">
Storing Content
</h3>
<p>
If you have not familiarized yourself with the the Player, please start
with {@tutorial player}. In order to store content you need to install the
polyfills and initialize the player, but do not need to load the video source.
</p>
<p>
Here is a simple page which demonstrates basic offline storage:
</p>
<pre class="prettyprint source"><code id="sample7">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;title&gt;TurtleTube - Offline&lt;/title&gt;
&lt;!-- Load the Shaka Player library. --&gt;
&lt;script src="shaka-player.compiled.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;video id="video"
width="640" height="480"
crossorigin="anonymous"
controls&gt;
Your browser does not support HTML5 video.
&lt;/video&gt;
&lt;/body&gt;
&lt;script&gt;
var video;
function initPlayer() {
// Install polyfills.
shaka.polyfill.installAll();
// Find the video element.
video = document.getElementById('video');
// Attach the player to the window so that it can be easily debugged.
window.player = new shaka.player.Player(video);
// Listen for errors from the Player.
player.addEventListener('error', function(event) {
console.error(event);
});
}
function initialize() {
if (!window.player)
initPlayer();
}
function chooseTracks(videoSource) {
var ids = [];
var videoTracks = videoSource.getVideoTracks();
if (videoTracks.length) {
videoTracks.sort(shaka.player.VideoTrack.compare);
// Choosing the smallest track.
var track = videoTracks[0];
ids.push(track.id);
}
var audioTracks = videoSource.getAudioTracks();
if (audioTracks.length) {
// The video source gives you the preferred language first.
// Remove any tracks from other languages first.
var lang = audioTracks[0].lang;
audioTracks = audioTracks.filter(function(track) {
return track.lang == lang;
});
// From what's left, choose the middle stream. If we have high, medium,
// and low quality audio, this is medium. If we only have high and low,
// this is high.
var index = Math.floor(audioTracks.length / 2);
ids.push(audioTracks[index].id);
}
// Return IDs of chosen tracks.
return Promise.resolve(ids);
}
function storeContent() {
// Construct an OfflineVideoSource.
var offlineSource = new shaka.player.OfflineVideoSource(
null, // groupId, not used when storing content.
null); // estimator, optional parameter.
// Listen for progress events from the OfflineVideoSource.
offlineSource.addEventListener('progress', function(event) {
// Percentage complete is the detail field of the event.
console.log(
'Content storage is ' + event.detail.toFixed(2) + '% complete.');
});
// Store content from MPD url.
var mpdUrl = 'https://turtle-tube.appspot.com/t/t2/dash.mpd';
var preferredLanguage = 'en-US';
return offlineSource.store(
mpdUrl,
preferredLanguage,
null, // interpretContentProtection, not needed for clear content.
chooseTracks.bind(null, offlineSource)
).then(
function(groupId) {
window.groupId = groupId;
console.log('Stored content under group ID ' + groupId);
}
);
}
function test() {
initialize();
storeContent().catch(
function(e) {
console.error(e);
});
}
document.addEventListener('DOMContentLoaded', test);
&lt;/script&gt;
&lt;/html&gt;
</code></pre>
<h3 class="tutorial-heading">
Playing Stored Content
</h3>
<p>
In order to playback content, you need the group ID of the stored content. The
group ID will be used to create a new {@link shaka.player.OfflineVideoSource}
to be loaded into the {@link shaka.player.Player}.
</p>
<pre class="prettyprint source"><code id="sample8">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;title&gt;TurtleTube - Offline&lt;/title&gt;
&lt;!-- Load the Shaka Player library. --&gt;
&lt;script src="shaka-player.compiled.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;video id="video"
width="640" height="480"
crossorigin="anonymous"
controls&gt;
Your browser does not support HTML5 video.
&lt;/video&gt;
&lt;/body&gt;
&lt;script&gt;
var video;
function initPlayer() {
// Install polyfills.
shaka.polyfill.installAll();
// Find the video element.
video = document.getElementById('video');
// Attach the player to the window so that it can be easily debugged.
window.player = new shaka.player.Player(video);
// Listen for errors from the Player.
player.addEventListener('error', function(event) {
console.error(event);
});
}
function initialize() {
if (!window.player)
initPlayer();
}
function chooseTracks(videoSource) {
var ids = [];
var videoTracks = videoSource.getVideoTracks();
if (videoTracks.length) {
videoTracks.sort(shaka.player.VideoTrack.compare);
// Choosing the smallest track.
var track = videoTracks[0];
ids.push(track.id);
}
var audioTracks = videoSource.getAudioTracks();
if (audioTracks.length) {
// The video source gives you the preferred language first.
// Remove any tracks from other languages first.
var lang = audioTracks[0].lang;
audioTracks = audioTracks.filter(function(track) {
return track.lang == lang;
});
// From what's left, choose the middle stream. If we have high, medium,
// and low quality audio, this is medium. If we only have high and low,
// this is high.
var index = Math.floor(audioTracks.length / 2);
ids.push(audioTracks[index].id);
}
// Return IDs of chosen tracks.
return Promise.resolve(ids);
}
function storeContent() {
// Construct an OfflineVideoSource.
var offlineSource = new shaka.player.OfflineVideoSource(
null, // groupId, not used when storing content.
null); // estimator, optional parameter.
// Listen for progress events from the OfflineVideoSource.
offlineSource.addEventListener('progress', function(event) {
// Percentage complete is the detail field of the event.
console.log(
'Content storage is ' + event.detail.toFixed(2) + '% complete.');
});
// Store content from MPD url.
var mpdUrl = 'https://turtle-tube.appspot.com/t/t2/dash.mpd';
var preferredLanguage = 'en-US';
return offlineSource.store(
mpdUrl,
preferredLanguage,
null, // interpretContentProtection, not needed for clear content.
chooseTracks.bind(null, offlineSource)
).then(
function(groupId) {
window.groupId = groupId;
console.log('Stored content under group ID ' + groupId);
}
);
}
<span class="newCode"> function playOfflineContent() {</span>
<span class="newCode"> // Construct an OfflineVideoSource and load with player.</span>
<span class="newCode"> var offlineSource =</span>
<span class="newCode"> new shaka.player.OfflineVideoSource(window.groupId, null);</span>
<span class="newCode"> return window.player.load(offlineSource).then(</span>
<span class="newCode"> function() {</span>
<span class="newCode"> video.play();</span>
<span class="newCode"> console.log('Offline content with group ID ' + window.groupId +</span>
<span class="newCode"> ' ready for playback.');</span>
<span class="newCode"> });</span>
<span class="newCode"> }</span>
<span class="newCode"></span>
function test() {
initialize();
<span class="newCode"> storeContent().then(playOfflineContent).catch(</span>
function(e) {
console.error(e);
});
}
document.addEventListener('DOMContentLoaded', test);
&lt;/script&gt;
&lt;/html&gt;
</code></pre>
<h3 class="tutorial-heading">
Deleting Stored Content
</h3>
<p>
Similar to playing stored content, you will create a new {@link
shaka.player.OfflineVideoSource} with a known group ID to delete content.
</p>
<pre class="prettyprint source"><code id="sample9">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;title&gt;TurtleTube - Offline&lt;/title&gt;
&lt;!-- Load the Shaka Player library. --&gt;
&lt;script src="shaka-player.compiled.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;video id="video"
width="640" height="480"
crossorigin="anonymous"
controls&gt;
Your browser does not support HTML5 video.
&lt;/video&gt;
&lt;/body&gt;
&lt;script&gt;
var video;
function initPlayer() {
// Install polyfills.
shaka.polyfill.installAll();
// Find the video element.
video = document.getElementById('video');
// Attach the player to the window so that it can be easily debugged.
window.player = new shaka.player.Player(video);
// Listen for errors from the Player.
player.addEventListener('error', function(event) {
console.error(event);
});
}
function initialize() {
if (!window.player)
initPlayer();
}
function chooseTracks(videoSource) {
var ids = [];
var videoTracks = videoSource.getVideoTracks();
if (videoTracks.length) {
videoTracks.sort(shaka.player.VideoTrack.compare);
// Choosing the smallest track.
var track = videoTracks[0];
ids.push(track.id);
}
var audioTracks = videoSource.getAudioTracks();
if (audioTracks.length) {
// The video source gives you the preferred language first.
// Remove any tracks from other languages first.
var lang = audioTracks[0].lang;
audioTracks = audioTracks.filter(function(track) {
return track.lang == lang;
});
// From what's left, choose the middle stream. If we have high, medium,
// and low quality audio, this is medium. If we only have high and low,
// this is high.
var index = Math.floor(audioTracks.length / 2);
ids.push(audioTracks[index].id);
}
// Return IDs of chosen tracks.
return Promise.resolve(ids);
}
function storeContent() {
// Construct an OfflineVideoSource.
var offlineSource = new shaka.player.OfflineVideoSource(
null, // groupId, not used when storing content.
null); // estimator, optional parameter.
// Listen for progress events from the OfflineVideoSource.
offlineSource.addEventListener('progress', function(event) {
// Percentage complete is the detail field of the event.
console.log(
'Content storage is ' + event.detail.toFixed(2) + '% complete.');
});
// Store content from MPD url.
var mpdUrl = 'https://turtle-tube.appspot.com/t/t2/dash.mpd';
var preferredLanguage = 'en-US';
return offlineSource.store(
mpdUrl,
preferredLanguage,
null, // interpretContentProtection, not needed for clear content.
chooseTracks.bind(null, offlineSource)
).then(
function(groupId) {
window.groupId = groupId;
console.log('Stored content under group ID ' + groupId);
}
);
}
function playOfflineContent() {
// Construct an OfflineVideoSource and load with player.
var offlineSource =
new shaka.player.OfflineVideoSource(window.groupId, null);
return window.player.load(offlineSource).then(
function() {
video.play();
console.log('Offline content with group ID ' + window.groupId +
' ready for playback.');
});
}
<span class="newCode"> function deleteOfflineContent() {</span>
<span class="newCode"> var offlineSource =</span>
<span class="newCode"> new shaka.player.OfflineVideoSource(window.groupId, null);</span>
<span class="newCode"> return offlineSource.deleteGroup().then(</span>
<span class="newCode"> function() {</span>
<span class="newCode"> console.log('Offline content with group ID ' + window.groupId +</span>
<span class="newCode"> ' successfully deleted.');</span>
<span class="newCode"> });</span>
<span class="newCode"> }</span>
<span class="newCode"></span>
function test() {
initialize();
<span class="newCode"> storeContent().then(deleteOfflineContent).catch(</span>
function(e) {
console.error(e);
});
}
document.addEventListener('DOMContentLoaded', test);
&lt;/script&gt;
&lt;/html&gt;
</code></pre>
<h3 class="tutorial-heading">
Offline Caveats
</h3>
<p>
{@link shaka.player.OfflineVideoSource} can only store encrypted streams on
platforms that support persistent licenses.
</p>
<p>
Offline playback relies on the {@link http://goo.gl/TFHaXL Indexed Database
API} for storage of content. Indexed Database is currently supported by most
web browsers.
</p>