-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Partial tutorial for offline. Issue #60.
Change-Id: If8388520b9dcbe8fb8ff95abe378a4e104f98e05
- Loading branch information
1 parent
eeaafe9
commit a953d7e
Showing
2 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
<!-- | ||
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"><!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>TurtleTube - Offline</title> | ||
<!-- Load the Shaka Player library. --> | ||
<script src="shaka-player.compiled.js"></script> | ||
</head> | ||
<body> | ||
<video id="video" | ||
width="640" height="480" | ||
crossorigin="anonymous" | ||
controls> | ||
Your browser does not support HTML5 video. | ||
</video> | ||
</body> | ||
<script> | ||
function initPlayer() { | ||
// Install polyfills. | ||
shaka.polyfill.installAll(); | ||
|
||
// Find the video element. | ||
var 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 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() { | ||
if (!window.player) { | ||
initPlayer(); | ||
} | ||
|
||
// Construct an OfflineVideoSource. | ||
var estimator = new shaka.util.EWMABandwidthEstimator(); | ||
var offlineSource = new shaka.player.OfflineVideoSource( | ||
null, // groupId, not used when storing content. | ||
estimator); | ||
|
||
// 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 = 'http://turtle-tube.appspot.com/t/t2/dash.mpd'; | ||
var preferredLanguage = 'en-US'; | ||
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 ' + window.groupId); | ||
} | ||
).catch( | ||
function(e) { | ||
console.error(e); | ||
}); | ||
} | ||
|
||
document.addEventListener('DOMContentLoaded', storeContent); | ||
</script> | ||
</html> | ||
</code></pre> | ||
|
||
<h3 class="tutorial-heading"> | ||
Playing Stored Content | ||
</h3> | ||
|
||
<p> | ||
TODO | ||
</p> | ||
|
||
<h3 class="tutorial-heading"> | ||
Deleting Stored Content | ||
</h3> | ||
|
||
<p> | ||
TODO | ||
</p> | ||
|
||
<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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>TurtleTube - Offline</title> | ||
<!-- Load the Shaka Player library. --> | ||
<script src="shaka-player.compiled.js"></script> | ||
</head> | ||
<body> | ||
<video id="video" | ||
width="640" height="480" | ||
crossorigin="anonymous" | ||
controls> | ||
Your browser does not support HTML5 video. | ||
</video> | ||
</body> | ||
<script> | ||
function initPlayer() { | ||
// Install polyfills. | ||
shaka.polyfill.installAll(); | ||
|
||
// Find the video element. | ||
var 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 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() { | ||
if (!window.player) { | ||
initPlayer(); | ||
} | ||
|
||
// Construct an OfflineVideoSource. | ||
var estimator = new shaka.util.EWMABandwidthEstimator(); | ||
var offlineSource = new shaka.player.OfflineVideoSource( | ||
null, // groupId, not used when storing content. | ||
estimator); | ||
|
||
// 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 = 'http://turtle-tube.appspot.com/t/t2/dash.mpd'; | ||
var preferredLanguage = 'en-US'; | ||
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 ' + window.groupId); | ||
} | ||
).catch( | ||
function(e) { | ||
console.error(e); | ||
}); | ||
} | ||
|
||
document.addEventListener('DOMContentLoaded', storeContent); | ||
</script> | ||
</html> |