Skip to content

Commit

Permalink
fix(hls): Support playing media playlists directly (#4080)
Browse files Browse the repository at this point in the history
Closes #3536
  • Loading branch information
theodab committed Mar 31, 2022
1 parent 19e24b1 commit 48dd205
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 66 deletions.
18 changes: 17 additions & 1 deletion demo/common/asset.js
Expand Up @@ -77,6 +77,8 @@ const ShakaDemoAssetInfo = class {
this.imaContentSrcId = null;
/** @type {?string} */
this.mimeType = null;
/** @type {?string} */
this.mediaPlaylistFullMimeType = null;


// Offline storage values.
Expand Down Expand Up @@ -161,6 +163,15 @@ const ShakaDemoAssetInfo = class {
return this.drm.length == 1 && this.drm[0] == shakaAssets.KeySystem.CLEAR;
}

/**
* @param {string} mediaPlaylistFullMimeType
* @return {!ShakaDemoAssetInfo}
*/
setMediaPlaylistFullMimeType(mediaPlaylistFullMimeType) {
this.mediaPlaylistFullMimeType = mediaPlaylistFullMimeType;
return this;
}

/**
* @param {!Object} extraConfig
* @return {!ShakaDemoAssetInfo}
Expand Down Expand Up @@ -368,14 +379,19 @@ const ShakaDemoAssetInfo = class {
*/
getConfiguration() {
const config = /** @type {shaka.extern.PlayerConfiguration} */(
{drm: {advanced: {}}, manifest: {dash: {}}});
{drm: {advanced: {}}, manifest: {dash: {}, hls: {}}});

if (this.extraConfig) {
for (const key in this.extraConfig) {
config[key] = this.extraConfig[key];
}
}

if (this.mediaPlaylistFullMimeType) {
config.manifest.hls.mediaPlaylistFullMimeType =
this.mediaPlaylistFullMimeType;
}

if (this.licenseServers.size) {
config.drm.servers = config.drm.servers || {};
this.licenseServers.forEach((value, key) => {
Expand Down
9 changes: 9 additions & 0 deletions demo/common/assets.js
Expand Up @@ -294,6 +294,15 @@ shakaAssets.testAssets = [
.addFeature(shakaAssets.Feature.SUBTITLES)
.addFeature(shakaAssets.Feature.SURROUND)
.addFeature(shakaAssets.Feature.OFFLINE),
new ShakaDemoAssetInfo(
/* name= */ 'Angel One (HLS, MP4, video media playlist only)',
/* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png',
/* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/playlist_v-0480p-1000k-libx264.mp4.m3u8',
/* source= */ shakaAssets.Source.SHAKA)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.MP4)
.addFeature(shakaAssets.Feature.OFFLINE)
.setMediaPlaylistFullMimeType('video/mp4; codecs="avc1.4d401f"'),
new ShakaDemoAssetInfo(
/* name= */ 'Angel One (HLS, MP4, multilingual, Widevine)',
/* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/angel_one.png',
Expand Down
2 changes: 2 additions & 0 deletions demo/common/message_ids.js
Expand Up @@ -107,6 +107,8 @@ shakaDemo.MessageIds = {
DRM_SYSTEM: 'DEMO_DRM_SYSTEM',
DRM_TAB: 'DEMO_DRM_TAB',
EDIT_CUSTOM: 'DEMO_EDIT_CUSTOM',
HLS_FULL_MIME_TYPE: 'DEMO_HLS_FULL_MIME_TYPE',
HLS_TAB: 'DEMO_HLS_TAB',
HEADERS_TAB: 'DEMO_HEADERS_TAB',
ICON_URL: 'DEMO_ICON_URL',
LICENSE_CERTIFICATE_URL: 'DEMO_LICENSE_CERTIFICATE_URL',
Expand Down
39 changes: 39 additions & 0 deletions demo/custom.js
Expand Up @@ -245,6 +245,40 @@ shakaDemo.Custom = class {
}


/**
* @param {!ShakaDemoAssetInfo} assetInProgress
* @param {!Array.<!HTMLInputElement>} inputsToCheck
* @return {!Element} div
* @private
*/
makeAssetDialogContentsHLS_(assetInProgress, inputsToCheck) {
const mediaPlaylistDiv = document.createElement('div');
const containerStyle = shakaDemo.InputContainer.Style.FLEX;
const container = new shakaDemo.InputContainer(
mediaPlaylistDiv, /* headerText= */ null, containerStyle,
/* docLink= */ null);
container.getClassList().add('wide-input');
container.setDefaultRowClass('wide-input');

const fullMimeTypeSetup = (input, container) => {
if (assetInProgress.mediaPlaylistFullMimeType) {
input.value = assetInProgress.mediaPlaylistFullMimeType;
}
const defaultConfig = shaka.util.PlayerConfiguration.createDefault();
input.placeholder = defaultConfig.manifest.hls.mediaPlaylistFullMimeType;
};
const fullMimeTypeOnChange = (input) => {
assetInProgress.setMediaPlaylistFullMimeType(input.value);
};
const fullMimeTypeName = shakaDemoMain.getLocalizedString(
shakaDemo.MessageIds.HLS_FULL_MIME_TYPE);
this.makeField_(
container, fullMimeTypeName, fullMimeTypeSetup, fullMimeTypeOnChange);

return mediaPlaylistDiv;
}


/**
* @param {!ShakaDemoAssetInfo} assetInProgress
* @param {!Array.<!HTMLInputElement>} inputsToCheck
Expand Down Expand Up @@ -674,6 +708,8 @@ shakaDemo.Custom = class {
assetInProgress, inputsToCheck);
const adsDiv = this.makeAssetDialogContentsAds_(
assetInProgress, inputsToCheck);
const hlsDiv = this.makeAssetDialogContentsHLS_(
assetInProgress, inputsToCheck);
const extraConfigDiv = this.makeAssetDialogContentsExtra_(
assetInProgress, inputsToCheck);
const finishDiv = this.makeAssetDialogContentsFinish_(
Expand Down Expand Up @@ -713,6 +749,8 @@ shakaDemo.Custom = class {
shakaDemo.MessageIds.HEADERS_TAB, headersDiv, /* startOn= */ false);
addTabButton(
shakaDemo.MessageIds.ADS_TAB, adsDiv, /* startOn= */ false);
addTabButton(
shakaDemo.MessageIds.HLS_TAB, hlsDiv, /* startOn= */ false);
addTabButton(
shakaDemo.MessageIds.EXTRA_TAB, extraConfigDiv, /* startOn= */ false);

Expand All @@ -722,6 +760,7 @@ shakaDemo.Custom = class {
this.dialog_.appendChild(drmDiv);
this.dialog_.appendChild(headersDiv);
this.dialog_.appendChild(adsDiv);
this.dialog_.appendChild(hlsDiv);
this.dialog_.appendChild(extraConfigDiv);
this.dialog_.appendChild(finishDiv);
this.dialog_.appendChild(iconDiv);
Expand Down
2 changes: 2 additions & 0 deletions demo/locales/en.json
Expand Up @@ -88,6 +88,7 @@
"DEMO_HIGH_DEFINITION": "High definition",
"DEMO_HIGH_DEFINITION_SEARCH": "Filters for assets with at least one high-definition video stream.",
"DEMO_HLS": "HLS",
"DEMO_HLS_TAB": "HLS",
"DEMO_HOME": "HOME",
"DEMO_ICON_URL": "Icon URL",
"DEMO_IGNORE_DASH_DRM": "Ignore DASH DRM Info",
Expand Down Expand Up @@ -166,6 +167,7 @@
"DEMO_OFFLINE_SECTION_HEADER": "Offline",
"DEMO_FAILURE_MISC": "Shaka Player failed to load! If you are using an ad blocker, try switching to compiled mode at the bottom of the page.",
"DEMO_FAILURE_NO_BROWSER_SUPPORT": "Your browser is not supported!",
"DEMO_HLS_FULL_MIME_TYPE": "Full Mime Type for Playing Media Playlists Directly",
"DEMO_PLAY": "Play",
"DEMO_PLAYREADY": "PlayReady DRM",
"DEMO_PREFER_FORCED_SUBS": "Prefer Forced Subs",
Expand Down
8 changes: 8 additions & 0 deletions demo/locales/source.json
Expand Up @@ -355,6 +355,10 @@
"description": "Text that describes an asset that is packaged in an HLS manifest.",
"message": "[PROPER_NAME:HLS]"
},
"DEMO_HLS_TAB": {
"description": "The header for a tab within the custom asset creation dialog.",
"message": "[PROPER_NAME:HLS]"
},
"DEMO_HOME": {
"description": "A link in the header, that switches to a page configuration for viewing the curated set of front-page content.",
"message": "HOME"
Expand Down Expand Up @@ -667,6 +671,10 @@
"description": "An error displayed if Shaka Player is unable to load due to lack of browser support.",
"message": "Your browser is not supported!"
},
"DEMO_HLS_FULL_MIME_TYPE": {
"description": "The label on a field that allows users to provide a full mime type for a custom asset.",
"message": "Full Mime Type for Playing Media Playlists Directly"
},
"DEMO_PLAY": {
"description": "A button to play the attached asset.",
"message": "Play"
Expand Down
12 changes: 11 additions & 1 deletion externs/shaka/player.js
Expand Up @@ -748,7 +748,8 @@ shaka.extern.DashManifestConfiguration;
* ignoreImageStreamFailures: boolean,
* defaultAudioCodec: string,
* defaultVideoCodec: string,
* ignoreManifestProgramDateTime: boolean
* ignoreManifestProgramDateTime: boolean,
* mediaPlaylistFullMimeType: string
* }}
*
* @property {boolean} ignoreTextStreamFailures
Expand All @@ -768,6 +769,15 @@ shaka.extern.DashManifestConfiguration;
* <code>EXT-X-PROGRAM-DATE-TIME</code> tags in the manifest.
* Meant for tags that are incorrect or malformed.
* <i>Defaults to <code>false</code>.</i>
* @property {string} mediaPlaylistFullMimeType
* A string containing a full mime type, including both the basic mime type
* and also the codecs. Used when the HLS parser parses a media playlist
* directly, required since all of the mime type and codecs information is
* contained within the master playlist.
* You can use the <code>shaka.util.MimeUtils.getFullType()</code> utility to
* format this value.
* <i>Defaults to
* <code>'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"'</code>.</i>
* @exportDoc
*/
shaka.extern.HlsManifestConfiguration;
Expand Down

0 comments on commit 48dd205

Please sign in to comment.