Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(hls): Support playing media playlists directly #4080

Merged
merged 3 commits into from Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
joeyparrish marked this conversation as resolved.
Show resolved Hide resolved
* 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