Skip to content

Commit

Permalink
feat(MSS): Add support to Microsoft Smooth Streaming
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Feb 21, 2023
1 parent ef8078a commit 433d24f
Show file tree
Hide file tree
Showing 39 changed files with 3,268 additions and 77 deletions.
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# ![Shaka Player](docs/shaka-player-logo.png)

Shaka Player is an open-source JavaScript library for adaptive media. It plays
adaptive media formats (such as [DASH][] and [HLS][]) in a browser, without
using plugins or Flash. Instead, Shaka Player uses the open web standards
[MediaSource Extensions][] and [Encrypted Media Extensions][].
adaptive media formats (such as [DASH][], [HLS][] and [MSS][]) in a browser,
without using plugins or Flash. Instead, Shaka Player uses the open web
standards [MediaSource Extensions][] and [Encrypted Media Extensions][].

Shaka Player also supports [offline storage and playback][] of media using
[IndexedDB][]. Content can be stored on any browser. Storage of licenses
Expand All @@ -18,6 +18,7 @@ For details on what's coming next, see our [development roadmap](roadmap.md).

[DASH]: http://dashif.org/
[HLS]: https://developer.apple.com/streaming/
[MSS]: https://learn.microsoft.com/en-us/iis/media/smooth-streaming/smooth-streaming-transport-protocol
[MediaSource Extensions]: https://www.w3.org/TR/media-source/
[Encrypted Media Extensions]: https://www.w3.org/TR/encrypted-media/
[IndexedDB]: https://www.w3.org/TR/IndexedDB-2/
Expand Down Expand Up @@ -84,6 +85,7 @@ supported. This supports both DASH and HLS manifests.
|:----:|:-------------:|:---:|:---:|:-------------------:|
|DASH |**Y** |**Y**| - |**Y** |
|HLS |**Y** |**Y**|**Y**| - |
|MSS |**Y** | - | - | - |

You can also create a [manifest parser plugin][] to support custom manifest
formats.
Expand Down Expand Up @@ -159,6 +161,20 @@ HLS features **not** supported:
[MPEG-5 Part2 LCEVC]: https://www.lcevc.org


## MSS features

MSS features supported:
- VOD
- AAC and H.264
- Encrypted content (PlayReady)
- TTML/DFXP
- Only supported with [codem-isoboxer][]

MSS features **not** supported:
- Live

[codem-isoboxer]: https://github.com/Dash-Industry-Forum/codem-isoboxer

## DRM support matrix

|Browser |Widevine |PlayReady|FairPlay |ClearKey⁶ |
Expand Down Expand Up @@ -196,6 +212,7 @@ NOTES:
|:--------:|:--------:|:-------:|:-------:|:--------:|
|DASH |**Y** |**Y** | - |**Y** |
|HLS |**Y** |**Y** |**Y** ¹ | - |
|MSS | - |**Y** | - | - |

NOTES:
- ¹: By default, FairPlay is handled using Apple's native HLS player, when on
Expand All @@ -211,6 +228,7 @@ Shaka Player supports:
- Can parse "sidx" box for DASH's SegmentBase@indexRange and
SegmentTemplate@index
- Can find and parse "tfdt" box to find segment start time in HLS
- For MSS it's necessary [codem-isoboxer][] v0.3.7+
- WebM
- Depends on browser support for the container via MediaSource
- Can parse [cueing data][] elements for DASH's SegmentBase@indexRange and
Expand Down
1 change: 1 addition & 0 deletions build/types/manifests
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

+@dash
+@hls
+@mss
+@offline
7 changes: 7 additions & 0 deletions build/types/mss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# The MSS manifest parser plugin.

+../../lib/mss/content_protection.js
+../../lib/mss/mss_parser.js
+../../lib/mss/mss_utils.js

+../../lib/transmuxer/mss_transmuxer.js
10 changes: 10 additions & 0 deletions demo/common/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ shakaAssets.Feature = {
DASH: shakaDemo.MessageIds.DASH,
// Set if the asset is an HLS manifest.
HLS: shakaDemo.MessageIds.HLS,
// Set if the asset is an MSS manifest.
MSS: shakaDemo.MessageIds.MSS,

// Set if the asset has at least one image stream.
THUMBNAILS: shakaDemo.MessageIds.THUMBNAILS,
Expand Down Expand Up @@ -903,6 +905,14 @@ shakaAssets.testAssets = [
.addFeature(shakaAssets.Feature.MP4)
.addFeature(shakaAssets.Feature.LIVE)
.addFeature(shakaAssets.Feature.THUMBNAILS),
new ShakaDemoAssetInfo(
/* name= */ 'Microsoft Smooth Streaming',
/* iconUri= */ 'https://reference.dashif.org/dash.js/latest/samples/lib/img/mss-1.jpg',
/* manifestUri= */ 'https://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest',
/* source= */ shakaAssets.Source.DASH_IF)
.addFeature(shakaAssets.Feature.MSS)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.MP4),
// End DASH-IF Assets }}}

// bitcodin assets {{{
Expand Down
3 changes: 3 additions & 0 deletions demo/common/message_ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ shakaDemo.MessageIds = {
LIVE: 'DEMO_LIVE',
MP2TS: 'DEMO_MP2TS',
MP4: 'DEMO_MP4',
MSS: 'DEMO_MSS',
MULTIPLE_LANGUAGES: 'DEMO_MULTIPLE_LANGUAGES',
OFFLINE: 'DEMO_OFFLINE',
STORED: 'DEMO_STORED',
Expand Down Expand Up @@ -86,6 +87,7 @@ shakaDemo.MessageIds = {
UNSUPPORTED_NO_OFFLINE: 'DEMO_UNSUPPORTED_NO_OFFLINE',
UNSUPPORTED_NO_KEY_SUPPORT: 'DEMO_UNSUPPORTED_NO_KEY_SUPPORT',
UNSUPPORTED_NO_LICENSE_SUPPORT: 'DEMO_UNSUPPORTED_NO_LICENSE_SUPPORT',
UNSUPPORTED_NO_MSS_SUPPORT: 'DEMO_UNSUPPORTED_NO_MSS_SUPPORT',
/* Visualizer. */
VISUALIZER_AUTO_SCREENSHOT_TOGGLE: 'DEMO_VISUALIZER_AUTO_SCREENSHOT_TOGGLE',
VISUALIZER_BUTTON: 'DEMO_VISUALIZER_BUTTON',
Expand Down Expand Up @@ -241,6 +243,7 @@ shakaDemo.MessageIds = {
MIN_PIXELS: 'DEMO_MIN_PIXELS',
MIN_TOTAL_BYTES: 'DEMO_MIN_TOTAL_BYTES',
MIN_WIDTH: 'DEMO_MIN_WIDTH',
MSS_SEQUENCE_MODE: 'DEMO_MSS_SEQUENCE_MODE',
NETWORK_INFORMATION: 'DEMO_NETWORK_INFORMATION',
NUMBER_DECIMAL_WARNING: 'DEMO_NUMBER_DECIMAL_WARNING',
NUMBER_INTEGER_WARNING: 'DEMO_NUMBER_INTEGER_WARNING',
Expand Down
4 changes: 3 additions & 1 deletion demo/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ shakaDemo.Config = class {
.addBoolInput_(MessageIds.DISABLE_THUMBNAILS,
'manifest.disableThumbnails')
.addBoolInput_(MessageIds.SEGMENT_RELATIVE_VTT_TIMING,
'manifest.segmentRelativeVttTiming');
'manifest.segmentRelativeVttTiming')
.addBoolInput_(MessageIds.MSS_SEQUENCE_MODE,
'manifest.mss.sequenceMode');

this.addRetrySection_('manifest', MessageIds.MANIFEST_RETRY_SECTION_HEADER);
}
Expand Down
2 changes: 2 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
<script defer src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
<!-- transmuxing support is enabled by including this: -->
<script defer src="../node_modules/mux.js/dist/mux.min.js"></script>
<!-- MSS support is enabled by including this: -->
<script defer src="../node_modules/codem-isoboxer/dist/iso_boxer.min.js"></script>
<!-- MPEG-5 Part2 LCEVC support is enabled by including this: -->
<script defer src="../node_modules/lcevc_dil.js/dist/lcevc_dil.min.js"></script>
<!-- MDL is enabled by including this: -->
Expand Down
3 changes: 3 additions & 0 deletions demo/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@
"DEMO_MIN_WIDTH": "Min Width",
"DEMO_MP2TS": "MPEG-2 TS",
"DEMO_MP4": "MP4",
"DEMO_MSS": "MSS",
"DEMO_MSS_SEQUENCE_MODE": "Enable MSS sequence mode",
"DEMO_MULTIPLE_LANGUAGES": "Multiple languages",
"DEMO_NAME": "Name",
"DEMO_NAME_ERROR": "Must be a unique name.",
Expand Down Expand Up @@ -244,6 +246,7 @@
"DEMO_UNSUPPORTED_NO_HLS_SUPPORT": "Your browser does not support HLS manifests.",
"DEMO_UNSUPPORTED_NO_KEY_SUPPORT": "Your browser does not support the required key systems.",
"DEMO_UNSUPPORTED_NO_LICENSE_SUPPORT": "Your browser does not support offline licenses for the required key systems.",
"DEMO_UNSUPPORTED_NO_MSS_SUPPORT": "Your browser does not support MSS manifests.",
"DEMO_UNSUPPORTED_NO_OFFLINE": "Your browser does not support offline storage.",
"DEMO_UPDATE_EXPIRATION_TIME": "Update expiration time",
"DEMO_UPDATE_INTERVAL_SECONDS": "Update interval seconds",
Expand Down
12 changes: 12 additions & 0 deletions demo/locales/source.json
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,14 @@
"description": "Text that describes an asset that uses the MP4 container.",
"message": "[JARGON:MP4]"
},
"DEMO_MSS": {
"description": "Text that describes an asset that is packaged in an MSS manifest.",
"message": "[PROPER_NAME:MSS]"
},
"DEMO_MSS_SEQUENCE_MODE": {
"description": "The name of a configuration value.",
"message": "Enable MSS sequence mode"
},
"DEMO_MULTIPLE_LANGUAGES": {
"description": "A tag that marks an asset as having multiple languages.",
"message": "Multiple languages"
Expand Down Expand Up @@ -979,6 +987,10 @@
"description": "An error message that shows why an asset cannot be stored offline: the browser cannot store protected content offline.",
"message": "Your browser does not support offline licenses for the required key systems."
},
"DEMO_UNSUPPORTED_NO_MSS_SUPPORT": {
"description": "An error message that shows why an asset cannot be stored offline: the browser cannot play MSS (https://en.wikipedia.org/wiki/Adaptive_bitrate_streaming#Microsoft_Smooth_Streaming_(MSS)) content.",
"message": "Your browser does not support [PROPER_NAME:MSS] manifests."
},
"DEMO_UNSUPPORTED_NO_OFFLINE": {
"description": "An error message that shows why an asset cannot be stored offline: the browser does not support storing things offline, in general.",
"message": "Your browser does not support offline storage."
Expand Down
4 changes: 4 additions & 0 deletions demo/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,10 @@ shakaDemo.Main = class {
!this.support_.manifest['m3u8']) {
return shakaDemo.MessageIds.UNSUPPORTED_NO_HLS_SUPPORT;
}
if (asset.features.includes(shakaAssets.Feature.MSS) &&
!this.support_.manifest['ism']) {
return shakaDemo.MessageIds.UNSUPPORTED_NO_MSS_SUPPORT;
}

// Does the asset contain a playable mime type?
const mimeTypes = [];
Expand Down
2 changes: 1 addition & 1 deletion demo/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ shakaDemo.Search = class {
/* docLink= */ null);
this.makeSelectInput_(coreContainer,
shakaDemo.MessageIds.MANIFEST_SEARCH,
[Feature.DASH, Feature.HLS], FEATURE);
[Feature.DASH, Feature.HLS, Feature.MSS], FEATURE);
this.makeSelectInput_(coreContainer,
shakaDemo.MessageIds.CONTAINER_SEARCH,
[Feature.MP4, Feature.MP2TS, Feature.WEBM, Feature.CONTAINERLESS],
Expand Down
3 changes: 3 additions & 0 deletions demo/service_worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ const OPTIONAL_RESOURCES = [
// The mux.js transmuxing library for MPEG-2 TS and CEA support.
'../node_modules/mux.js/dist/mux.min.js',

// The codem-isoboxer library for MSS support.
'../node_modules/codem-isoboxer/dist/iso_boxer.min.js',

// The cast sender SDK.
'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js',

Expand Down
94 changes: 94 additions & 0 deletions externs/isoboxer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @fileoverview Externs for codem-isoboxer library.
* @externs
*/


/**
* @typedef {{
* Utils: !ISOBoxerUtils,
* parseBuffer: function(!(ArrayBuffer|ArrayBufferView)):!ISOBoxer,
* createBox: function(string, !ISOBoxer, boolean=):!ISOBoxer,
* createFullBox: function(string, !ISOBoxer, ?ISOBoxer=):!ISOBoxer,
* addBoxProcessor: function(string, function()):!ISOBoxer,
* createFile: function():!ISOBoxer,
* write: function():!ArrayBuffer,
* fetch: function(!ArrayBuffer):!ISOBoxer
* }}
* @property {!ISOBoxerUtils} Utils
* @property {function(!(ArrayBuffer|ArrayBufferView)):!ISOBoxer} parseBuffer
* @property {function(string, !ISOBoxer, boolean=):!ISOBoxer} createBox
* @property {function(string, !ISOBoxer, ?ISOBoxer=):!ISOBoxer} createFullBox
* @property {function(string, function()):!ISOBoxer} addBoxProcessor
* @property {function():!ISOBoxer} createFile
* @property {function():!ArrayBuffer} write
* @property {function(!ArrayBuffer):!ISOBoxer} fetch
* @const
*/
var ISOBoxer;


/**
* @typedef {{
* appendBox: function(!ISOBoxer, !ISOBoxer):!ISOBox
* }}
* @const
*/
var ISOBoxerUtils;


/**
* @typedef {{
* type: string,
* size: number,
* _parent: ISOBox,
* boxes: !Array.<!ISOBox>,
* entry: !Array.<!Object>,
* version: !number,
* flags: !number,
* sample_count: !number,
* default_sample_info_size: !number,
* entry_count: !number,
* _procFullBox: function(),
* _procField: function(!string, !string, !number),
* _procFieldArray: function(!string, !number, !string, !number),
* _procEntries: function(!string, !number, !function(!ISOEntry)),
* _procEntryField: function(!ISOBox, !string, !string, !number),
* _procSubEntries: function(!ISOBox, !string, !number, !function(!ISOEntry))
* }}
* @property {string} type
* @property {number} size
* @property {ISOBox} _parent
* @property {!Array.<!ISOBox>} boxes
* @property {!Array.<!ISOEntry>} entry
* @property {!number} version
* @property {!number} flags
* @property {!number} sample_count
* @property {!number} default_sample_info_sizes
* @property {!number} entry_count
* @property {function()} _procFullBox
* @property {function(!string, !string, !number)} _procField
* @property {function(!string, !number, !string, !number)} _procFieldArray
* @property {function(!string, !number, !function(!ISOEntry))} _procEntries
* @property {function(!ISOBox, !string, !string, !number)} _procEntryField
* @property {function(!ISOBox, !string, !number, !function(!ISOEntry))}
* _procSubEntries
* @const
*/
var ISOBox;


/**
* @typedef {{
* NumberOfEntries: number
* }}
* @property {number} NumberOfEntries
* @const
*/
var ISOEntry;
31 changes: 30 additions & 1 deletion externs/shaka/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ shaka.extern.FetchCryptoKeysFunction;
* tilesLayout: (string|undefined),
* matchedStreams:
* (!Array.<shaka.extern.Stream>|!Array.<shaka.extern.StreamDB>|
* undefined)
* undefined),
* mssPrivateData: (shaka.extern.MssPrivateData|undefined)
* }}
*
* @description
Expand Down Expand Up @@ -438,7 +439,35 @@ shaka.extern.FetchCryptoKeysFunction;
* @property {(!Array.<shaka.extern.Stream>|!Array.<shaka.extern.StreamDB>|
* undefined)} matchedStreams
* The streams in all periods which match the stream. Used for Dash.
* @property {(shaka.extern.MssPrivateData|undefined)} mssPrivateData
* <i>Microsoft Smooth Streaming only.</i> <br>
* Private MSS data that is necessary to be able to do transmuxing..
*
* @exportDoc
*/
shaka.extern.Stream;


/**
* @typedef {{
* duration: number,
* timescale: number,
* codecPrivateData: string
* }}
*
* @description
* Private MSS data that is necessary to be able to do transmuxing.
*
* @property {number} duration
* <i>Required.</i> <br>
* MSS Stream duration.
* @property {number} timescale
* <i>Required.</i> <br>
* MSS timescale.
* @property {?string} codecPrivateData
* <i>Required.</i> <br>
* MSS codecPrivateData.
*
* @exportDoc
*/
shaka.extern.MssPrivateData;
Loading

0 comments on commit 433d24f

Please sign in to comment.