Skip to content

Commit 6224ef3

Browse files
authored
Merge pull request #1664 from canalplus/fix/edge-mse-in-worker
Fix: microsoft edge some codecs are not supported by MSE in worker
2 parents f9d12a3 + 7c6be38 commit 6224ef3

File tree

6 files changed

+99
-6
lines changed

6 files changed

+99
-6
lines changed

src/core/main/worker/content_preparer.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { MediaSource_ } from "../../../compat/browser_compatibility_types";
12
import features from "../../../features";
23
import log from "../../../log";
34
import type { IManifest, IManifestMetadata } from "../../../manifest";
45
import { createRepresentationFilterFromFnString } from "../../../manifest";
6+
import type Manifest from "../../../manifest/classes";
57
import type { IMediaSourceInterface } from "../../../mse";
68
import MainMediaSourceInterface from "../../../mse/main_media_source_interface";
79
import WorkerMediaSourceInterface from "../../../mse/worker_media_source_interface";
@@ -13,6 +15,7 @@ import { WorkerMessageType } from "../../../multithread_types";
1315
import type { IPlayerError } from "../../../public_types";
1416
import assert from "../../../utils/assert";
1517
import idGenerator from "../../../utils/id_generator";
18+
import isNullOrUndefined from "../../../utils/is_null_or_undefined";
1619
import objectAssign from "../../../utils/object_assign";
1720
import type {
1821
CancellationError,
@@ -278,7 +281,7 @@ export default class ContentPreparer {
278281
) {
279282
return;
280283
}
281-
284+
updateCodecSupportInWorkerMode(manifest);
282285
const sentManifest = manifest.getMetadataSnapshot();
283286
manifest.addEventListener(
284287
"manifestUpdate",
@@ -534,3 +537,34 @@ function createMediaSourceInterfaceAndSegmentSinksStore(
534537

535538
return [mediaSourceInterface, segmentSinksStore, textSender];
536539
}
540+
541+
/**
542+
* Set Representation.isCodecSupportedInWebWorker to true or false
543+
* If the codec is supported in the current context.
544+
* If MSE in worker is not available, the attribute is not set.
545+
*/
546+
function updateCodecSupportInWorkerMode(manifestToUpdate: Manifest) {
547+
if (isNullOrUndefined(MediaSource_)) {
548+
return;
549+
}
550+
551+
const codecsMap = new Map<string, boolean>();
552+
for (const period of manifestToUpdate.periods) {
553+
const checkedAdaptations = [
554+
...(period.adaptations.video ?? []),
555+
...(period.adaptations.audio ?? []),
556+
];
557+
for (const adaptation of checkedAdaptations) {
558+
for (const representation of adaptation.representations) {
559+
const codec = `${representation.mimeType};codecs="${representation.codecs[0]}"`;
560+
if (codecsMap.has(codec)) {
561+
representation.isCodecSupportedInWebWorker = codecsMap.get(codec);
562+
} else {
563+
const supported = MediaSource_.isTypeSupported(codec);
564+
representation.isCodecSupportedInWebWorker = supported;
565+
codecsMap.set(codec, supported);
566+
}
567+
}
568+
}
569+
}
570+
}

src/main_thread/init/multi_thread_content_initializer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { IMediaElement } from "../../compat/browser_compatibility_types";
2+
import hasMseInWorker from "../../compat/has_mse_in_worker";
23
import mayMediaElementFailOnUndecipherableData from "../../compat/may_media_element_fail_on_undecipherable_data";
34
import shouldReloadMediaSourceOnDecipherabilityUpdate from "../../compat/should_reload_media_source_on_decipherability_update";
45
import type { ISegmentSinkMetrics } from "../../core/segment_sinks/segment_sinks_store";
@@ -1412,6 +1413,7 @@ export default class MultiThreadContentInitializer extends ContentInitializer {
14121413
const updatedCodecs = updateManifestCodecSupport(
14131414
manifest,
14141415
this._currentContentInfo?.contentDecryptor ?? null,
1416+
hasMseInWorker,
14151417
);
14161418
if (updatedCodecs.length > 0) {
14171419
sendMessage(this._settings.worker, {

src/main_thread/init/utils/__tests__/update_manifest_codec_support.test.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ describe("init - utils - updateManifestCodecSupport", () => {
193193
},
194194
};
195195
const contentDecryptor = new ContentDecryptor(video, [keySystem1]);
196-
updateManifestCodecSupport(manifest, contentDecryptor);
196+
updateManifestCodecSupport(manifest, contentDecryptor, true);
197197
expect(representationAVC.isSupported).toBe(true);
198198
expect(representationHEVC.isSupported).toBe(true);
199199
expect(representationVP9.isSupported).toBe(false); // Not Supported by MSE
@@ -274,11 +274,53 @@ describe("init - utils - updateManifestCodecSupport", () => {
274274
const contentDecryptor = new ContentDecryptor(video, [keySystem1]);
275275
await sleep(100);
276276
contentDecryptor.attach();
277-
updateManifestCodecSupport(manifest, contentDecryptor);
277+
updateManifestCodecSupport(manifest, contentDecryptor, true);
278278
expect(encryptedRepresentationAVC.isSupported).toBe(true);
279279
expect(encryptedRepresentationHEVC.isSupported).toBe(false); // Not supported by EME
280280
expect(encryptedRepresentationVP9.isSupported).toBe(false); // Not supported by MSE
281281
expect(encryptedRepresentationMP4A.isSupported).toBe(true);
282282
expect(encryptedRepresentationEC3.isSupported).toBe(false); // Not supported by EME
283283
});
284+
285+
it("should update to false if the codec is not usable with MSE in worker", () => {
286+
const representationAVC: IRepresentationMetadata = {
287+
bitrate: 1000,
288+
id: "representation1",
289+
uniqueId: "representation1",
290+
codecs: ["avc1.4d401e"],
291+
mimeType: "video/mp4",
292+
isSupported: undefined,
293+
isCodecSupportedInWebWorker: undefined,
294+
};
295+
const representationHEVC: IRepresentationMetadata = {
296+
bitrate: 2000,
297+
id: "representation2",
298+
uniqueId: "representation2",
299+
codecs: ["hvc1.2.4.L153.B0"],
300+
mimeType: "video/mp4",
301+
isSupported: undefined,
302+
isCodecSupportedInWebWorker: false,
303+
};
304+
305+
const representationMP4A: IRepresentationMetadata = {
306+
bitrate: 1000,
307+
id: "representation4",
308+
uniqueId: "representation4",
309+
codecs: ["mp4a.40.2"],
310+
mimeType: "audio/mp4",
311+
isSupported: undefined,
312+
isCodecSupportedInWebWorker: true,
313+
};
314+
const manifest = generateFakeManifestWithRepresentations(
315+
[representationAVC, representationHEVC],
316+
[representationMP4A],
317+
);
318+
319+
const video = document.createElement("video");
320+
const contentDecryptor = new ContentDecryptor(video, []);
321+
updateManifestCodecSupport(manifest, contentDecryptor, true);
322+
expect(representationAVC.isSupported).toBe(true);
323+
expect(representationHEVC.isSupported).toBe(false); // not supported with MSE in worker
324+
expect(representationMP4A.isSupported).toBe(true);
325+
});
284326
});

src/main_thread/init/utils/update_manifest_codec_support.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,15 @@ export function getCodecsWithUnknownSupport(
5656
* Because probing for codec support is always synchronous in the main thread,
5757
* calling this function ensures that support is now known.
5858
*
59-
* @param {Object} manifest
60-
* @param {Object|null} contentDecryptor
61-
* @returns {boolean}
59+
* @param {Object} manifest - The manifest to update
60+
* @param {Object|null} contentDecryptor - The current content decryptor
61+
* @param {boolean} isPlayingWithMSEinWorker - True if WebWorker is used with MSE in worker
62+
* @returns {Array.<Object>}
6263
*/
6364
export function updateManifestCodecSupport(
6465
manifest: IManifestMetadata,
6566
contentDecryptor: ContentDecryptor | null,
67+
isPlayingWithMSEinWorker: boolean,
6668
): ICodecSupportInfo[] {
6769
const codecSupportMap: Map<
6870
string,
@@ -131,6 +133,14 @@ export function updateManifestCodecSupport(
131133
let hasSupportedCodec: boolean = false;
132134
let hasCodecWithUndefinedSupport: boolean = false;
133135
adaptation.representations.forEach((representation) => {
136+
if (
137+
representation.isCodecSupportedInWebWorker === false &&
138+
isPlayingWithMSEinWorker
139+
) {
140+
representation.isSupported = false;
141+
return;
142+
}
143+
134144
if (representation.isSupported !== undefined) {
135145
if (representation.isSupported) {
136146
hasSupportedCodec = true;

src/manifest/classes/representation.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ class Representation implements IRepresentationMetadata {
121121
* `Manifest` methods for this.
122122
*/
123123
public shouldBeAvoided: boolean;
124+
/** If the codec is supported with MSE in worker */
125+
public isCodecSupportedInWebWorker: boolean | undefined;
124126

125127
/**
126128
* @param {Object} args
@@ -484,6 +486,7 @@ class Representation implements IRepresentationMetadata {
484486
hdrInfo: this.hdrInfo,
485487
contentProtections: this.contentProtections,
486488
decipherable: this.decipherable,
489+
isCodecSupportedInWebWorker: this.isCodecSupportedInWebWorker,
487490
};
488491
}
489492
}

src/manifest/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,6 @@ export interface IRepresentationMetadata {
488488
decipherable?: boolean | undefined;
489489
/** Encryption information for this Representation. */
490490
contentProtections?: IContentProtections | undefined;
491+
/** If the codec is supported with MSE in worker */
492+
isCodecSupportedInWebWorker?: boolean | undefined;
491493
}

0 commit comments

Comments
 (0)