diff --git a/demo/common/message_ids.js b/demo/common/message_ids.js
index 99de27b8a2..1bc3e904e2 100644
--- a/demo/common/message_ids.js
+++ b/demo/common/message_ids.js
@@ -201,6 +201,7 @@ shakaDemo.MessageIds = {
FAST_HALF_LIFE: 'DEMO_FAST_HALF_LIFE',
FORCE_HTTPS: 'DEMO_FORCE_HTTPS',
FORCE_TRANSMUX: 'DEMO_FORCE_TRANSMUX',
+ INSERT_FAKE_ENCRYPTION_IN_INIT: 'DEMO_INSERT_FAKE_ENCRYPTION_IN_INIT',
FUZZ_FACTOR: 'DEMO_FUZZ_FACTOR',
GAP_DETECTION_THRESHOLD: 'DEMO_GAP_DETECTION_THRESHOLD',
GAP_JUMP_TIMER_TIME: 'DEMO_GAP_JUMP_TIMER_TIME',
diff --git a/demo/config.js b/demo/config.js
index 568dd5e0a2..d0aa4a2e35 100644
--- a/demo/config.js
+++ b/demo/config.js
@@ -512,7 +512,9 @@ shakaDemo.Config = class {
.addTextInput_(MessageIds.SOURCE_BUFFER_EXTRA_FEATURES,
'mediaSource.sourceBufferExtraFeatures')
.addBoolInput_(MessageIds.FORCE_TRANSMUX,
- 'mediaSource.forceTransmux');
+ 'mediaSource.forceTransmux')
+ .addBoolInput_(MessageIds.INSERT_FAKE_ENCRYPTION_IN_INIT,
+ 'mediaSource.insertFakeEncryptionInInit');
}
/** @private */
diff --git a/demo/locales/en.json b/demo/locales/en.json
index 13c9bdb287..caa5329808 100644
--- a/demo/locales/en.json
+++ b/demo/locales/en.json
@@ -88,6 +88,7 @@
"DEMO_FAST_HALF_LIFE": "Fast half life",
"DEMO_FORCE_HTTPS": "Force HTTPS",
"DEMO_FORCE_TRANSMUX": "Force Transmux",
+ "DEMO_INSERT_FAKE_ENCRYPTION_IN_INIT": "Insert fake encryption in init segments when needed by the platform.",
"DEMO_FRONT_INTRO_DISMISS": "Dismiss",
"DEMO_FRONT_INTRO_ONE": "This is a demo of Google's Shaka Player, a JavaScript library for adaptive video streaming.",
"DEMO_FRONT_INTRO_TWO": "Choose a video to playback; more assets are available via the \"all content\" tab.",
diff --git a/demo/locales/source.json b/demo/locales/source.json
index be6c8e64c0..ae61c3d367 100644
--- a/demo/locales/source.json
+++ b/demo/locales/source.json
@@ -355,6 +355,10 @@
"description": "The name of a configuration value.",
"message": "Force Transmux"
},
+ "DEMO_INSERT_FAKE_ENCRYPTION_IN_INIT": {
+ "description": "The name of a configuration value.",
+ "message": "Insert fake encryption in init segments when needed by the platform."
+ },
"DEMO_FRONT_INTRO_DISMISS": {
"description": "A button allowing users to dismiss the intro message.",
"message": "Dismiss"
diff --git a/externs/shaka/player.js b/externs/shaka/player.js
index 2d6d79b6ba..5bed82da58 100644
--- a/externs/shaka/player.js
+++ b/externs/shaka/player.js
@@ -1226,7 +1226,8 @@ shaka.extern.StreamingConfiguration;
/**
* @typedef {{
* sourceBufferExtraFeatures: string,
- * forceTransmux: boolean
+ * forceTransmux: boolean,
+* insertFakeEncryptionInInit: boolean
* }}
*
* @description
@@ -1240,6 +1241,17 @@ shaka.extern.StreamingConfiguration;
* If this is true
, we will transmux AAC and TS content even if
* not strictly necessary for the assets to be played.
* This value defaults to false
.
+ * @property {boolean} insertFakeEncryptionInInit
+ * If true, will apply a work-around for non-encrypted init segments on
+ * encrypted content for some platforms.
+ *
+ * See https://github.com/shaka-project/shaka-player/issues/2759.
+ *
+ * If you know you don't need this, you canset this value to
+ * false
to gain a few milliseconds on loading time and seek
+ * time.
+ *
+ * This value defaults to true
.
* @exportDoc
*/
shaka.extern.MediaSourceConfiguration;
diff --git a/lib/media/media_source_engine.js b/lib/media/media_source_engine.js
index 6f31e8ae12..8f2d8d95b9 100644
--- a/lib/media/media_source_engine.js
+++ b/lib/media/media_source_engine.js
@@ -1483,15 +1483,17 @@ shaka.media.MediaSourceEngine = class {
const encryptionExpected = this.expectedEncryption_[contentType];
// If:
- // 1. this is an init segment,
- // 2. and encryption is expected,
- // 3. and the platform requires encryption in all init segments,
- // 4. and the content is MP4 (mimeType == "video/mp4" or "audio/mp4"),
+ // 1. the configuration tells to insert fake encryption,
+ // 2. and this is an init segment,
+ // 3. and encryption is expected,
+ // 4. and the platform requires encryption in all init segments,
+ // 5. and the content is MP4 (mimeType == "video/mp4" or "audio/mp4"),
// then insert fake encryption metadata for init segments that lack it.
// The MP4 requirement is because we can currently only do this
// transformation on MP4 containers.
// See: https://github.com/shaka-project/shaka-player/issues/2759
- if (isInitSegment &&
+ if (this.config_.insertFakeEncryptionInInit &&
+ isInitSegment &&
encryptionExpected &&
shaka.util.Platform.requiresEncryptionInfoInAllInitSegments() &&
shaka.util.MimeUtils.getContainerType(
diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js
index d1a1696ec1..aa2b997e60 100644
--- a/lib/util/player_configuration.js
+++ b/lib/util/player_configuration.js
@@ -310,6 +310,7 @@ shaka.util.PlayerConfiguration = class {
const mediaSource = {
sourceBufferExtraFeatures: '',
forceTransmux: false,
+ insertFakeEncryptionInInit: true,
};
const ads = {
diff --git a/test/media/media_source_engine_unit.js b/test/media/media_source_engine_unit.js
index 7019b156e9..566e4e8326 100644
--- a/test/media/media_source_engine_unit.js
+++ b/test/media/media_source_engine_unit.js
@@ -56,9 +56,9 @@ describe('MediaSourceEngine', () => {
const buffer2 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (2));
const buffer3 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (3));
- const fakeVideoStream = {mimeType: 'video/foo', drmInfos: []};
- const fakeAudioStream = {mimeType: 'audio/foo', drmInfos: []};
- const fakeTextStream = {mimeType: 'text/foo', drmInfos: []};
+ const fakeVideoStream = {mimeType: 'video/mp4', drmInfos: [{}]};
+ const fakeAudioStream = {mimeType: 'audio/mp4', drmInfos: []};
+ const fakeTextStream = {mimeType: 'text/mp4', drmInfos: []};
const fakeTransportStream = {mimeType: 'tsMimetype', drmInfos: []};
/** @type {shaka.extern.Stream} */
@@ -82,6 +82,10 @@ describe('MediaSourceEngine', () => {
/** @type {!jasmine.Spy} */
let createMediaSourceSpy;
+ /** @type {!jasmine.Spy} */
+ let requiresEncryptionInfoInAllInitSegmentsSpy;
+ /** @type {!jasmine.Spy} */
+ let fakeEncryptionSpy;
/** @type {!shaka.media.MediaSourceEngine} */
let mediaSourceEngine;
@@ -139,6 +143,12 @@ describe('MediaSourceEngine', () => {
shaka.media.MediaSourceEngine.prototype.createMediaSource =
Util.spyFunc(createMediaSourceSpy);
+ requiresEncryptionInfoInAllInitSegmentsSpy = spyOn(shaka.util.Platform,
+ 'requiresEncryptionInfoInAllInitSegments').and.returnValue(false);
+
+ fakeEncryptionSpy = spyOn(shaka.media.ContentWorkarounds, 'fakeEncryption')
+ .and.callFake((data) => data + 100);
+
// MediaSourceEngine uses video to:
// - set src attribute
// - read error codes when operations fail
@@ -269,8 +279,8 @@ describe('MediaSourceEngine', () => {
initObject.set(ContentType.AUDIO, fakeAudioStream);
initObject.set(ContentType.VIDEO, fakeVideoStream);
await mediaSourceEngine.init(initObject, false);
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/foo');
- expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/foo');
+ expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/mp4');
+ expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/mp4');
expect(shaka.text.TextEngine).not.toHaveBeenCalled();
});
@@ -396,6 +406,42 @@ describe('MediaSourceEngine', () => {
await mediaSourceEngine.init(initObject, false);
});
+ it('should apply fake encryption by default', async () => {
+ requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
+
+ const p = mediaSourceEngine.appendBuffer(
+ ContentType.VIDEO, buffer, null, fakeStream,
+ /* hasClosedCaptions= */ false);
+
+ expect(fakeEncryptionSpy).toHaveBeenCalled();
+
+ expect(videoSourceBuffer.appendBuffer)
+ .toHaveBeenCalledWith((buffer + 100));
+ videoSourceBuffer.updateend();
+
+ await p;
+ });
+
+ it('should not apply fake encryption when config is off', async () => {
+ requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
+
+ const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
+ config.insertFakeEncryptionInInit = false;
+
+ mediaSourceEngine.configure(config);
+
+ const p = mediaSourceEngine.appendBuffer(
+ ContentType.VIDEO, buffer, null, fakeStream,
+ /* hasClosedCaptions= */ false);
+
+ expect(fakeEncryptionSpy).not.toHaveBeenCalled();
+
+ expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
+ videoSourceBuffer.updateend();
+
+ await p;
+ });
+
it('appends the given data', async () => {
const p = mediaSourceEngine.appendBuffer(
ContentType.AUDIO, buffer, null, fakeStream,