shaka-player 4.2.3 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/sync-labels.yaml +1 -1
- package/.github/workflows/update-issues.yaml +1 -1
- package/AUTHORS +5 -0
- package/CHANGELOG.md +85 -39
- package/CONTRIBUTORS +5 -0
- package/README.md +14 -0
- package/demo/common/assets.js +58 -0
- package/demo/common/message_ids.js +22 -1
- package/demo/config.js +89 -5
- package/demo/demo.less +7 -1
- package/demo/index.html +8 -1
- package/demo/locales/en.json +21 -1
- package/demo/locales/source.json +82 -2
- package/demo/main.js +57 -1
- package/demo/search.js +2 -0
- package/demo/visualizer.js +337 -0
- package/demo/visualizer_button.js +103 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +83 -58
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +83 -58
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +18 -11
- package/dist/locales.js +32 -32
- package/dist/receiver.compiled.debug.js +23 -19
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +23 -19
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +178 -27
- package/dist/shaka-player.compiled.debug.d.ts +178 -27
- package/dist/shaka-player.compiled.debug.externs.js +163 -32
- package/dist/shaka-player.compiled.debug.js +488 -422
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +163 -32
- package/dist/shaka-player.compiled.js +895 -857
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +178 -27
- package/dist/shaka-player.ui.debug.d.ts +178 -27
- package/dist/shaka-player.ui.debug.externs.js +163 -32
- package/dist/shaka-player.ui.debug.js +519 -450
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +163 -32
- package/dist/shaka-player.ui.js +1053 -1015
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-architecture.png +0 -0
- package/docs/design/lcevc-demo.png +0 -0
- package/docs/design/lcevc-integration.md +72 -0
- package/docs/tutorials/fairplay.md +7 -0
- package/docs/tutorials/faq.md +1 -1
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/upgrade.md +6 -0
- package/externs/ima.js +13 -1
- package/externs/lcevc.js +81 -0
- package/externs/mux.js +4 -42
- package/externs/shaka/ads.js +11 -1
- package/externs/shaka/manifest_parser.js +5 -1
- package/externs/shaka/player.js +178 -15
- package/lib/abr/simple_abr_manager.js +7 -0
- package/lib/ads/ad_manager.js +0 -8
- package/lib/ads/client_side_ad.js +15 -0
- package/lib/ads/client_side_ad_manager.js +21 -8
- package/lib/ads/server_side_ad.js +15 -0
- package/lib/ads/server_side_ad_manager.js +3 -3
- package/lib/cast/cast_proxy.js +2 -1
- package/lib/cast/cast_receiver.js +19 -5
- package/lib/cast/cast_sender.js +2 -1
- package/lib/cast/cast_utils.js +18 -6
- package/lib/cea/dummy_cea_parser.js +28 -0
- package/lib/cea/i_cea_parser.js +14 -2
- package/lib/cea/mp4_cea_parser.js +87 -5
- package/lib/config/auto_show_text.js +33 -0
- package/lib/dash/dash_parser.js +1 -1
- package/lib/hls/hls_parser.js +799 -376
- package/lib/lcevc/lcevc_dil.js +152 -0
- package/lib/media/closed_caption_parser.js +9 -6
- package/lib/media/drm_engine.js +14 -6
- package/lib/media/media_source_engine.js +112 -26
- package/lib/media/playhead.js +23 -1
- package/lib/media/presentation_timeline.js +26 -11
- package/lib/media/segment_reference.js +49 -1
- package/lib/media/streaming_engine.js +145 -24
- package/lib/media/transmuxer.js +79 -18
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +477 -85
- package/lib/polyfill/patchedmediakeys_apple.js +55 -1
- package/lib/text/ui_text_displayer.js +5 -5
- package/lib/text/vtt_text_parser.js +35 -1
- package/lib/util/dom_utils.js +0 -1
- package/lib/util/error.js +17 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/id3_utils.js +300 -0
- package/lib/util/manifest_parser_utils.js +4 -0
- package/lib/util/mime_utils.js +3 -6
- package/lib/util/mp4_box_parsers.js +15 -5
- package/lib/util/platform.js +9 -1
- package/lib/util/player_configuration.js +23 -1
- package/lib/util/ts_parser.js +499 -0
- package/maintained-branches.md +2 -2
- package/package.json +4 -1
- package/roadmap.md +27 -7
- package/test/ads/ad_manager_unit.js +180 -29
- package/test/cast/cast_receiver_integration.js +97 -16
- package/test/cast/cast_receiver_unit.js +17 -12
- package/test/cast/cast_utils_unit.js +4 -1
- package/test/dash/dash_parser_content_protection_unit.js +1 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +93 -1
- package/test/dash/dash_parser_segment_base_unit.js +1 -0
- package/test/dash/dash_parser_segment_list_unit.js +1 -0
- package/test/dash/dash_parser_segment_template_unit.js +1 -0
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +253 -19
- package/test/hls/hls_parser_unit.js +500 -12
- package/test/media/closed_caption_parser_unit.js +2 -1
- package/test/media/drm_engine_integration.js +3 -1
- package/test/media/media_source_engine_integration.js +102 -6
- package/test/media/media_source_engine_unit.js +10 -5
- package/test/media/playhead_unit.js +41 -0
- package/test/media/streaming_engine_integration.js +17 -1
- package/test/media/streaming_engine_unit.js +180 -24
- package/test/media/transmuxer_integration.js +21 -10
- package/test/player_integration.js +224 -82
- package/test/player_unit.js +92 -2
- package/test/polyfill/patchedmediakeys_apple_unit.js +124 -0
- package/test/test/assets/id3-metadata.aac +0 -0
- package/test/test/assets/id3-metadata.ts +0 -0
- package/test/test/assets/thumbnails-sprites.vtt +10 -0
- package/test/test/assets/thumbnails.vtt +10 -0
- package/test/test/util/dash_parser_util.js +2 -0
- package/test/test/util/fake_ad.js +21 -0
- package/test/test/util/fake_media_source_engine.js +7 -0
- package/test/test/util/id3_generator.js +100 -0
- package/test/test/util/manifest_generator.js +3 -6
- package/test/test/util/simple_fakes.js +7 -0
- package/test/test/util/stream_generator.js +38 -0
- package/test/test/util/test_scheme.js +43 -14
- package/test/text/vtt_text_parser_unit.js +11 -0
- package/test/ui/text_displayer_layout_unit.js +14 -0
- package/test/util/id3_utils_unit.js +116 -0
- package/test/util/ts_parser_unit.js +77 -0
- package/ui/controls.js +4 -1
- package/ui/less/containers.less +7 -0
- package/ui/settings_menu.js +11 -2
- package/ui/ui.js +43 -4
|
@@ -24,6 +24,7 @@ goog.require('shaka.util.Destroyer');
|
|
|
24
24
|
goog.require('shaka.util.Error');
|
|
25
25
|
goog.require('shaka.util.FakeEvent');
|
|
26
26
|
goog.require('shaka.util.IDestroyable');
|
|
27
|
+
goog.require('shaka.util.Id3Utils');
|
|
27
28
|
goog.require('shaka.util.ManifestParserUtils');
|
|
28
29
|
goog.require('shaka.util.MimeUtils');
|
|
29
30
|
goog.require('shaka.util.Mp4Parser');
|
|
@@ -77,6 +78,9 @@ shaka.media.StreamingEngine = class {
|
|
|
77
78
|
/** @private {?shaka.extern.Stream} */
|
|
78
79
|
this.currentTextStream_ = null;
|
|
79
80
|
|
|
81
|
+
/** @private {boolean} */
|
|
82
|
+
this.parsedPrftEventRaised_ = false;
|
|
83
|
+
|
|
80
84
|
/**
|
|
81
85
|
* Maps a content type, e.g., 'audio', 'video', or 'text', to a MediaState.
|
|
82
86
|
*
|
|
@@ -780,9 +784,9 @@ shaka.media.StreamingEngine = class {
|
|
|
780
784
|
|
|
781
785
|
// Init MediaSourceEngine.
|
|
782
786
|
const mediaSourceEngine = this.playerInterface_.mediaSourceEngine;
|
|
783
|
-
const
|
|
787
|
+
const forceTransmux = this.config_.forceTransmux;
|
|
784
788
|
|
|
785
|
-
await mediaSourceEngine.init(streamsByType,
|
|
789
|
+
await mediaSourceEngine.init(streamsByType, forceTransmux,
|
|
786
790
|
this.manifest_.sequenceMode);
|
|
787
791
|
this.destroyer_.ensureNotDestroyed();
|
|
788
792
|
|
|
@@ -1370,7 +1374,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1370
1374
|
JSON.stringify(buffered));
|
|
1371
1375
|
|
|
1372
1376
|
if (!mediaState.waitingToClearBuffer) {
|
|
1373
|
-
this.playerInterface_.onSegmentAppended(
|
|
1377
|
+
this.playerInterface_.onSegmentAppended(
|
|
1378
|
+
reference.startTime, reference.endTime, mediaState.type);
|
|
1374
1379
|
}
|
|
1375
1380
|
|
|
1376
1381
|
// Update right away.
|
|
@@ -1403,16 +1408,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1403
1408
|
this.mediaStates_.delete(ContentType.TEXT);
|
|
1404
1409
|
} else if (error.code == shaka.util.Error.Code.QUOTA_EXCEEDED_ERROR) {
|
|
1405
1410
|
this.handleQuotaExceeded_(mediaState, error);
|
|
1406
|
-
} else if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
|
|
1407
|
-
error.data && error.data[1] == 404) {
|
|
1408
|
-
// The segment could not be found, does not exist, or is not available.
|
|
1409
|
-
// In any case just try again.
|
|
1410
|
-
// The current segment is not available. Schedule another update to
|
|
1411
|
-
// fetch the segment again.
|
|
1412
|
-
shaka.log.v2(logPrefix, 'segment not available.');
|
|
1413
|
-
mediaState.performingUpdate = false;
|
|
1414
|
-
mediaState.updateTimer = null;
|
|
1415
|
-
this.scheduleUpdate_(mediaState, 1);
|
|
1416
1411
|
} else {
|
|
1417
1412
|
shaka.log.error(logPrefix, 'failed fetch and append: code=' +
|
|
1418
1413
|
error.code);
|
|
@@ -1455,9 +1450,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1455
1450
|
|
|
1456
1451
|
/**
|
|
1457
1452
|
* Clear per-stream error states and retry any failed streams.
|
|
1453
|
+
* @param {number} delaySeconds
|
|
1458
1454
|
* @return {boolean} False if unable to retry.
|
|
1459
1455
|
*/
|
|
1460
|
-
retry() {
|
|
1456
|
+
retry(delaySeconds) {
|
|
1461
1457
|
if (this.destroyer_.destroyed()) {
|
|
1462
1458
|
shaka.log.error('Unable to retry after StreamingEngine is destroyed!');
|
|
1463
1459
|
return false;
|
|
@@ -1474,7 +1470,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1474
1470
|
if (mediaState.hasError) {
|
|
1475
1471
|
shaka.log.info(logPrefix, 'Retrying after failure...');
|
|
1476
1472
|
mediaState.hasError = false;
|
|
1477
|
-
this.scheduleUpdate_(mediaState,
|
|
1473
|
+
this.scheduleUpdate_(mediaState, delaySeconds);
|
|
1478
1474
|
}
|
|
1479
1475
|
}
|
|
1480
1476
|
|
|
@@ -1635,6 +1631,17 @@ shaka.media.StreamingEngine = class {
|
|
|
1635
1631
|
try {
|
|
1636
1632
|
const initSegment = await fetchInit;
|
|
1637
1633
|
this.destroyer_.ensureNotDestroyed();
|
|
1634
|
+
|
|
1635
|
+
const parser = new shaka.util.Mp4Parser();
|
|
1636
|
+
const Mp4Parser = shaka.util.Mp4Parser;
|
|
1637
|
+
parser.box('moov', Mp4Parser.children)
|
|
1638
|
+
.box('trak', Mp4Parser.children)
|
|
1639
|
+
.box('mdia', Mp4Parser.children)
|
|
1640
|
+
.fullBox('mdhd', (box) => {
|
|
1641
|
+
this.parseMDHD_(reference, box);
|
|
1642
|
+
})
|
|
1643
|
+
.parse(initSegment);
|
|
1644
|
+
|
|
1638
1645
|
shaka.log.v1(logPrefix, 'appending init segment');
|
|
1639
1646
|
const hasClosedCaptions = mediaState.stream.closedCaptions &&
|
|
1640
1647
|
mediaState.stream.closedCaptions.size > 0;
|
|
@@ -1674,15 +1681,36 @@ shaka.media.StreamingEngine = class {
|
|
|
1674
1681
|
|
|
1675
1682
|
const hasClosedCaptions = stream.closedCaptions &&
|
|
1676
1683
|
stream.closedCaptions.size > 0;
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1684
|
+
|
|
1685
|
+
let parser;
|
|
1686
|
+
const hasEmsg = ((stream.emsgSchemeIdUris != null &&
|
|
1687
|
+
stream.emsgSchemeIdUris.length > 0) ||
|
|
1688
|
+
this.config_.dispatchAllEmsgBoxes);
|
|
1689
|
+
const shouldParsePrftBox =
|
|
1690
|
+
(this.config_.parsePrftBox && !this.parsedPrftEventRaised_);
|
|
1691
|
+
|
|
1692
|
+
if (hasEmsg || shouldParsePrftBox) {
|
|
1693
|
+
parser = new shaka.util.Mp4Parser();
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
if (hasEmsg) {
|
|
1697
|
+
parser
|
|
1681
1698
|
.fullBox(
|
|
1682
1699
|
'emsg',
|
|
1683
1700
|
(box) => this.parseEMSG_(
|
|
1684
|
-
reference, stream.emsgSchemeIdUris, box))
|
|
1685
|
-
|
|
1701
|
+
reference, stream.emsgSchemeIdUris, box));
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
if (shouldParsePrftBox) {
|
|
1705
|
+
parser
|
|
1706
|
+
.fullBox(
|
|
1707
|
+
'prft',
|
|
1708
|
+
(box) => this.parsePrft_(
|
|
1709
|
+
reference, box));
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
if (hasEmsg || shouldParsePrftBox) {
|
|
1713
|
+
parser.parse(segment);
|
|
1686
1714
|
}
|
|
1687
1715
|
|
|
1688
1716
|
await this.evict_(mediaState, presentationTime);
|
|
@@ -1778,6 +1806,21 @@ shaka.media.StreamingEngine = class {
|
|
|
1778
1806
|
// A special scheme in DASH used to signal manifest updates.
|
|
1779
1807
|
if (schemeId == 'urn:mpeg:dash:event:2012') {
|
|
1780
1808
|
this.playerInterface_.onManifestUpdate();
|
|
1809
|
+
} else if (schemeId == 'https://aomedia.org/emsg/ID3') {
|
|
1810
|
+
// See https://aomediacodec.github.io/id3-emsg/
|
|
1811
|
+
const frames = shaka.util.Id3Utils.getID3Frames(messageData);
|
|
1812
|
+
if (frames.length && reference) {
|
|
1813
|
+
/** @private {shaka.extern.ID3Metadata} */
|
|
1814
|
+
const metadata = {
|
|
1815
|
+
cueTime: reference.startTime,
|
|
1816
|
+
data: messageData,
|
|
1817
|
+
frames: frames,
|
|
1818
|
+
dts: reference.startTime,
|
|
1819
|
+
pts: reference.startTime,
|
|
1820
|
+
};
|
|
1821
|
+
this.playerInterface_.onMetadata(
|
|
1822
|
+
[metadata], /* offset= */ 0, reference.endTime);
|
|
1823
|
+
}
|
|
1781
1824
|
} else {
|
|
1782
1825
|
/** @type {shaka.extern.EmsgInfo} */
|
|
1783
1826
|
const emsg = {
|
|
@@ -1801,6 +1844,77 @@ shaka.media.StreamingEngine = class {
|
|
|
1801
1844
|
}
|
|
1802
1845
|
}
|
|
1803
1846
|
|
|
1847
|
+
/**
|
|
1848
|
+
* Parse MDHD box.
|
|
1849
|
+
* @param {!shaka.media.SegmentReference} reference
|
|
1850
|
+
* @param {!shaka.extern.ParsedBox} box
|
|
1851
|
+
* @private
|
|
1852
|
+
*/
|
|
1853
|
+
parseMDHD_(reference, box) {
|
|
1854
|
+
const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
|
|
1855
|
+
box.reader || 0, box.version || 0);
|
|
1856
|
+
reference.initSegmentReference.timescale = parsedMDHDBox.timescale;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
/**
|
|
1860
|
+
* Parse PRFT box.
|
|
1861
|
+
* @param {!shaka.media.SegmentReference} reference
|
|
1862
|
+
* @param {!shaka.extern.ParsedBox} box
|
|
1863
|
+
* @private
|
|
1864
|
+
*/
|
|
1865
|
+
parsePrft_(reference, box) {
|
|
1866
|
+
if (this.parsedPrftEventRaised_ ||
|
|
1867
|
+
!reference.initSegmentReference.timescale) {
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
box.reader.readUint32(); // Ignore referenceTrackId
|
|
1871
|
+
const ntpTimestampSec = box.reader.readUint32();
|
|
1872
|
+
const ntpTimestampFrac = box.reader.readUint32();
|
|
1873
|
+
const ntpTimestamp = ntpTimestampSec * 1000 +
|
|
1874
|
+
ntpTimestampFrac / 2**32 * 1000;
|
|
1875
|
+
|
|
1876
|
+
let mediaTime;
|
|
1877
|
+
if (box.version === 0) {
|
|
1878
|
+
mediaTime = box.reader.readUint32();
|
|
1879
|
+
} else {
|
|
1880
|
+
try {
|
|
1881
|
+
mediaTime = box.reader.readUint64();
|
|
1882
|
+
} catch (e) {
|
|
1883
|
+
shaka.log.warning('parsePrft_: parsing mediatime resulted in a '+
|
|
1884
|
+
'MEDIA.JS_INTEGER_OVERFLOW exception');
|
|
1885
|
+
this.parsedPrftEventRaised_ = true;
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
const timescale = reference.initSegmentReference.timescale;
|
|
1891
|
+
const wallClockTime = this.convertNtp(ntpTimestamp);
|
|
1892
|
+
const programStartDate = new Date(wallClockTime -
|
|
1893
|
+
(mediaTime / timescale) * 1000);
|
|
1894
|
+
const prftInfo = {
|
|
1895
|
+
wallClockTime,
|
|
1896
|
+
programStartDate,
|
|
1897
|
+
};
|
|
1898
|
+
|
|
1899
|
+
const eventName = shaka.util.FakeEvent.EventName.Prft;
|
|
1900
|
+
const data = (new Map()).set('detail', prftInfo);
|
|
1901
|
+
const event = new shaka.util.FakeEvent(
|
|
1902
|
+
eventName, data);
|
|
1903
|
+
this.playerInterface_.onEvent(event);
|
|
1904
|
+
this.parsedPrftEventRaised_ = true;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
|
|
1908
|
+
/**
|
|
1909
|
+
* Convert Ntp ntpTimeStamp to UTC Time
|
|
1910
|
+
*
|
|
1911
|
+
* @param {number} ntpTimeStamp
|
|
1912
|
+
* @return {number} utcTime
|
|
1913
|
+
*/
|
|
1914
|
+
convertNtp(ntpTimeStamp) {
|
|
1915
|
+
const start = new Date(Date.UTC(1900, 0, 1, 0, 0, 0));
|
|
1916
|
+
return new Date(start.getTime() + ntpTimeStamp).getTime();
|
|
1917
|
+
}
|
|
1804
1918
|
|
|
1805
1919
|
/**
|
|
1806
1920
|
* Evicts media to meet the max buffer behind limit.
|
|
@@ -2080,10 +2194,12 @@ shaka.media.StreamingEngine = class {
|
|
|
2080
2194
|
* onError: function(!shaka.util.Error),
|
|
2081
2195
|
* onEvent: function(!Event),
|
|
2082
2196
|
* onManifestUpdate: function(),
|
|
2083
|
-
* onSegmentAppended: function(
|
|
2197
|
+
* onSegmentAppended: function(number, number,
|
|
2198
|
+
* !shaka.util.ManifestParserUtils.ContentType),
|
|
2084
2199
|
* onInitSegmentAppended: function(!number,!shaka.media.InitSegmentReference),
|
|
2085
2200
|
* beforeAppendSegment: function(
|
|
2086
|
-
* shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise
|
|
2201
|
+
* shaka.util.ManifestParserUtils.ContentType,!BufferSource):Promise,
|
|
2202
|
+
* onMetadata: !function(!Array.<shaka.extern.ID3Metadata>, number, ?number)
|
|
2087
2203
|
* }}
|
|
2088
2204
|
*
|
|
2089
2205
|
* @property {function():number} getPresentationTime
|
|
@@ -2106,14 +2222,19 @@ shaka.media.StreamingEngine = class {
|
|
|
2106
2222
|
* Called when an event occurs that should be sent to the app.
|
|
2107
2223
|
* @property {function()} onManifestUpdate
|
|
2108
2224
|
* Called when an embedded 'emsg' box should trigger a manifest update.
|
|
2109
|
-
* @property {function(
|
|
2225
|
+
* @property {function(number, number,
|
|
2226
|
+
* !shaka.util.ManifestParserUtils.ContentType)} onSegmentAppended
|
|
2110
2227
|
* Called after a segment is successfully appended to a MediaSource.
|
|
2228
|
+
* The parameters are the start and end time.
|
|
2111
2229
|
* @property
|
|
2112
2230
|
* {function(!number, !shaka.media.InitSegmentReference)} onInitSegmentAppended
|
|
2113
2231
|
* Called when an init segment is appended to a MediaSource.
|
|
2114
2232
|
* @property {!function(shaka.util.ManifestParserUtils.ContentType,
|
|
2115
2233
|
* !BufferSource):Promise} beforeAppendSegment
|
|
2116
2234
|
* A function called just before appending to the source buffer.
|
|
2235
|
+
* @property
|
|
2236
|
+
* {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)} onMetadata
|
|
2237
|
+
* Called when an ID3 is found in a EMSG.
|
|
2117
2238
|
*/
|
|
2118
2239
|
shaka.media.StreamingEngine.PlayerInterface;
|
|
2119
2240
|
|
package/lib/media/transmuxer.js
CHANGED
|
@@ -18,13 +18,18 @@ goog.require('shaka.dependencies');
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Transmuxer provides all operations for transmuxing from Transport
|
|
21
|
-
* Stream to MP4.
|
|
21
|
+
* Stream or AAC to MP4.
|
|
22
22
|
*
|
|
23
23
|
* @implements {shaka.util.IDestroyable}
|
|
24
24
|
*/
|
|
25
25
|
shaka.media.Transmuxer = class {
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} mimeType
|
|
28
|
+
*/
|
|
29
|
+
constructor(mimeType) {
|
|
30
|
+
/** @private {string} */
|
|
31
|
+
this.originalMimeType_ = mimeType;
|
|
32
|
+
|
|
28
33
|
/** @private {?muxjs} */
|
|
29
34
|
this.muxjs_ = shaka.dependencies.muxjs();
|
|
30
35
|
|
|
@@ -42,9 +47,6 @@ shaka.media.Transmuxer = class {
|
|
|
42
47
|
/** @private {!Array.<muxjs.mp4.ClosedCaption>} */
|
|
43
48
|
this.captions_ = [];
|
|
44
49
|
|
|
45
|
-
/** @private {!Array.<muxjs.mp4.Metadata>} */
|
|
46
|
-
this.metadata_ = [];
|
|
47
|
-
|
|
48
50
|
/** @private {boolean} */
|
|
49
51
|
this.isTransmuxing_ = false;
|
|
50
52
|
|
|
@@ -64,7 +66,8 @@ shaka.media.Transmuxer = class {
|
|
|
64
66
|
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
|
-
* Check if the content type is Transport Stream, and if muxjs is
|
|
69
|
+
* Check if the content type is Transport Stream or AAC, and if muxjs is
|
|
70
|
+
* loaded.
|
|
68
71
|
* @param {string} mimeType
|
|
69
72
|
* @param {string=} contentType
|
|
70
73
|
* @return {boolean}
|
|
@@ -72,41 +75,88 @@ shaka.media.Transmuxer = class {
|
|
|
72
75
|
static isSupported(mimeType, contentType) {
|
|
73
76
|
const Transmuxer = shaka.media.Transmuxer;
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
const isTs = Transmuxer.isTsContainer_(mimeType);
|
|
79
|
+
const isAac = Transmuxer.isAacContainer_(mimeType);
|
|
80
|
+
|
|
81
|
+
if (!shaka.dependencies.muxjs() || (!isTs && !isAac)) {
|
|
76
82
|
return false;
|
|
77
83
|
}
|
|
78
84
|
|
|
85
|
+
if (isAac) {
|
|
86
|
+
return MediaSource.isTypeSupported(Transmuxer.convertAacCodecs_());
|
|
87
|
+
}
|
|
88
|
+
|
|
79
89
|
if (contentType) {
|
|
80
90
|
return MediaSource.isTypeSupported(
|
|
81
|
-
Transmuxer.
|
|
91
|
+
Transmuxer.convertTsCodecs_(contentType, mimeType));
|
|
82
92
|
}
|
|
83
93
|
|
|
84
94
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
85
95
|
|
|
86
|
-
const audioMime = Transmuxer.
|
|
87
|
-
const videoMime = Transmuxer.
|
|
96
|
+
const audioMime = Transmuxer.convertTsCodecs_(ContentType.AUDIO, mimeType);
|
|
97
|
+
const videoMime = Transmuxer.convertTsCodecs_(ContentType.VIDEO, mimeType);
|
|
88
98
|
return MediaSource.isTypeSupported(audioMime) ||
|
|
89
99
|
MediaSource.isTypeSupported(videoMime);
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Check if the mimetype is 'audio/aac'.
|
|
105
|
+
* @param {string} mimeType
|
|
106
|
+
* @return {boolean}
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
static isAacContainer_(mimeType) {
|
|
110
|
+
return mimeType.toLowerCase().split(';')[0] == 'audio/aac';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
93
114
|
/**
|
|
94
115
|
* Check if the mimetype contains 'mp2t'.
|
|
95
116
|
* @param {string} mimeType
|
|
96
117
|
* @return {boolean}
|
|
118
|
+
* @private
|
|
97
119
|
*/
|
|
98
|
-
static
|
|
120
|
+
static isTsContainer_(mimeType) {
|
|
99
121
|
return mimeType.toLowerCase().split(';')[0].split('/')[1] == 'mp2t';
|
|
100
122
|
}
|
|
101
123
|
|
|
102
124
|
|
|
125
|
+
/**
|
|
126
|
+
* For any stream, convert its codecs to MP4 codecs.
|
|
127
|
+
* @param {string} contentType
|
|
128
|
+
* @param {string} mimeType
|
|
129
|
+
* @return {string}
|
|
130
|
+
*/
|
|
131
|
+
static convertCodecs(contentType, mimeType) {
|
|
132
|
+
const Transmuxer = shaka.media.Transmuxer;
|
|
133
|
+
if (Transmuxer.isAacContainer_(mimeType)) {
|
|
134
|
+
return Transmuxer.convertAacCodecs_();
|
|
135
|
+
} else if (Transmuxer.isTsContainer_(mimeType)) {
|
|
136
|
+
return Transmuxer.convertTsCodecs_(contentType, mimeType);
|
|
137
|
+
}
|
|
138
|
+
return mimeType;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* For aac stream, convert its codecs to MP4 codecs.
|
|
144
|
+
* @return {string}
|
|
145
|
+
* @private
|
|
146
|
+
*/
|
|
147
|
+
static convertAacCodecs_() {
|
|
148
|
+
return 'audio/mp4; codecs="mp4a.40.2"';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
103
152
|
/**
|
|
104
153
|
* For transport stream, convert its codecs to MP4 codecs.
|
|
105
154
|
* @param {string} contentType
|
|
106
155
|
* @param {string} tsMimeType
|
|
107
156
|
* @return {string}
|
|
157
|
+
* @private
|
|
108
158
|
*/
|
|
109
|
-
static
|
|
159
|
+
static convertTsCodecs_(contentType, tsMimeType) {
|
|
110
160
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
111
161
|
let mp4MimeType = tsMimeType.replace(/mp2t/i, 'mp4');
|
|
112
162
|
if (contentType == ContentType.AUDIO) {
|
|
@@ -148,12 +198,20 @@ shaka.media.Transmuxer = class {
|
|
|
148
198
|
}
|
|
149
199
|
|
|
150
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Returns the original mimetype of the transmuxer.
|
|
203
|
+
* @return {string}
|
|
204
|
+
*/
|
|
205
|
+
getOrginalMimeType() {
|
|
206
|
+
return this.originalMimeType_;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
151
210
|
/**
|
|
152
211
|
* Transmux from Transport stream to MP4, using the mux.js library.
|
|
153
212
|
* @param {BufferSource} data
|
|
154
213
|
* @return {!Promise.<{data: !Uint8Array,
|
|
155
|
-
* captions: !Array.<!muxjs.mp4.ClosedCaption
|
|
156
|
-
* metadata: !Array.<!Object>}>}
|
|
214
|
+
* captions: !Array.<!muxjs.mp4.ClosedCaption>}>}
|
|
157
215
|
*/
|
|
158
216
|
transmux(data) {
|
|
159
217
|
goog.asserts.assert(!this.isTransmuxing_,
|
|
@@ -162,7 +220,6 @@ shaka.media.Transmuxer = class {
|
|
|
162
220
|
this.transmuxPromise_ = new shaka.util.PublicPromise();
|
|
163
221
|
this.transmuxedData_ = [];
|
|
164
222
|
this.captions_ = [];
|
|
165
|
-
this.metadata_ = [];
|
|
166
223
|
|
|
167
224
|
const dataArray = shaka.util.BufferUtils.toUint8(data);
|
|
168
225
|
this.muxTransmuxer_.push(dataArray);
|
|
@@ -182,6 +239,12 @@ shaka.media.Transmuxer = class {
|
|
|
182
239
|
return this.transmuxPromise_;
|
|
183
240
|
}
|
|
184
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Reset captions from Transport stream to MP4, using the mux.js library.
|
|
244
|
+
*/
|
|
245
|
+
resetCaptions() {
|
|
246
|
+
this.muxTransmuxer_.resetCaptions();
|
|
247
|
+
}
|
|
185
248
|
|
|
186
249
|
/**
|
|
187
250
|
* Handles the 'data' event of the transmuxer.
|
|
@@ -194,7 +257,6 @@ shaka.media.Transmuxer = class {
|
|
|
194
257
|
*/
|
|
195
258
|
onTransmuxed_(segment) {
|
|
196
259
|
this.captions_ = segment.captions;
|
|
197
|
-
this.metadata_ = segment.metadata;
|
|
198
260
|
this.transmuxedData_.push(
|
|
199
261
|
shaka.util.Uint8ArrayUtils.concat(segment.initSegment, segment.data));
|
|
200
262
|
}
|
|
@@ -209,7 +271,6 @@ shaka.media.Transmuxer = class {
|
|
|
209
271
|
const output = {
|
|
210
272
|
data: shaka.util.Uint8ArrayUtils.concat(...this.transmuxedData_),
|
|
211
273
|
captions: this.captions_,
|
|
212
|
-
metadata: this.metadata_,
|
|
213
274
|
};
|
|
214
275
|
|
|
215
276
|
this.transmuxPromise_.resolve(output);
|
package/lib/offline/storage.js
CHANGED