From 13bf0e5d2c30a6d7fab383554b9ea662b0b6ad9d Mon Sep 17 00:00:00 2001 From: Paul Berberian Date: Thu, 11 Jul 2024 16:42:04 +0200 Subject: [PATCH] DASH: Remove "native" JS parser From the v4.1.0, we had 3 MPD parsers: - The "native" one, relying on the web's DOMParser API. This is historically the first one we used and still the one we rely by default on main thread. - The "WebAssembly" one, added in 2021. This one was initially written when we had to manage multi-megabytes MPD. Those took forever to parse on low-end devices but worse even on a PC, parsing it often (e.g. for a live content) could lead to a crash after several hours due to GC pressure. The idea was to parse the MPD in another thread (the initial MULTI_THREAD attempts date back from here :p) and to rely on WebAssembly to better control memory usage and performance (also the "native" one wasn't usable anyway on a WebWorker due to browser limitations). It turned out that the WebAssembly version was so light (note: we also rely on XML StAX parsing instead of DOM parsing which may have helped for that part) and fast that we didn't yet need the complexity of bringing another thread here. - The "fast js" one, added at the last `v4.1.0` release. This one follows attempts to make the `MULTI_THREAD` feature usable on non-WebAssembly devices. We noticed that other developers had recently made attempts for fast JS parsing without even needing the use of the DOMParser. They reported even faster performance due to much fewer XML integrity checks (which is OK for us, as MPD parsing performance is one of the most important aspect for us). This commit proposes that we remove the "native" one to just replace it by the "fast js" one. The "fast js" one has already been used in production for more than 6 months without issue, is equal-to-faster than the native one and it would lead to much less code. --- src/core/main/worker/worker_main.ts | 4 +- src/features/features_object.ts | 2 +- src/features/list/__tests__/dash.test.ts | 6 +- src/features/list/__tests__/dash_wasm.test.ts | 5 +- src/features/list/dash.ts | 4 +- src/features/types.ts | 13 +- .../refresh_scheduled_events_list.test.ts | 58 +- .../refresh_scheduled_events_list.ts | 9 +- .../__tests__/parse_s_element.test.ts | 104 +-- .../construct_timeline_from_elements.ts | 16 +- ...nstruct_timeline_from_previous_timeline.ts | 18 +- .../timeline/find_first_common_start_time.ts | 24 +- .../indexes/timeline/parse_s_element.ts | 44 -- .../timeline/timeline_representation_index.ts | 4 +- .../manifest/dash/common/parse_periods.ts | 31 +- .../__tests__/parse_from_xml_string.test.ts | 0 .../{fast-js-parser => js-parser}/index.ts | 0 .../node_parsers/AdaptationSet.ts | 0 .../node_parsers/BaseURL.ts | 0 .../node_parsers/ContentComponent.ts | 0 .../node_parsers/ContentProtection.ts | 0 .../node_parsers/EventStream.ts | 0 .../node_parsers/Initialization.ts | 0 .../node_parsers/MPD.ts | 0 .../node_parsers/Period.ts | 0 .../node_parsers/Representation.ts | 0 .../node_parsers/SegmentBase.ts | 0 .../node_parsers/SegmentList.ts | 0 .../node_parsers/SegmentTemplate.ts | 0 .../node_parsers/SegmentTimeline.ts | 0 .../node_parsers/SegmentURL.ts | 0 .../__tests__/AdaptationSet.test.ts | 0 .../__tests__/ContentComponent.test.ts | 0 .../__tests__/ContentProtection.test.ts | 0 .../__tests__/Initialization.test.ts | 0 .../node_parsers/__tests__/SegmentURL.test.ts | 0 .../node_parsers/__tests__/utils.test.ts | 0 .../node_parsers/utils.ts | 0 .../parse_from_xml_string.ts | 0 .../__tests__/parse_from_document.test.ts | 28 - .../manifest/dash/native-parser/index.ts | 18 - .../node_parsers/AdaptationSet.ts | 432 ------------ .../native-parser/node_parsers/BaseURL.ts | 34 - .../node_parsers/ContentComponent.ts | 49 -- .../node_parsers/ContentProtection.ts | 99 --- .../native-parser/node_parsers/EventStream.ts | 119 ---- .../node_parsers/Initialization.ts | 47 -- .../dash/native-parser/node_parsers/MPD.ts | 202 ------ .../dash/native-parser/node_parsers/Period.ts | 168 ----- .../node_parsers/Representation.ts | 262 -------- .../native-parser/node_parsers/SegmentBase.ts | 129 ---- .../native-parser/node_parsers/SegmentList.ts | 50 -- .../node_parsers/SegmentTemplate.ts | 102 --- .../node_parsers/SegmentTimeline.ts | 33 - .../native-parser/node_parsers/SegmentURL.ts | 61 -- .../__tests__/AdaptationSet.test.ts | 617 ------------------ .../__tests__/ContentComponent.test.ts | 52 -- .../__tests__/ContentProtection.test.ts | 234 ------- .../__tests__/Initialization.test.ts | 112 ---- .../__tests__/SegmentTimeline.test.ts | 99 --- .../node_parsers/__tests__/SegmentURL.test.ts | 168 ----- .../node_parsers/__tests__/utils.test.ts | 201 ------ .../dash/native-parser/node_parsers/utils.ts | 385 ----------- .../dash/native-parser/parse_from_document.ts | 125 ---- .../manifest/dash/node_parser_types.ts | 19 +- src/transports/dash/manifest_parser.ts | 31 +- 66 files changed, 99 insertions(+), 4119 deletions(-) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/__tests__/parse_from_xml_string.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/index.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/AdaptationSet.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/BaseURL.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/ContentComponent.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/ContentProtection.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/EventStream.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/Initialization.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/MPD.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/Period.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/Representation.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/SegmentBase.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/SegmentList.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/SegmentTemplate.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/SegmentTimeline.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/SegmentURL.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/__tests__/AdaptationSet.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/__tests__/ContentComponent.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/__tests__/ContentProtection.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/__tests__/Initialization.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/__tests__/SegmentURL.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/__tests__/utils.test.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/node_parsers/utils.ts (100%) rename src/parsers/manifest/dash/{fast-js-parser => js-parser}/parse_from_xml_string.ts (100%) delete mode 100644 src/parsers/manifest/dash/native-parser/__tests__/parse_from_document.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/index.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/BaseURL.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/ContentComponent.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/ContentProtection.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/EventStream.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/Initialization.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/MPD.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/Period.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/Representation.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/SegmentBase.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/SegmentList.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/SegmentTemplate.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/SegmentTimeline.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/SegmentURL.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/AdaptationSet.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentComponent.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/__tests__/utils.test.ts delete mode 100644 src/parsers/manifest/dash/native-parser/node_parsers/utils.ts delete mode 100644 src/parsers/manifest/dash/native-parser/parse_from_document.ts diff --git a/src/core/main/worker/worker_main.ts b/src/core/main/worker/worker_main.ts index 8fc8458657..8d68e98bec 100644 --- a/src/core/main/worker/worker_main.ts +++ b/src/core/main/worker/worker_main.ts @@ -10,7 +10,7 @@ import type { IReferenceUpdateMessage, } from "../../../multithread_types"; import { MainThreadMessageType, WorkerMessageType } from "../../../multithread_types"; -import DashFastJsParser from "../../../parsers/manifest/dash/fast-js-parser"; +import DashJsParser from "../../../parsers/manifest/dash/js-parser"; import DashWasmParser from "../../../parsers/manifest/dash/wasm-parser"; import { ObservationPosition } from "../../../playback_observer"; import type { IWorkerPlaybackObservation } from "../../../playback_observer/worker_playback_observer"; @@ -72,7 +72,7 @@ export default function initializeWorkerMain() { // TODO allow worker-side feature-switching? Not sure how const dashWasmParser = new DashWasmParser(); features.dashParsers.wasm = dashWasmParser; - features.dashParsers.fastJs = DashFastJsParser; + features.dashParsers.js = DashJsParser; features.transports.dash = createDashPipelines; /** diff --git a/src/features/features_object.ts b/src/features/features_object.ts index 3adfdbdc04..fd4f632665 100644 --- a/src/features/features_object.ts +++ b/src/features/features_object.ts @@ -21,7 +21,7 @@ import type { IFeaturesObject } from "./types"; * @type {Object} */ const features: IFeaturesObject = { - dashParsers: { wasm: null, native: null, fastJs: null }, + dashParsers: { wasm: null, js: null }, createDebugElement: null, directfile: null, decrypt: null, diff --git a/src/features/list/__tests__/dash.test.ts b/src/features/list/__tests__/dash.test.ts index 8f996ffc72..c3896dc28e 100644 --- a/src/features/list/__tests__/dash.test.ts +++ b/src/features/list/__tests__/dash.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from "vitest"; import MediaSourceContentInitializer from "../../../main_thread/init/media_source_content_initializer"; -import nativeDashParser from "../../../parsers/manifest/dash/native-parser"; +import dashJsParser from "../../../parsers/manifest/dash/js-parser"; import DASHFeature from "../../../transports/dash"; import type { IFeaturesObject } from "../../types"; import addDASHFeature from "../dash"; @@ -9,13 +9,13 @@ describe("Features list - DASH", () => { it("should add DASH in the current features", () => { const featureObject = { transports: {}, - dashParsers: { fastJs: null, native: null, wasm: null }, + dashParsers: { js: null, wasm: null }, mainThreadMediaSourceInit: null, } as unknown as IFeaturesObject; addDASHFeature(featureObject); expect(featureObject).toEqual({ transports: { dash: DASHFeature }, - dashParsers: { native: nativeDashParser, fastJs: null, wasm: null }, + dashParsers: { js: dashJsParser, wasm: null }, mainThreadMediaSourceInit: MediaSourceContentInitializer, }); expect(featureObject.transports.dash).toBe(DASHFeature); diff --git a/src/features/list/__tests__/dash_wasm.test.ts b/src/features/list/__tests__/dash_wasm.test.ts index b12524c103..20df11c1d1 100644 --- a/src/features/list/__tests__/dash_wasm.test.ts +++ b/src/features/list/__tests__/dash_wasm.test.ts @@ -21,12 +21,11 @@ describe("Features list - DASH WASM Parser", () => { const featureObject = { transports: {}, - dashParsers: { native: null, fastJs: null, wasm: null }, + dashParsers: { js: null, wasm: null }, } as unknown as IFeaturesObject; DASH_WASM._addFeature(featureObject); expect(featureObject.transports).toEqual({ dash: DASHFeature }); - expect(featureObject.dashParsers.native).toEqual(null); - expect(featureObject.dashParsers.fastJs).toEqual(null); + expect(featureObject.dashParsers.js).toEqual(null); expect(featureObject.dashParsers.wasm).toBeInstanceOf(DashWasmParser); }); }); diff --git a/src/features/list/dash.ts b/src/features/list/dash.ts index 4f1f70b338..eb1b31d29e 100644 --- a/src/features/list/dash.ts +++ b/src/features/list/dash.ts @@ -15,7 +15,7 @@ */ import MediaSourceContentInitializer from "../../main_thread/init/media_source_content_initializer"; -import dashJsParser from "../../parsers/manifest/dash/native-parser"; +import dashJsParser from "../../parsers/manifest/dash/js-parser"; import dash from "../../transports/dash"; import type { IFeaturesObject } from "../types"; @@ -27,7 +27,7 @@ function addDASHFeature(features: IFeaturesObject): void { if (features.transports.dash === undefined) { features.transports.dash = dash; } - features.dashParsers.native = dashJsParser; + features.dashParsers.js = dashJsParser; features.mainThreadMediaSourceInit = MediaSourceContentInitializer; } diff --git a/src/features/types.ts b/src/features/types.ts index 26fcacafe1..082061e88c 100644 --- a/src/features/types.ts +++ b/src/features/types.ts @@ -61,12 +61,7 @@ export type IHTMLTextTracksBuffer = new ( */ export type INativeTextTracksBuffer = new (mediaElement: IMediaElement) => SegmentSink; -export type IDashNativeParser = ( - dom: Document, - args: IMPDParserArguments, -) => IDashParserResponse; - -export type IDashFastJsParser = ( +export type IDashJsParser = ( xml: string, args: IMPDParserArguments, ) => IDashParserResponse; @@ -142,11 +137,7 @@ export interface IFeaturesObject { /** * Entirely JavaScript-based Manifest DASH parser. */ - fastJs: IDashFastJsParser | null; - /** - * JavaScript+Browser's DOMParser-based Manifest DASH parser. - */ - native: IDashNativeParser | null; + js: IDashJsParser | null; }; /** Implement text track rendering through `` HTML elements. */ nativeTextDisplayer: typeof NativeTextDisplayer | null; diff --git a/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts b/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts index 9c6cdd5ad9..5861b0f0f6 100644 --- a/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts +++ b/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect, vi } from "vitest"; import type { IManifest } from "../../../../manifest"; +import type { IParsedStreamEventData } from "../../../../parsers/manifest"; import type { IStreamEventData } from "../../../../public_types"; import type IRefreshScheduledEventsList from "../stream_events_emitter/refresh_scheduled_events_list"; import type { @@ -9,13 +10,33 @@ import type { describe("init - refreshScheduledEventsList", () => { it("should correctly refresh scheduled events", async () => { - function generateEventData(): IStreamEventData { + function generateInputEventData(): IParsedStreamEventData { return { type: "dash-event-stream", value: { schemeIdUri: "toto", timescale: 1, - element: document.createElement("div"), + xmlData: { data: "
", namespaces: [] }, + }, + }; + } + function generateOutputEventData(): IStreamEventData { + const parsedDom = new DOMParser().parseFromString( + "
", + "application/xml", + ).documentElement; + + const element = + parsedDom.children.length > 0 + ? parsedDom.children[0] + : (parsedDom.childNodes[0] as HTMLElement); + + return { + type: "dash-event-stream", + value: { + schemeIdUri: "toto", + timescale: 1, + element, }, }; } @@ -23,14 +44,14 @@ describe("init - refreshScheduledEventsList", () => { periods: [ { start: 0, - streamEvents: [{ start: 0, end: 1, data: generateEventData(), id: "1" }], + streamEvents: [{ start: 0, end: 1, data: generateInputEventData(), id: "1" }], }, { start: 10, streamEvents: [ - { start: 11, end: 20, data: generateEventData(), id: "2" }, - { start: 12, data: generateEventData(), id: "3" }, - { start: 13, end: 13.1, data: generateEventData(), id: "4" }, + { start: 11, end: 20, data: generateInputEventData(), id: "2" }, + { start: 12, data: generateInputEventData(), id: "3" }, + { start: 13, end: 13.1, data: generateInputEventData(), id: "4" }, ], }, ], @@ -41,22 +62,22 @@ describe("init - refreshScheduledEventsList", () => { start: 1000, end: 1000000, id: "must-disapear", - data: generateEventData(), + data: generateOutputEventData(), publicEvent: { start: 1000, end: 1000000, - data: generateEventData(), + data: generateOutputEventData(), }, }, { start: 0, end: 1, - data: generateEventData(), + data: generateOutputEventData(), id: "1", publicEvent: { start: 1000, end: 1000000, - data: generateEventData(), + data: generateOutputEventData(), }, }, ]; @@ -70,33 +91,32 @@ describe("init - refreshScheduledEventsList", () => { start: 0, end: 1, id: "1", - data: generateEventData(), + data: generateOutputEventData(), publicEvent: { start: 1000, end: 1000000, - data: generateEventData(), + data: generateOutputEventData(), }, }, { start: 11, end: 20, id: "2", - publicEvent: { start: 11, end: 20, data: generateEventData() }, - data: generateEventData(), + publicEvent: { start: 11, end: 20, data: generateOutputEventData() }, + data: generateOutputEventData(), }, { start: 12, - end: undefined, id: "3", - publicEvent: { start: 12, data: generateEventData() }, - data: generateEventData(), + publicEvent: { start: 12, data: generateOutputEventData() }, + data: generateOutputEventData(), }, { start: 13, end: 13.1, id: "4", - publicEvent: { start: 13, end: 13.1, data: generateEventData() }, - data: generateEventData(), + publicEvent: { start: 13, end: 13.1, data: generateOutputEventData() }, + data: generateOutputEventData(), }, ]); }); diff --git a/src/main_thread/init/utils/stream_events_emitter/refresh_scheduled_events_list.ts b/src/main_thread/init/utils/stream_events_emitter/refresh_scheduled_events_list.ts index b57de0d57e..2f63f5eed9 100644 --- a/src/main_thread/init/utils/stream_events_emitter/refresh_scheduled_events_list.ts +++ b/src/main_thread/init/utils/stream_events_emitter/refresh_scheduled_events_list.ts @@ -41,9 +41,7 @@ function refreshScheduledEventsList( } let element: Element; - if (data.value.element !== undefined) { - element = data.value.element; - } else if (data.value.xmlData !== undefined) { + if (data.value.xmlData !== undefined) { // First, we will create a parent Element defining all namespaces that // should have been encountered until know. // This is needed because the DOMParser API might throw when @@ -66,7 +64,10 @@ function refreshScheduledEventsList( } else { return; } - const actualData = { type: data.type, value: { ...data.value, element } }; + const actualData = { + type: data.type, + value: { ...data.value, xmlData: undefined, element }, + }; if (end === undefined) { const newScheduledEvent = { start, diff --git a/src/parsers/manifest/dash/common/indexes/timeline/__tests__/parse_s_element.test.ts b/src/parsers/manifest/dash/common/indexes/timeline/__tests__/parse_s_element.test.ts index 2dbccd3d73..3f0619e534 100644 --- a/src/parsers/manifest/dash/common/indexes/timeline/__tests__/parse_s_element.test.ts +++ b/src/parsers/manifest/dash/common/indexes/timeline/__tests__/parse_s_element.test.ts @@ -2,64 +2,11 @@ import { describe, it, expect, vi } from "vitest"; import log from "../../../../../../../log"; import type { ITNode } from "../../../../../../../utils/xml-parser"; import { parseXml } from "../../../../../../../utils/xml-parser"; -import { parseSHTMLElement, parseSElementNode } from "../parse_s_element"; +import { parseSElementNode } from "../parse_s_element"; function testNumberAttribute(attributeName: string, variableName?: string): void { const _variableName = variableName ?? attributeName; - it(`should correctly parse an HTML S element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element1)).toEqual({ [_variableName]: 12 }); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element2)).toEqual({ [_variableName]: 0 }); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element3)).toEqual({ [_variableName]: -50 }); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); - - it(`should correctly parse an HTML S element with an incorrect ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element1)).toEqual({}); - expect(spyLog).toHaveBeenCalledTimes(1); - expect(spyLog).toHaveBeenCalledWith(`DASH: invalid ${attributeName} ("toto")`); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element2)).toEqual({}); - expect(spyLog).toHaveBeenCalledTimes(2); - expect(spyLog).toHaveBeenCalledWith(`DASH: invalid ${attributeName} ("PT5M")`); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - - expect(parseSHTMLElement(element3)).toEqual({}); - expect(spyLog).toHaveBeenCalledTimes(3); - expect(spyLog).toHaveBeenCalledWith(`DASH: invalid ${attributeName} ("")`); - spyLog.mockRestore(); - }); - it(`should correctly parse a node S element with a correct ${attributeName} attribute`, () => { const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); const element1 = parseXml(``)[0] as ITNode; @@ -97,43 +44,10 @@ function testNumberAttribute(attributeName: string, variableName?: string): void } describe("DASH Node Parsers - S", () => { - it("should correctly parse an HTML S element without attributes", () => { - const element = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(parseSHTMLElement(element)).toEqual({}); - }); - - it("should correctly parse a Node S element without attributes", () => { - const element = parseXml("")[0] as ITNode; - expect(parseSElementNode(element)).toEqual({}); - }); - testNumberAttribute("t", "start"); testNumberAttribute("r", "repeatCount"); testNumberAttribute("d", "duration"); - it("should correctly parse an HTML S Element with every attributes", () => { - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element1)).toEqual({ - start: 0, - repeatCount: 12, - duration: 4, - }); - - const element2 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element2)).toEqual({ - start: 99, - repeatCount: 0, - duration: 4, - }); - }); - it("should correctly parse a node S Element with every attributes", () => { const element1 = parseXml('')[0] as ITNode; expect(parseSElementNode(element1)).toEqual({ @@ -150,22 +64,6 @@ describe("DASH Node Parsers - S", () => { }); }); - it("should correctly parse an HTML S Element with unknown attributes", () => { - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSHTMLElement(element1)).toEqual({ - start: 0, - repeatCount: 12, - duration: 4, - }); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseSHTMLElement(element2)).toEqual({}); - }); - it("should correctly parse a node S Element with unknown attributes", () => { const element1 = parseXml('')[0] as ITNode; expect(parseSElementNode(element1)).toEqual({ diff --git a/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.ts b/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.ts index 9f2d905177..e260518302 100644 --- a/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.ts +++ b/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.ts @@ -18,29 +18,23 @@ import type { ITNode } from "../../../../../../utils/xml-parser"; import type { IIndexSegment } from "../../../../utils/index_helpers"; import convertElementsToIndexSegment from "./convert_element_to_index_segment"; import type { IParsedS } from "./parse_s_element"; -import { parseSElementNode, parseSHTMLElement } from "./parse_s_element"; +import { parseSElementNode } from "./parse_s_element"; /** * Allows to generate the "timeline" for the "Timeline" RepresentationIndex. * Call this function when the timeline is unknown. * This function was added to only perform that task lazily, i.e. only when * first needed. - * @param {Array.|HTMLCollection} elements - All S nodes constituting + * @param {Array.} elements - All S nodes constituting * the corresponding SegmentTimeline node. * @returns {Array.} */ export default function constructTimelineFromElements( - elements: ITNode[] | HTMLCollection, + elements: ITNode[], ): IIndexSegment[] { const initialTimeline: IParsedS[] = []; - if (Array.isArray(elements)) { - for (let i = 0; i < elements.length; i++) { - initialTimeline.push(parseSElementNode(elements[i])); - } - } else { - for (let i = 0; i < elements.length; i++) { - initialTimeline.push(parseSHTMLElement(elements[i])); - } + for (let i = 0; i < elements.length; i++) { + initialTimeline.push(parseSElementNode(elements[i])); } const timeline: IIndexSegment[] = []; for (let i = 0; i < initialTimeline.length; i++) { diff --git a/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.ts b/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.ts index c038b2b88a..413f1ce32d 100644 --- a/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.ts +++ b/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.ts @@ -21,10 +21,10 @@ import constructTimelineFromElements from "./construct_timeline_from_elements"; import convertElementToIndexSegment from "./convert_element_to_index_segment"; import findFirstCommonStartTime from "./find_first_common_start_time"; import type { IParsedS } from "./parse_s_element"; -import { parseSElementNode, parseSHTMLElement } from "./parse_s_element"; +import { parseSElementNode } from "./parse_s_element"; export default function constructTimelineFromPreviousTimeline( - newElements: ITNode[] | HTMLCollection, + newElements: ITNode[], prevTimeline: IIndexSegment[], ): IIndexSegment[] { // Find first index in both timeline where a common segment is found. @@ -65,9 +65,7 @@ export default function constructTimelineFromPreviousTimeline( } const prevLastElement = newTimeline[newTimeline.length - 1]; - const newCommonElt = Array.isArray(newElements) - ? parseSElementNode(newElements[lastCommonEltNewEltsIdx]) - : parseSHTMLElement(newElements[lastCommonEltNewEltsIdx]); + const newCommonElt = parseSElementNode(newElements[lastCommonEltNewEltsIdx]); const newRepeatCountOffseted = (newCommonElt.repeatCount ?? 0) - repeatNumberInNewElements; if ( @@ -90,14 +88,8 @@ export default function constructTimelineFromPreviousTimeline( const newEltsToPush: IIndexSegment[] = []; const items: IParsedS[] = []; - if (Array.isArray(newElements)) { - for (let i = lastCommonEltNewEltsIdx + 1; i < newElements.length; i++) { - items.push(parseSElementNode(newElements[i])); - } - } else { - for (let i = lastCommonEltNewEltsIdx + 1; i < newElements.length; i++) { - items.push(parseSHTMLElement(newElements[i])); - } + for (let i = lastCommonEltNewEltsIdx + 1; i < newElements.length; i++) { + items.push(parseSElementNode(newElements[i])); } for (let i = 0; i < items.length; i++) { const item = items[i]; diff --git a/src/parsers/manifest/dash/common/indexes/timeline/find_first_common_start_time.ts b/src/parsers/manifest/dash/common/indexes/timeline/find_first_common_start_time.ts index bb793ea602..6bd7dcc3eb 100644 --- a/src/parsers/manifest/dash/common/indexes/timeline/find_first_common_start_time.ts +++ b/src/parsers/manifest/dash/common/indexes/timeline/find_first_common_start_time.ts @@ -29,7 +29,7 @@ import type { IIndexSegment } from "../../../../utils/index_helpers"; */ export default function findFirstCommonStartTime( prevTimeline: IIndexSegment[], - newElements: ITNode[] | HTMLCollection, + newElements: ITNode[], ): { /** Index in `prevSegments` where the first common segment start is found. */ prevSegmentsIdx: number; @@ -50,9 +50,7 @@ export default function findFirstCommonStartTime( return null; } const prevInitialStart = prevTimeline[0].start; - const newFirstTAttr = Array.isArray(newElements) - ? newElements[0].attributes.t - : newElements[0].getAttribute("t"); + const newFirstTAttr = newElements[0].attributes.t; const newInitialStart = isNullOrUndefined(newFirstTAttr) ? null : parseInt(newFirstTAttr, 10); @@ -104,18 +102,15 @@ export default function findFirstCommonStartTime( } } else { let newElementsIdx = 0; - let newNodeElt: ITNode | null = Array.isArray(newElements) ? newElements[0] : null; - let newDomElt: Element | null = Array.isArray(newElements) ? null : newElements[0]; + let newNodeElt: ITNode | null = newElements[0]; let currentTimeOffset = newInitialStart; while (true) { - const dAttr = - newNodeElt !== null ? newNodeElt.attributes.d : newDomElt?.getAttribute("d"); + const dAttr = newNodeElt.attributes.d; const duration = isNullOrUndefined(dAttr) ? null : parseInt(dAttr, 10); if (duration === null || Number.isNaN(duration)) { return null; } - const rAttr = - newNodeElt !== null ? newNodeElt.attributes.r : newDomElt?.getAttribute("r"); + const rAttr = newNodeElt.attributes.r; const repeatCount = isNullOrUndefined(rAttr) ? null : parseInt(rAttr, 10); if (repeatCount !== null) { @@ -142,13 +137,8 @@ export default function findFirstCommonStartTime( if (newElementsIdx >= newElements.length) { return null; } - if (Array.isArray(newElements)) { - newNodeElt = newElements[newElementsIdx]; - } else { - newDomElt = newElements[newElementsIdx]; - } - const tAttr = - newNodeElt !== null ? newNodeElt.attributes.t : newDomElt?.getAttribute("t"); + newNodeElt = newElements[newElementsIdx]; + const tAttr = newNodeElt.attributes.t; const time = isNullOrUndefined(tAttr) ? null : parseInt(tAttr, 10); if (time !== null) { if (Number.isNaN(time)) { diff --git a/src/parsers/manifest/dash/common/indexes/timeline/parse_s_element.ts b/src/parsers/manifest/dash/common/indexes/timeline/parse_s_element.ts index d18733feba..41babe1b4c 100644 --- a/src/parsers/manifest/dash/common/indexes/timeline/parse_s_element.ts +++ b/src/parsers/manifest/dash/common/indexes/timeline/parse_s_element.ts @@ -78,47 +78,3 @@ export function parseSElementNode(root: ITNode): IParsedS { } return parsedS; } - -/** - * Parse a given element in the MPD under an `Element` form into a JS - * Object. - * @param {Element} root - * @returns {Object} - */ -export function parseSHTMLElement(root: Element): IParsedS { - const parsedS: IParsedS = {}; - - for (let j = 0; j < root.attributes.length; j++) { - const attribute = root.attributes[j]; - switch (attribute.name) { - case "t": { - const start = parseInt(attribute.value, 10); - if (isNaN(start)) { - log.warn(`DASH: invalid t ("${attribute.value}")`); - } else { - parsedS.start = start; - } - break; - } - case "d": { - const duration = parseInt(attribute.value, 10); - if (isNaN(duration)) { - log.warn(`DASH: invalid d ("${attribute.value}")`); - } else { - parsedS.duration = duration; - } - break; - } - case "r": { - const repeatCount = parseInt(attribute.value, 10); - if (isNaN(repeatCount)) { - log.warn(`DASH: invalid r ("${attribute.value}")`); - } else { - parsedS.repeatCount = repeatCount; - } - break; - } - } - } - return parsedS; -} diff --git a/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts b/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts index 284ebaaefc..5e5b8daeee 100644 --- a/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +++ b/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts @@ -150,7 +150,7 @@ export interface ITimelineIndexIndexArgument { */ presentationTimeOffset?: number | undefined; - timelineParser?: (() => ITNode[] | HTMLCollection) | undefined; + timelineParser?: (() => ITNode[]) | undefined; timeline?: ISegmentTimelineElement[] | undefined; } @@ -248,7 +248,7 @@ export default class TimelineRepresentationIndex implements IRepresentationIndex * Lazily get the S elements from this timeline. * `null` once this call has been done once, to free memory. */ - private _parseTimeline: (() => ITNode[] | HTMLCollection) | null; + private _parseTimeline: (() => ITNode[]) | null; /** * This variable represents the same `TimelineRepresentationIndex` at the diff --git a/src/parsers/manifest/dash/common/parse_periods.ts b/src/parsers/manifest/dash/common/parse_periods.ts index ffe26f737c..51ece0b271 100644 --- a/src/parsers/manifest/dash/common/parse_periods.ts +++ b/src/parsers/manifest/dash/common/parse_periods.ts @@ -19,7 +19,6 @@ import type { IManifest } from "../../../../manifest"; import flatMap from "../../../../utils/flat_map"; import idGenerator from "../../../../utils/id_generator"; import isNullOrUndefined from "../../../../utils/is_null_or_undefined"; -import isWorker from "../../../../utils/is_worker"; import getMonotonicTimeStamp from "../../../../utils/monotonic_timestamp"; import objectValues from "../../../../utils/object_values"; import { utf8ToStr } from "../../../../utils/string_parsing"; @@ -313,23 +312,19 @@ function generateStreamEvents( let element; let xmlData; - if (!isWorker && eventIr.eventStreamData instanceof Element) { - element = eventIr.eventStreamData; - } else { - try { - xmlData = { - namespaces: allNamespaces, - data: - typeof eventIr.eventStreamData === "string" - ? eventIr.eventStreamData - : utf8ToStr(new Uint8Array(eventIr.eventStreamData as ArrayBuffer)), - }; - } catch (err) { - log.error( - "DASH: Error while parsing event-stream:", - err instanceof Error ? err.message : "Unknown error", - ); - } + try { + xmlData = { + namespaces: allNamespaces, + data: + typeof eventIr.eventStreamData === "string" + ? eventIr.eventStreamData + : utf8ToStr(new Uint8Array(eventIr.eventStreamData)), + }; + } catch (err) { + log.error( + "DASH: Error while parsing event-stream:", + err instanceof Error ? err.message : "Unknown error", + ); } res.push({ start, diff --git a/src/parsers/manifest/dash/fast-js-parser/__tests__/parse_from_xml_string.test.ts b/src/parsers/manifest/dash/js-parser/__tests__/parse_from_xml_string.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/__tests__/parse_from_xml_string.test.ts rename to src/parsers/manifest/dash/js-parser/__tests__/parse_from_xml_string.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/index.ts b/src/parsers/manifest/dash/js-parser/index.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/index.ts rename to src/parsers/manifest/dash/js-parser/index.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/AdaptationSet.ts b/src/parsers/manifest/dash/js-parser/node_parsers/AdaptationSet.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/AdaptationSet.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/AdaptationSet.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/BaseURL.ts b/src/parsers/manifest/dash/js-parser/node_parsers/BaseURL.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/BaseURL.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/BaseURL.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/ContentComponent.ts b/src/parsers/manifest/dash/js-parser/node_parsers/ContentComponent.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/ContentComponent.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/ContentComponent.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/ContentProtection.ts b/src/parsers/manifest/dash/js-parser/node_parsers/ContentProtection.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/ContentProtection.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/ContentProtection.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/EventStream.ts b/src/parsers/manifest/dash/js-parser/node_parsers/EventStream.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/EventStream.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/EventStream.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/Initialization.ts b/src/parsers/manifest/dash/js-parser/node_parsers/Initialization.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/Initialization.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/Initialization.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/MPD.ts b/src/parsers/manifest/dash/js-parser/node_parsers/MPD.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/MPD.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/MPD.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/Period.ts b/src/parsers/manifest/dash/js-parser/node_parsers/Period.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/Period.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/Period.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/Representation.ts b/src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/Representation.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentBase.ts b/src/parsers/manifest/dash/js-parser/node_parsers/SegmentBase.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentBase.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/SegmentBase.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentList.ts b/src/parsers/manifest/dash/js-parser/node_parsers/SegmentList.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentList.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/SegmentList.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentTemplate.ts b/src/parsers/manifest/dash/js-parser/node_parsers/SegmentTemplate.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentTemplate.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/SegmentTemplate.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentTimeline.ts b/src/parsers/manifest/dash/js-parser/node_parsers/SegmentTimeline.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentTimeline.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/SegmentTimeline.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentURL.ts b/src/parsers/manifest/dash/js-parser/node_parsers/SegmentURL.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/SegmentURL.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/SegmentURL.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/AdaptationSet.test.ts b/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/AdaptationSet.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/AdaptationSet.test.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/__tests__/AdaptationSet.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentComponent.test.ts b/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/ContentComponent.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentComponent.test.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/__tests__/ContentComponent.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentProtection.test.ts b/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/ContentProtection.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentProtection.test.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/__tests__/ContentProtection.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/Initialization.test.ts b/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/Initialization.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/Initialization.test.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/__tests__/Initialization.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/SegmentURL.test.ts b/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/SegmentURL.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/SegmentURL.test.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/__tests__/SegmentURL.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/utils.test.ts b/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/utils.test.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/utils.test.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/__tests__/utils.test.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/utils.ts b/src/parsers/manifest/dash/js-parser/node_parsers/utils.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/node_parsers/utils.ts rename to src/parsers/manifest/dash/js-parser/node_parsers/utils.ts diff --git a/src/parsers/manifest/dash/fast-js-parser/parse_from_xml_string.ts b/src/parsers/manifest/dash/js-parser/parse_from_xml_string.ts similarity index 100% rename from src/parsers/manifest/dash/fast-js-parser/parse_from_xml_string.ts rename to src/parsers/manifest/dash/js-parser/parse_from_xml_string.ts diff --git a/src/parsers/manifest/dash/native-parser/__tests__/parse_from_document.test.ts b/src/parsers/manifest/dash/native-parser/__tests__/parse_from_document.test.ts deleted file mode 100644 index 21196c1540..0000000000 --- a/src/parsers/manifest/dash/native-parser/__tests__/parse_from_document.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, it, expect } from "vitest"; -import type { IManifest } from "../../../../../manifest"; -import parseFromDocument from "../index"; - -describe("parseFromDocument", () => { - function setDocumentFromString(str: string): Document { - return new DOMParser().parseFromString(str, "application/xml"); - } - - it("throws root if not MPD", function () { - const doc = setDocumentFromString(""); - - expect(function () { - parseFromDocument(doc, { - url: "", - externalClockOffset: 10, - unsafelyBaseOnPreviousManifest: null, - }); - }).toThrow("document root should be MPD"); - expect(function () { - const prevManifest = {} as unknown as IManifest; - parseFromDocument(doc, { - url: "", - unsafelyBaseOnPreviousManifest: prevManifest, - }); - }).toThrow("document root should be MPD"); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/index.ts b/src/parsers/manifest/dash/native-parser/index.ts deleted file mode 100644 index 4599d5561a..0000000000 --- a/src/parsers/manifest/dash/native-parser/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import parseFromDocument from "./parse_from_document"; -export default parseFromDocument; diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts b/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts deleted file mode 100644 index 09ddfe0811..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts +++ /dev/null @@ -1,432 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import isNullOrUndefined from "../../../../../utils/is_null_or_undefined"; -import type { - IAdaptationSetAttributes, - IAdaptationSetChildren, - IAdaptationSetIntermediateRepresentation, -} from "../../node_parser_types"; -import parseBaseURL from "./BaseURL"; -import parseContentComponent from "./ContentComponent"; -import parseContentProtection from "./ContentProtection"; -import { createRepresentationIntermediateRepresentation } from "./Representation"; -import parseSegmentBase from "./SegmentBase"; -import parseSegmentList from "./SegmentList"; -import parseSegmentTemplate from "./SegmentTemplate"; -import { - parseBoolean, - parseIntOrBoolean, - parseMaybeDividedNumber, - parseMPDFloat, - parseMPDInteger, - parseScheme, - ValueParser, -} from "./utils"; - -/** - * Parse child nodes from an AdaptationSet. - * @param {NodeList} adaptationSetChildren - The AdaptationSet child nodes. - * @returns {Array.} - */ -function parseAdaptationSetChildren( - adaptationSetChildren: NodeList, -): [IAdaptationSetChildren, Error[]] { - const children: IAdaptationSetChildren = { - baseURLs: [], - representations: [], - }; - const contentProtections = []; - let warnings: Error[] = []; - for (let i = 0; i < adaptationSetChildren.length; i++) { - if (adaptationSetChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentElement = adaptationSetChildren[i] as Element; - - switch (currentElement.nodeName) { - case "Accessibility": - if (children.accessibilities === undefined) { - children.accessibilities = [parseScheme(currentElement)]; - } else { - children.accessibilities.push(parseScheme(currentElement)); - } - break; - - case "BaseURL": { - const [baseURLObj, baseURLWarnings] = parseBaseURL(currentElement); - if (baseURLObj !== undefined) { - children.baseURLs.push(baseURLObj); - } - if (baseURLWarnings.length > 0) { - warnings = warnings.concat(baseURLWarnings); - } - break; - } - - case "ContentComponent": - children.contentComponent = parseContentComponent(currentElement); - break; - - case "EssentialProperty": - if (isNullOrUndefined(children.essentialProperties)) { - children.essentialProperties = [parseScheme(currentElement)]; - } else { - children.essentialProperties.push(parseScheme(currentElement)); - } - break; - - case "InbandEventStream": - if (children.inbandEventStreams === undefined) { - children.inbandEventStreams = []; - } - children.inbandEventStreams.push(parseScheme(currentElement)); - break; - - case "Label": { - const label = currentElement.textContent; - - if (label !== null && label !== undefined) { - children.label = label; - } - break; - } - - case "Representation": { - const [representation, representationWarnings] = - createRepresentationIntermediateRepresentation(currentElement); - children.representations.push(representation); - if (representationWarnings.length > 0) { - warnings = warnings.concat(representationWarnings); - } - break; - } - - case "Role": - if (isNullOrUndefined(children.roles)) { - children.roles = [parseScheme(currentElement)]; - } else { - children.roles.push(parseScheme(currentElement)); - } - break; - - case "SupplementalProperty": - if (isNullOrUndefined(children.supplementalProperties)) { - children.supplementalProperties = [parseScheme(currentElement)]; - } else { - children.supplementalProperties.push(parseScheme(currentElement)); - } - break; - - case "SegmentBase": { - const [segmentBase, segmentBaseWarnings] = parseSegmentBase(currentElement); - children.segmentBase = segmentBase; - if (segmentBaseWarnings.length > 0) { - warnings = warnings.concat(segmentBaseWarnings); - } - break; - } - - case "SegmentList": { - const [segmentList, segmentListWarnings] = parseSegmentList(currentElement); - children.segmentList = segmentList; - if (segmentListWarnings.length > 0) { - warnings = warnings.concat(segmentListWarnings); - } - break; - } - - case "SegmentTemplate": { - const [segmentTemplate, segmentTemplateWarnings] = - parseSegmentTemplate(currentElement); - children.segmentTemplate = segmentTemplate; - if (segmentTemplateWarnings.length > 0) { - warnings = warnings.concat(segmentTemplateWarnings); - } - break; - } - - case "ContentProtection": { - const [contentProtection, contentProtectionWarnings] = - parseContentProtection(currentElement); - if (contentProtectionWarnings.length > 0) { - warnings = warnings.concat(contentProtectionWarnings); - } - if (contentProtection !== undefined) { - contentProtections.push(contentProtection); - } - break; - } - - // case "Rating": - // children.rating = currentElement; - // break; - - // case "Viewpoint": - // children.viewpoint = currentElement; - // break; - } - } - } - if (contentProtections.length > 0) { - children.contentProtections = contentProtections; - } - return [children, warnings]; -} - -/** - * Parse every attributes from an AdaptationSet root element into a simple JS - * object. - * @param {Element} root - The AdaptationSet root element. - * @returns {Array.} - */ -function parseAdaptationSetAttributes( - root: Element, -): [IAdaptationSetAttributes, Error[]] { - const parsedAdaptation: IAdaptationSetAttributes = {}; - const warnings: Error[] = []; - const parseValue = ValueParser(parsedAdaptation, warnings); - - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - - switch (attribute.name) { - case "id": - parsedAdaptation.id = attribute.value; - break; - - case "group": - parseValue(attribute.value, { - asKey: "group", - parser: parseMPDInteger, - dashName: "group", - }); - break; - - case "lang": - parsedAdaptation.language = attribute.value; - break; - - case "contentType": - parsedAdaptation.contentType = attribute.value; - break; - - case "par": - parsedAdaptation.par = attribute.value; - break; - - case "minBandwidth": - parseValue(attribute.value, { - asKey: "minBitrate", - parser: parseMPDInteger, - dashName: "minBandwidth", - }); - break; - - case "maxBandwidth": - parseValue(attribute.value, { - asKey: "maxBitrate", - parser: parseMPDInteger, - dashName: "maxBandwidth", - }); - break; - - case "minWidth": - parseValue(attribute.value, { - asKey: "minWidth", - parser: parseMPDInteger, - dashName: "minWidth", - }); - break; - - case "maxWidth": - parseValue(attribute.value, { - asKey: "maxWidth", - parser: parseMPDInteger, - dashName: "maxWidth", - }); - break; - - case "minHeight": - parseValue(attribute.value, { - asKey: "minHeight", - parser: parseMPDInteger, - dashName: "minHeight", - }); - break; - - case "maxHeight": - parseValue(attribute.value, { - asKey: "maxHeight", - parser: parseMPDInteger, - dashName: "maxHeight", - }); - break; - - case "minFrameRate": - parseValue(attribute.value, { - asKey: "minFrameRate", - parser: parseMaybeDividedNumber, - dashName: "minFrameRate", - }); - break; - - case "maxFrameRate": - parseValue(attribute.value, { - asKey: "maxFrameRate", - parser: parseMaybeDividedNumber, - dashName: "maxFrameRate", - }); - break; - - case "selectionPriority": - parseValue(attribute.value, { - asKey: "selectionPriority", - parser: parseMPDInteger, - dashName: "selectionPriority", - }); - break; - - case "segmentAlignment": - parseValue(attribute.value, { - asKey: "segmentAlignment", - parser: parseIntOrBoolean, - dashName: "segmentAlignment", - }); - break; - - case "subsegmentAlignment": - parseValue(attribute.value, { - asKey: "subsegmentAlignment", - parser: parseIntOrBoolean, - dashName: "subsegmentAlignment", - }); - break; - - case "bitstreamSwitching": - parseValue(attribute.value, { - asKey: "bitstreamSwitching", - parser: parseBoolean, - dashName: "bitstreamSwitching", - }); - break; - - case "audioSamplingRate": - parsedAdaptation.audioSamplingRate = attribute.value; - break; - - case "codecs": - parsedAdaptation.codecs = attribute.value; - break; - - case "scte214:supplementalCodecs": - parsedAdaptation.supplementalCodecs = attribute.value; - break; - - case "codingDependency": - parseValue(attribute.value, { - asKey: "codingDependency", - parser: parseBoolean, - dashName: "codingDependency", - }); - break; - - case "frameRate": - parseValue(attribute.value, { - asKey: "frameRate", - parser: parseMaybeDividedNumber, - dashName: "frameRate", - }); - break; - - case "height": - parseValue(attribute.value, { - asKey: "height", - parser: parseMPDInteger, - dashName: "height", - }); - break; - - case "maxPlayoutRate": - parseValue(attribute.value, { - asKey: "maxPlayoutRate", - parser: parseMPDFloat, - dashName: "maxPlayoutRate", - }); - break; - - case "maximumSAPPeriod": - parseValue(attribute.value, { - asKey: "maximumSAPPeriod", - parser: parseMPDFloat, - dashName: "maximumSAPPeriod", - }); - break; - - case "mimeType": - parsedAdaptation.mimeType = attribute.value; - break; - - case "profiles": - parsedAdaptation.profiles = attribute.value; - break; - - case "segmentProfiles": - parsedAdaptation.segmentProfiles = attribute.value; - break; - - case "width": - parseValue(attribute.value, { - asKey: "width", - parser: parseMPDInteger, - dashName: "width", - }); - break; - - case "availabilityTimeOffset": - parseValue(attribute.value, { - asKey: "availabilityTimeOffset", - parser: parseMPDFloat, - dashName: "availabilityTimeOffset", - }); - break; - - case "availabilityTimeComplete": - parseValue(attribute.value, { - asKey: "availabilityTimeComplete", - parser: parseBoolean, - dashName: "availabilityTimeComplete", - }); - break; - } - } - - return [parsedAdaptation, warnings]; -} - -/** - * Parse an AdaptationSet element into an AdaptationSet intermediate - * representation. - * @param {Element} adaptationSetElement - The AdaptationSet root element. - * @returns {Array.} - */ -export function createAdaptationSetIntermediateRepresentation( - adaptationSetElement: Element, -): [IAdaptationSetIntermediateRepresentation, Error[]] { - const childNodes = adaptationSetElement.childNodes; - const [children, childrenWarnings] = parseAdaptationSetChildren(childNodes); - const [attributes, attrsWarnings] = parseAdaptationSetAttributes(adaptationSetElement); - const warnings = childrenWarnings.concat(attrsWarnings); - return [{ children, attributes }, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/BaseURL.ts b/src/parsers/manifest/dash/native-parser/node_parsers/BaseURL.ts deleted file mode 100644 index c7eb5068f4..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/BaseURL.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { IBaseUrlIntermediateRepresentation } from "../../node_parser_types"; - -/** - * Parse an BaseURL element into an BaseURL intermediate - * representation. - * @param {Element} root - The BaseURL root element. - * @returns {Array.} - */ -export default function parseBaseURL( - root: Element, -): [IBaseUrlIntermediateRepresentation | undefined, Error[]] { - const value = root.textContent; - const warnings: Error[] = []; - if (value === null || value.length === 0) { - return [undefined, warnings]; - } - return [{ value }, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/ContentComponent.ts b/src/parsers/manifest/dash/native-parser/node_parsers/ContentComponent.ts deleted file mode 100644 index 4baa71672a..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/ContentComponent.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { IContentComponentAttributes } from "../../node_parser_types"; - -/** - * Parse a "ContentComponent" Element in a DASH MPD. - * @param {Element} root - * @returns {Object} - */ -export default function parseContentComponent( - root: Element, -): IContentComponentAttributes { - const ret: IContentComponentAttributes = {}; - - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - - switch (attribute.name) { - case "id": - ret.id = attribute.value; - break; - case "lang": - ret.language = attribute.value; - break; - case "contentType": - ret.contentType = attribute.value; - break; - case "par": - ret.par = attribute.value; - break; - } - } - - return ret; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/ContentProtection.ts b/src/parsers/manifest/dash/native-parser/node_parsers/ContentProtection.ts deleted file mode 100644 index 996706d73b..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/ContentProtection.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import log from "../../../../../log"; -import { hexToBytes } from "../../../../../utils/string_parsing"; -import type { - IContentProtectionAttributes, - IContentProtectionChildren, - IContentProtectionIntermediateRepresentation, -} from "../../node_parser_types"; -import { parseBase64 } from "./utils"; - -/** - * @param {NodeList} contentProtectionChildren - * @Returns {Object} - */ -function parseContentProtectionChildren( - contentProtectionChildren: NodeList, -): [IContentProtectionChildren, Error[]] { - const warnings: Error[] = []; - const cencPssh: Uint8Array[] = []; - for (let i = 0; i < contentProtectionChildren.length; i++) { - if (contentProtectionChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentElement = contentProtectionChildren[i] as Element; - if (currentElement.nodeName === "cenc:pssh") { - const content = currentElement.textContent; - if (content !== null && content.length > 0) { - const [toUint8Array, error] = parseBase64(content, "cenc:pssh"); - if (error !== null) { - log.warn(error.message); - warnings.push(error); - } - if (toUint8Array !== null) { - cencPssh.push(toUint8Array); - } - } - } - } - } - return [{ cencPssh }, warnings]; -} - -/** - * @param {Element} root - * @returns {Object} - */ -function parseContentProtectionAttributes(root: Element): IContentProtectionAttributes { - const ret: IContentProtectionAttributes = {}; - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - - switch (attribute.name) { - case "schemeIdUri": - ret.schemeIdUri = attribute.value; - break; - case "value": - ret.value = attribute.value; - break; - case "cenc:default_KID": - ret.keyId = hexToBytes(attribute.value.replace(/-/g, "")); - break; - case "ref": - ret.ref = attribute.value; - break; - case "refId": - ret.refId = attribute.value; - break; - } - } - - return ret; -} - -/** - * @param {Element} contentProtectionElement - * @returns {Object} - */ -export default function parseContentProtection( - contentProtectionElement: Element, -): [IContentProtectionIntermediateRepresentation, Error[]] { - const [children, childrenWarnings] = parseContentProtectionChildren( - contentProtectionElement.childNodes, - ); - const attributes = parseContentProtectionAttributes(contentProtectionElement); - return [{ children, attributes }, childrenWarnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/EventStream.ts b/src/parsers/manifest/dash/native-parser/node_parsers/EventStream.ts deleted file mode 100644 index 33fbc3241d..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/EventStream.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - IEventStreamEventIntermediateRepresentation, - IEventStreamIntermediateRepresentation, -} from "../../node_parser_types"; -import { parseMPDInteger, ValueParser } from "./utils"; - -/** - * Parse the EventStream node to extract Event nodes and their - * content. - * @param {Element} element - * @returns {Array} - */ -export default function parseEventStream( - element: Element, -): [IEventStreamIntermediateRepresentation, Error[]] { - const eventStreamIR: IEventStreamIntermediateRepresentation = { - children: { events: [] }, - attributes: {}, - }; - let warnings: Error[] = []; - - // 1 - Parse attributes - const parseValue = ValueParser(eventStreamIR.attributes, warnings); - for (let i = 0; i < element.attributes.length; i++) { - const attr = element.attributes[i]; - switch (attr.name) { - case "schemeIdUri": - eventStreamIR.attributes.schemeIdUri = attr.value; - break; - - case "timescale": - parseValue(attr.value, { - asKey: "timescale", - parser: parseMPDInteger, - dashName: "timescale", - }); - break; - - case "value": - eventStreamIR.attributes.value = attr.value; - break; - } - } - - for (let i = 0; i < element.childNodes.length; i++) { - if (element.childNodes[i].nodeType === Node.ELEMENT_NODE) { - const currentElement = element.childNodes[i] as Element; - - switch (currentElement.nodeName) { - case "Event": { - const [event, eventWarnings] = parseEvent(currentElement); - eventStreamIR.children.events.push(event); - if (eventWarnings.length > 0) { - warnings = warnings.concat(eventWarnings); - } - break; - } - } - } - } - - return [eventStreamIR, warnings]; -} - -/** - * Parse `Event` Element, as found in EventStream nodes. - * @param {Element} element - * @returns {Array} - */ -function parseEvent( - element: Element, -): [IEventStreamEventIntermediateRepresentation, Error[]] { - const eventIR: IEventStreamEventIntermediateRepresentation = { - eventStreamData: element, - }; - const warnings: Error[] = []; - - // 1 - Parse attributes - const parseValue = ValueParser(eventIR, warnings); - for (let i = 0; i < element.attributes.length; i++) { - const attr = element.attributes[i]; - switch (attr.name) { - case "presentationTime": - parseValue(attr.value, { - asKey: "presentationTime", - parser: parseMPDInteger, - dashName: "presentationTime", - }); - break; - case "duration": - parseValue(attr.value, { - asKey: "duration", - parser: parseMPDInteger, - dashName: "duration", - }); - break; - case "id": - eventIR.id = attr.value; - break; - } - } - return [eventIR, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/Initialization.ts b/src/parsers/manifest/dash/native-parser/node_parsers/Initialization.ts deleted file mode 100644 index a5dbd418ce..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/Initialization.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { IInitializationAttributes } from "../../node_parser_types"; -import { parseByteRange, ValueParser } from "./utils"; - -/** - * @param {Element} root - * @returns {Array.} - */ -export default function parseInitialization( - root: Element, -): [IInitializationAttributes, Error[]] { - const parsedInitialization: IInitializationAttributes = {}; - const warnings: Error[] = []; - const parseValue = ValueParser(parsedInitialization, warnings); - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - switch (attribute.name) { - case "range": - parseValue(attribute.value, { - asKey: "range", - parser: parseByteRange, - dashName: "range", - }); - break; - - case "sourceURL": - parsedInitialization.media = attribute.value; - break; - } - } - return [parsedInitialization, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/MPD.ts b/src/parsers/manifest/dash/native-parser/node_parsers/MPD.ts deleted file mode 100644 index e51eaf1a75..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/MPD.ts +++ /dev/null @@ -1,202 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - IBaseUrlIntermediateRepresentation, - IContentProtectionIntermediateRepresentation, - IMPDAttributes, - IMPDChildren, - IMPDIntermediateRepresentation, - IPeriodIntermediateRepresentation, - IScheme, -} from "../../node_parser_types"; -import parseBaseURL from "./BaseURL"; -import parseContentProtection from "./ContentProtection"; -import { createPeriodIntermediateRepresentation } from "./Period"; -import { parseDateTime, parseDuration, parseScheme, ValueParser } from "./utils"; - -/** - * Parse children of the MPD's root into a simple object. - * @param {NodeList} mpdChildren - * @returns {Array.} - */ -function parseMPDChildren(mpdChildren: NodeList): [IMPDChildren, Error[]] { - const baseURLs: IBaseUrlIntermediateRepresentation[] = []; - const locations: string[] = []; - const periods: IPeriodIntermediateRepresentation[] = []; - const utcTimings: IScheme[] = []; - const contentProtections: IContentProtectionIntermediateRepresentation[] = []; - - let warnings: Error[] = []; - for (let i = 0; i < mpdChildren.length; i++) { - if (mpdChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentNode = mpdChildren[i] as Element; - switch (currentNode.nodeName) { - case "BaseURL": { - const [baseURLObj, baseURLWarnings] = parseBaseURL(currentNode); - if (baseURLObj !== undefined) { - baseURLs.push(baseURLObj); - } - warnings = warnings.concat(baseURLWarnings); - break; - } - - case "Location": - locations.push(currentNode.textContent === null ? "" : currentNode.textContent); - break; - - case "Period": { - const [period, periodWarnings] = - createPeriodIntermediateRepresentation(currentNode); - periods.push(period); - warnings = warnings.concat(periodWarnings); - break; - } - - case "UTCTiming": { - const utcTiming = parseScheme(currentNode); - utcTimings.push(utcTiming); - break; - } - - case "ContentProtection": { - const [contentProtection, contentProtectionWarnings] = - parseContentProtection(currentNode); - if (contentProtectionWarnings.length > 0) { - warnings = warnings.concat(contentProtectionWarnings); - } - if (contentProtection !== undefined) { - contentProtections.push(contentProtection); - } - break; - } - } - } - } - - return [{ baseURLs, locations, periods, utcTimings, contentProtections }, warnings]; -} - -/** - * @param {Element} root - * @returns {Array.} - */ -function parseMPDAttributes(root: Element): [IMPDAttributes, Error[]] { - const res: IMPDAttributes = {}; - const warnings: Error[] = []; - const parseValue = ValueParser(res, warnings); - - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - - switch (attribute.name) { - case "id": - res.id = attribute.value; - break; - case "profiles": - res.profiles = attribute.value; - break; - case "type": - res.type = attribute.value; - break; - - case "availabilityStartTime": - parseValue(attribute.value, { - asKey: "availabilityStartTime", - parser: parseDateTime, - dashName: "availabilityStartTime", - }); - break; - case "availabilityEndTime": - parseValue(attribute.value, { - asKey: "availabilityEndTime", - parser: parseDateTime, - dashName: "availabilityEndTime", - }); - break; - case "publishTime": - parseValue(attribute.value, { - asKey: "publishTime", - parser: parseDateTime, - dashName: "publishTime", - }); - break; - case "mediaPresentationDuration": - parseValue(attribute.value, { - asKey: "duration", - parser: parseDuration, - dashName: "mediaPresentationDuration", - }); - break; - case "minimumUpdatePeriod": - parseValue(attribute.value, { - asKey: "minimumUpdatePeriod", - parser: parseDuration, - dashName: "minimumUpdatePeriod", - }); - break; - case "minBufferTime": - parseValue(attribute.value, { - asKey: "minBufferTime", - parser: parseDuration, - dashName: "minBufferTime", - }); - break; - case "timeShiftBufferDepth": - parseValue(attribute.value, { - asKey: "timeShiftBufferDepth", - parser: parseDuration, - dashName: "timeShiftBufferDepth", - }); - break; - case "suggestedPresentationDelay": - parseValue(attribute.value, { - asKey: "suggestedPresentationDelay", - parser: parseDuration, - dashName: "suggestedPresentationDelay", - }); - break; - case "maxSegmentDuration": - parseValue(attribute.value, { - asKey: "maxSegmentDuration", - parser: parseDuration, - dashName: "maxSegmentDuration", - }); - break; - case "maxSubsegmentDuration": - parseValue(attribute.value, { - asKey: "maxSubsegmentDuration", - parser: parseDuration, - dashName: "maxSubsegmentDuration", - }); - break; - } - } - return [res, warnings]; -} - -/** - * @param {Element} root - * @returns {Array.} - */ -export function createMPDIntermediateRepresentation( - root: Element, -): [IMPDIntermediateRepresentation, Error[]] { - const [children, childrenWarnings] = parseMPDChildren(root.childNodes); - const [attributes, attrsWarnings] = parseMPDAttributes(root); - const warnings = childrenWarnings.concat(attrsWarnings); - return [{ children, attributes }, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/Period.ts b/src/parsers/manifest/dash/native-parser/node_parsers/Period.ts deleted file mode 100644 index 70f539f989..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/Period.ts +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - IAdaptationSetIntermediateRepresentation, - IBaseUrlIntermediateRepresentation, - IContentProtectionIntermediateRepresentation, - IPeriodAttributes, - IPeriodChildren, - IPeriodIntermediateRepresentation, - ISegmentTemplateIntermediateRepresentation, -} from "../../node_parser_types"; -import { createAdaptationSetIntermediateRepresentation } from "./AdaptationSet"; -import parseBaseURL from "./BaseURL"; -import parseContentProtection from "./ContentProtection"; -import parseEventStream from "./EventStream"; -import parseSegmentTemplate from "./SegmentTemplate"; -import { parseBoolean, parseDuration, ValueParser } from "./utils"; - -/** - * @param {NodeList} periodChildren - * @returns {Array} - */ -function parsePeriodChildren(periodChildren: NodeList): [IPeriodChildren, Error[]] { - const baseURLs: IBaseUrlIntermediateRepresentation[] = []; - const adaptations: IAdaptationSetIntermediateRepresentation[] = []; - let segmentTemplate: ISegmentTemplateIntermediateRepresentation | undefined; - const contentProtections: IContentProtectionIntermediateRepresentation[] = []; - - let warnings: Error[] = []; - const eventStreams = []; - for (let i = 0; i < periodChildren.length; i++) { - if (periodChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentElement = periodChildren[i] as Element; - - switch (currentElement.nodeName) { - case "BaseURL": { - const [baseURLObj, baseURLWarnings] = parseBaseURL(currentElement); - if (baseURLObj !== undefined) { - baseURLs.push(baseURLObj); - } - warnings = warnings.concat(baseURLWarnings); - break; - } - - case "AdaptationSet": { - const [adaptation, adaptationWarnings] = - createAdaptationSetIntermediateRepresentation(currentElement); - adaptations.push(adaptation); - warnings = warnings.concat(adaptationWarnings); - break; - } - - case "EventStream": { - const [eventStream, eventStreamWarnings] = parseEventStream(currentElement); - eventStreams.push(eventStream); - warnings = warnings.concat(eventStreamWarnings); - break; - } - - case "SegmentTemplate": { - const [parsedSegmentTemplate, segmentTemplateWarnings] = - parseSegmentTemplate(currentElement); - segmentTemplate = parsedSegmentTemplate; - if (segmentTemplateWarnings.length > 0) { - warnings = warnings.concat(segmentTemplateWarnings); - } - break; - } - - case "ContentProtection": { - const [contentProtection, contentProtectionWarnings] = - parseContentProtection(currentElement); - if (contentProtectionWarnings.length > 0) { - warnings = warnings.concat(contentProtectionWarnings); - } - if (contentProtection !== undefined) { - contentProtections.push(contentProtection); - } - break; - } - } - } - } - - return [ - { baseURLs, adaptations, eventStreams, segmentTemplate, contentProtections }, - warnings, - ]; -} - -/** - * @param {Element} periodElement - * @returns {Array} - */ -function parsePeriodAttributes(periodElement: Element): [IPeriodAttributes, Error[]] { - const res: IPeriodAttributes = {}; - const warnings: Error[] = []; - const parseValue = ValueParser(res, warnings); - for (let i = 0; i < periodElement.attributes.length; i++) { - const attr = periodElement.attributes[i]; - - switch (attr.name) { - case "id": - res.id = attr.value; - break; - - case "start": - parseValue(attr.value, { - asKey: "start", - parser: parseDuration, - dashName: "start", - }); - break; - - case "duration": - parseValue(attr.value, { - asKey: "duration", - parser: parseDuration, - dashName: "duration", - }); - break; - - case "bitstreamSwitching": - parseValue(attr.value, { - asKey: "bitstreamSwitching", - parser: parseBoolean, - dashName: "bitstreamSwitching", - }); - break; - - case "xlink:href": - res.xlinkHref = attr.value; - break; - - case "xlink:actuate": - res.xlinkActuate = attr.value; - break; - } - } - return [res, warnings]; -} - -/** - * @param {Element} periodElement - * @returns {Array} - */ -export function createPeriodIntermediateRepresentation( - periodElement: Element, -): [IPeriodIntermediateRepresentation, Error[]] { - const [children, childrenWarnings] = parsePeriodChildren(periodElement.childNodes); - const [attributes, attrsWarnings] = parsePeriodAttributes(periodElement); - const warnings = childrenWarnings.concat(attrsWarnings); - return [{ children, attributes }, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/Representation.ts b/src/parsers/manifest/dash/native-parser/node_parsers/Representation.ts deleted file mode 100644 index 8a86659dd1..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/Representation.ts +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import isNullOrUndefined from "../../../../../utils/is_null_or_undefined"; -import type { - IRepresentationAttributes, - IRepresentationChildren, - IRepresentationIntermediateRepresentation, -} from "../../node_parser_types"; -import parseBaseURL from "./BaseURL"; -import parseContentProtection from "./ContentProtection"; -import parseSegmentBase from "./SegmentBase"; -import parseSegmentList from "./SegmentList"; -import parseSegmentTemplate from "./SegmentTemplate"; -import { - MPDError, - parseBoolean, - parseMaybeDividedNumber, - parseMPDFloat, - parseMPDInteger, - parseScheme, - ValueParser, -} from "./utils"; - -/** - * @param {NodeList} representationChildren - * @returns {Object} - */ -function parseRepresentationChildren( - representationChildren: NodeList, -): [IRepresentationChildren, Error[]] { - const children: IRepresentationChildren = { - baseURLs: [], - }; - const contentProtections = []; - - let warnings: Error[] = []; - for (let i = 0; i < representationChildren.length; i++) { - if (representationChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentElement = representationChildren[i] as Element; - - switch (currentElement.nodeName) { - case "BaseURL": { - const [baseURLObj, baseURLWarnings] = parseBaseURL(currentElement); - if (baseURLObj !== undefined) { - children.baseURLs.push(baseURLObj); - } - warnings = warnings.concat(baseURLWarnings); - break; - } - case "InbandEventStream": - if (children.inbandEventStreams === undefined) { - children.inbandEventStreams = []; - } - children.inbandEventStreams.push(parseScheme(currentElement)); - break; - case "SegmentBase": { - const [segmentBase, segmentBaseWarnings] = parseSegmentBase(currentElement); - children.segmentBase = segmentBase; - if (segmentBaseWarnings.length > 0) { - warnings = warnings.concat(segmentBaseWarnings); - } - break; - } - case "SegmentList": { - const [segmentList, segmentListWarnings] = parseSegmentList(currentElement); - warnings = warnings.concat(segmentListWarnings); - children.segmentList = segmentList; - break; - } - case "SegmentTemplate": { - const [segmentTemplate, segmentTemplateWarnings] = - parseSegmentTemplate(currentElement); - warnings = warnings.concat(segmentTemplateWarnings); - children.segmentTemplate = segmentTemplate; - break; - } - - case "ContentProtection": { - const [contentProtection, contentProtectionWarnings] = - parseContentProtection(currentElement); - if (contentProtectionWarnings.length > 0) { - warnings = warnings.concat(contentProtectionWarnings); - } - if (contentProtection !== undefined) { - contentProtections.push(contentProtection); - } - break; - } - case "SupplementalProperty": - if (isNullOrUndefined(children.supplementalProperties)) { - children.supplementalProperties = [parseScheme(currentElement)]; - } else { - children.supplementalProperties.push(parseScheme(currentElement)); - } - break; - } - } - } - if (contentProtections.length > 0) { - children.contentProtections = contentProtections; - } - return [children, warnings]; -} - -/** - * @param {Element} representationElement - * @returns {Array} - */ -function parseRepresentationAttributes( - representationElement: Element, -): [IRepresentationAttributes, Error[]] { - const attributes: IRepresentationAttributes = {}; - const warnings: Error[] = []; - const parseValue = ValueParser(attributes, warnings); - for (let i = 0; i < representationElement.attributes.length; i++) { - const attr = representationElement.attributes[i]; - - switch (attr.name) { - case "audioSamplingRate": - attributes.audioSamplingRate = attr.value; - break; - - case "bandwidth": - parseValue(attr.value, { - asKey: "bitrate", - parser: parseMPDInteger, - dashName: "bandwidth", - }); - break; - - case "codecs": - attributes.codecs = attr.value; - break; - - case "codingDependency": - parseValue(attr.value, { - asKey: "codingDependency", - parser: parseBoolean, - dashName: "codingDependency", - }); - break; - - case "frameRate": - parseValue(attr.value, { - asKey: "frameRate", - parser: parseMaybeDividedNumber, - dashName: "frameRate", - }); - break; - - case "height": - parseValue(attr.value, { - asKey: "height", - parser: parseMPDInteger, - dashName: "height", - }); - break; - - case "id": - attributes.id = attr.value; - break; - - case "maxPlayoutRate": - parseValue(attr.value, { - asKey: "maxPlayoutRate", - parser: parseMPDFloat, - dashName: "maxPlayoutRate", - }); - break; - - case "maximumSAPPeriod": - parseValue(attr.value, { - asKey: "maximumSAPPeriod", - parser: parseMPDFloat, - dashName: "maximumSAPPeriod", - }); - break; - - case "mimeType": - attributes.mimeType = attr.value; - break; - - case "profiles": - attributes.profiles = attr.value; - break; - - case "qualityRanking": - parseValue(attr.value, { - asKey: "qualityRanking", - parser: parseMPDInteger, - dashName: "qualityRanking", - }); - break; - - case "scte214:supplementalCodecs": - attributes.supplementalCodecs = attr.value; - break; - - case "segmentProfiles": - attributes.segmentProfiles = attr.value; - break; - - case "width": - parseValue(attr.value, { - asKey: "width", - parser: parseMPDInteger, - dashName: "width", - }); - break; - - case "availabilityTimeOffset": - parseValue(attr.value, { - asKey: "availabilityTimeOffset", - parser: parseMPDFloat, - dashName: "availabilityTimeOffset", - }); - break; - - case "availabilityTimeComplete": - parseValue(attr.value, { - asKey: "availabilityTimeComplete", - parser: parseBoolean, - dashName: "availabilityTimeComplete", - }); - break; - } - } - if (attributes.bitrate === undefined) { - warnings.push(new MPDError("No bitrate found on a Representation")); - } - return [attributes, warnings]; -} - -/** - * @param {Element} representationElement - * @returns {Array} - */ -export function createRepresentationIntermediateRepresentation( - representationElement: Element, -): [IRepresentationIntermediateRepresentation, Error[]] { - const [children, childrenWarnings] = parseRepresentationChildren( - representationElement.childNodes, - ); - const [attributes, attrsWarnings] = - parseRepresentationAttributes(representationElement); - const warnings = childrenWarnings.concat(attrsWarnings); - return [{ children, attributes }, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentBase.ts b/src/parsers/manifest/dash/native-parser/node_parsers/SegmentBase.ts deleted file mode 100644 index ce9fd102bd..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentBase.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ISegmentBaseIntermediateRepresentation } from "../../node_parser_types"; -import parseInitialization from "./Initialization"; -import { - parseBoolean, - parseByteRange, - parseMPDFloat, - parseMPDInteger, - ValueParser, -} from "./utils"; - -/** - * Parse a SegmentBase element into a SegmentBase intermediate representation. - * @param {Element} root - The SegmentBase root element. - * @returns {Array} - */ -export default function parseSegmentBase( - root: Element, -): [ISegmentBaseIntermediateRepresentation, Error[]] { - const attributes: ISegmentBaseIntermediateRepresentation = {}; - - let warnings: Error[] = []; - const parseValue = ValueParser(attributes, warnings); - const segmentBaseChildren = root.childNodes; - for (let i = 0; i < segmentBaseChildren.length; i++) { - if (segmentBaseChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentNode = segmentBaseChildren[i] as Element; - if (currentNode.nodeName === "Initialization") { - const [initialization, initializationWarnings] = parseInitialization(currentNode); - attributes.initialization = initialization; - warnings = warnings.concat(initializationWarnings); - } - } - } - - for (let i = 0; i < root.attributes.length; i++) { - const attr = root.attributes[i]; - switch (attr.name) { - case "timescale": - parseValue(attr.value, { - asKey: "timescale", - parser: parseMPDInteger, - dashName: "timescale", - }); - break; - - case "presentationTimeOffset": - parseValue(attr.value, { - asKey: "presentationTimeOffset", - parser: parseMPDFloat, - dashName: "presentationTimeOffset", - }); - break; - - case "indexRange": - parseValue(attr.value, { - asKey: "indexRange", - parser: parseByteRange, - dashName: "indexRange", - }); - break; - - case "indexRangeExact": - parseValue(attr.value, { - asKey: "indexRangeExact", - parser: parseBoolean, - dashName: "indexRangeExact", - }); - break; - - case "availabilityTimeOffset": - parseValue(attr.value, { - asKey: "availabilityTimeOffset", - parser: parseMPDFloat, - dashName: "availabilityTimeOffset", - }); - break; - - case "availabilityTimeComplete": - parseValue(attr.value, { - asKey: "availabilityTimeComplete", - parser: parseBoolean, - dashName: "availabilityTimeComplete", - }); - break; - - case "duration": - parseValue(attr.value, { - asKey: "duration", - parser: parseMPDInteger, - dashName: "duration", - }); - break; - - case "startNumber": - parseValue(attr.value, { - asKey: "startNumber", - parser: parseMPDInteger, - dashName: "startNumber", - }); - break; - - case "endNumber": - parseValue(attr.value, { - asKey: "endNumber", - parser: parseMPDInteger, - dashName: "endNumber", - }); - break; - } - } - - return [attributes, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentList.ts b/src/parsers/manifest/dash/native-parser/node_parsers/SegmentList.ts deleted file mode 100644 index 25d821ff0a..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentList.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import objectAssign from "../../../../../utils/object_assign"; -import type { - ISegmentListIntermediateRepresentation, - ISegmentUrlIntermediateRepresentation, -} from "../../node_parser_types"; -import parseSegmentBase from "./SegmentBase"; -import parseSegmentURL from "./SegmentURL"; - -/** - * @param {Element} root - * @returns {Array} - */ -export default function parseSegmentList( - root: Element, -): [ISegmentListIntermediateRepresentation, Error[]] { - const [base, baseWarnings] = parseSegmentBase(root); - let warnings: Error[] = baseWarnings; - - const list: ISegmentUrlIntermediateRepresentation[] = []; - - const segmentListChildren = root.childNodes; - for (let i = 0; i < segmentListChildren.length; i++) { - if (segmentListChildren[i].nodeType === Node.ELEMENT_NODE) { - const currentNode = segmentListChildren[i] as Element; - if (currentNode.nodeName === "SegmentURL") { - const [segmentURL, segmentURLWarnings] = parseSegmentURL(currentNode); - list.push(segmentURL); - warnings = warnings.concat(segmentURLWarnings); - } - } - } - const ret = objectAssign(base, { list }); - return [ret, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentTemplate.ts b/src/parsers/manifest/dash/native-parser/node_parsers/SegmentTemplate.ts deleted file mode 100644 index bce7570d7c..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentTemplate.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import isNullOrUndefined from "../../../../../utils/is_null_or_undefined"; -import objectAssign from "../../../../../utils/object_assign"; -import type { - ISegmentTemplateIntermediateRepresentation, - ITimelineParser, -} from "../../node_parser_types"; -import parseSegmentBase from "./SegmentBase"; -import createSegmentTimelineParser from "./SegmentTimeline"; -import { parseBoolean, parseMPDFloat, ValueParser } from "./utils"; - -/** - * Parse a SegmentTemplate element into a SegmentTemplate intermediate - * representation. - * @param {Element} root - The SegmentTemplate root element. - * @returns {Array} - */ -export default function parseSegmentTemplate( - root: Element, -): [ISegmentTemplateIntermediateRepresentation, Error[]] { - const [base, segmentBaseWarnings] = parseSegmentBase(root); - const warnings: Error[] = segmentBaseWarnings; - - let timelineParser: ITimelineParser | undefined; - - // First look for a possible SegmentTimeline - for (let i = 0; i < root.childNodes.length; i++) { - if (root.childNodes[i].nodeType === Node.ELEMENT_NODE) { - const currentNode = root.childNodes[i] as Element; - if (currentNode.nodeName === "SegmentTimeline") { - timelineParser = createSegmentTimelineParser(currentNode); - } - } - } - - const ret: ISegmentTemplateIntermediateRepresentation = objectAssign({}, base, { - duration: base.duration, - timelineParser, - }); - - const parseValue = ValueParser(ret, warnings); - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - - switch (attribute.nodeName) { - case "initialization": - if (isNullOrUndefined(ret.initialization)) { - ret.initialization = { media: attribute.value }; - } - break; - - case "index": - ret.index = attribute.value; - break; - - case "availabilityTimeOffset": - parseValue(attribute.value, { - asKey: "availabilityTimeOffset", - parser: parseMPDFloat, - dashName: "availabilityTimeOffset", - }); - break; - - case "availabilityTimeComplete": - parseValue(attribute.value, { - asKey: "availabilityTimeComplete", - parser: parseBoolean, - dashName: "availabilityTimeComplete", - }); - break; - - case "media": - ret.media = attribute.value; - break; - - case "bitstreamSwitching": - parseValue(attribute.value, { - asKey: "bitstreamSwitching", - parser: parseBoolean, - dashName: "bitstreamSwitching", - }); - break; - } - } - - return [ret, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentTimeline.ts b/src/parsers/manifest/dash/native-parser/node_parsers/SegmentTimeline.ts deleted file mode 100644 index 8aabea2b4d..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentTimeline.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ITimelineParser } from "../../node_parser_types"; - -/** - * @param {Element} root - * @returns {Function} - */ -export default function createSegmentTimelineParser(root: Element): ITimelineParser { - let result: HTMLCollection | null = null; - return function (): HTMLCollection { - if (result === null) { - const elements = root.getElementsByTagName("S"); - result = elements; - return elements; - } - return result; - }; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentURL.ts b/src/parsers/manifest/dash/native-parser/node_parsers/SegmentURL.ts deleted file mode 100644 index fe0e8a9a53..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/SegmentURL.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ISegmentUrlIntermediateRepresentation } from "../../node_parser_types"; -import { parseByteRange, ValueParser } from "./utils"; - -/** - * Parse a SegmentURL element into a SegmentURL intermediate - * representation. - * @param {Element} root - The SegmentURL root element. - * @returns {Array} - */ -export default function parseSegmentURL( - root: Element, -): [ISegmentUrlIntermediateRepresentation, Error[]] { - const parsedSegmentURL: ISegmentUrlIntermediateRepresentation = {}; - const warnings: Error[] = []; - const parseValue = ValueParser(parsedSegmentURL, warnings); - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - switch (attribute.name) { - case "media": - parsedSegmentURL.media = attribute.value; - break; - - case "indexRange": - parseValue(attribute.value, { - asKey: "indexRange", - parser: parseByteRange, - dashName: "indexRange", - }); - break; - - case "index": - parsedSegmentURL.index = attribute.value; - break; - - case "mediaRange": - parseValue(attribute.value, { - asKey: "mediaRange", - parser: parseByteRange, - dashName: "mediaRange", - }); - break; - } - } - return [parsedSegmentURL, warnings]; -} diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/AdaptationSet.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/AdaptationSet.test.ts deleted file mode 100644 index 0ae4b69295..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/AdaptationSet.test.ts +++ /dev/null @@ -1,617 +0,0 @@ -import { describe, it, expect, vi } from "vitest"; -import log from "../../../../../../log"; -import { createAdaptationSetIntermediateRepresentation } from "../AdaptationSet"; -import { MPDError } from "../utils"; - -function testBooleanAttribute(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: true }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: false }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); - - it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error1 = new MPDError( - `\`${attributeName}\` property is not a boolean value but "foobar"`, - ); - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: false }, - children: { baseURLs: [], representations: [] }, - }, - [error1], - ]); - expect(spyLog).toHaveBeenCalledTimes(1); - expect(spyLog).toHaveBeenNthCalledWith(1, error1.message); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error2 = new MPDError( - `\`${attributeName}\` property is not a boolean value but ""`, - ); - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: false }, - children: { baseURLs: [], representations: [] }, - }, - [error2], - ]); - expect(spyLog).toHaveBeenCalledTimes(2); - expect(spyLog).toHaveBeenNthCalledWith(2, error2.message); - spyLog.mockRestore(); - }); -} - -function testStringAttribute(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: "foobar" }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: "" }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); -} - -function testMaybeDividedNumber(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: 12.4 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: 0 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { - attributes: { [_variableName]: 13.5 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); - - it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error1 = new MPDError(`\`${attributeName}\` property is invalid: "toto"`); - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error1], - ]); - - expect(spyLog).toHaveBeenCalledTimes(1); - expect(spyLog).toHaveBeenNthCalledWith(1, error1.message); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error2 = new MPDError(`\`${attributeName}\` property is invalid: "PT5M"`); - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error2], - ]); - - expect(spyLog).toHaveBeenCalledTimes(2); - expect(spyLog).toHaveBeenNthCalledWith(2, error2.message); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error3 = new MPDError(`\`${attributeName}\` property is invalid: ""`); - - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error3], - ]); - - expect(spyLog).toHaveBeenCalledTimes(3); - expect(spyLog).toHaveBeenNthCalledWith(3, error3.message); - spyLog.mockRestore(); - }); -} - -function testFloatAttribute(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: 12 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: 0 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { - attributes: { [_variableName]: -50.12 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); - - it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error1 = new MPDError(`\`${attributeName}\` property is invalid: "toto"`); - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error1], - ]); - - expect(spyLog).toHaveBeenCalledTimes(1); - expect(spyLog).toHaveBeenNthCalledWith(1, error1.message); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error2 = new MPDError(`\`${attributeName}\` property is invalid: "PT5M"`); - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error2], - ]); - - expect(spyLog).toHaveBeenCalledTimes(2); - expect(spyLog).toHaveBeenNthCalledWith(2, error2.message); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error3 = new MPDError(`\`${attributeName}\` property is invalid: ""`); - - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error3], - ]); - - expect(spyLog).toHaveBeenCalledTimes(3); - expect(spyLog).toHaveBeenNthCalledWith(3, error3.message); - spyLog.mockRestore(); - }); -} - -function testIntegerAttribute(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: 12 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: 0 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { - attributes: { [_variableName]: -50 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); - - it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error1 = new MPDError( - `\`${attributeName}\` property is not an integer value but "toto"`, - ); - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error1], - ]); - - expect(spyLog).toHaveBeenCalledTimes(1); - expect(spyLog).toHaveBeenNthCalledWith(1, error1.message); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error2 = new MPDError( - `\`${attributeName}\` property is not an integer value but "PT5M"`, - ); - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error2], - ]); - - expect(spyLog).toHaveBeenCalledTimes(2); - expect(spyLog).toHaveBeenNthCalledWith(2, error2.message); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error3 = new MPDError( - `\`${attributeName}\` property is not an integer value but ""`, - ); - - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error3], - ]); - - expect(spyLog).toHaveBeenCalledTimes(3); - expect(spyLog).toHaveBeenNthCalledWith(3, error3.message); - spyLog.mockRestore(); - }); -} - -function testNumberOrBooleanAttribute( - attributeName: string, - variableName?: string, -): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse an AdaptationSet element with a correct ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: 12 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: 0 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { - attributes: { [_variableName]: -50 }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); - - it(`should correctly parse an AdaptationSet element with an incorrect ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error1 = new MPDError( - `\`${attributeName}\` property is not a boolean nor an integer but "toto"`, - ); - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error1], - ]); - - expect(spyLog).toHaveBeenCalledTimes(1); - expect(spyLog).toHaveBeenNthCalledWith(1, error1.message); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error2 = new MPDError( - `\`${attributeName}\` property is not a boolean nor an integer but "PT5M"`, - ); - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error2], - ]); - - expect(spyLog).toHaveBeenCalledTimes(2); - expect(spyLog).toHaveBeenNthCalledWith(2, error2.message); - - const element3 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - const error3 = new MPDError( - `\`${attributeName}\` property is not a boolean nor an integer but ""`, - ); - - expect(createAdaptationSetIntermediateRepresentation(element3)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [error3], - ]); - - expect(spyLog).toHaveBeenCalledTimes(3); - expect(spyLog).toHaveBeenNthCalledWith(3, error3.message); - spyLog.mockRestore(); - }); - - it(`should correctly parse an AdaptationSet element with a boolean ${attributeName} attribute`, () => { - const spyLog = vi.spyOn(log, "warn").mockImplementation(vi.fn()); - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: { [_variableName]: true }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: { [_variableName]: false }, - children: { baseURLs: [], representations: [] }, - }, - [], - ]); - - expect(spyLog).not.toHaveBeenCalled(); - spyLog.mockRestore(); - }); -} - -describe("DASH Node Parsers - AdaptationSet", () => { - it("should correctly parse an AdaptationSet element without attributes nor children", () => { - const element = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [], - ]); - }); - - testStringAttribute("audioSamplingRate"); - testBooleanAttribute("bitstreamSwitching"); - testStringAttribute("codecs"); - testBooleanAttribute("codingDependency"); - testStringAttribute("contentType"); - testMaybeDividedNumber("frameRate"); - testIntegerAttribute("group"); - testIntegerAttribute("height"); - testStringAttribute("id"); - testStringAttribute("lang", "language"); - testIntegerAttribute("maxBandwidth", "maxBitrate"); - testMaybeDividedNumber("maxFrameRate"); - testIntegerAttribute("maxHeight"); - testFloatAttribute("maxPlayoutRate"); - testIntegerAttribute("maxWidth"); - testFloatAttribute("maximumSAPPeriod"); - testStringAttribute("mimeType"); - testIntegerAttribute("minBandwidth", "minBitrate"); - testMaybeDividedNumber("minFrameRate"); - testIntegerAttribute("minHeight"); - testIntegerAttribute("minWidth"); - testStringAttribute("par"); - testStringAttribute("profiles"); - testNumberOrBooleanAttribute("segmentAlignment"); - testStringAttribute("segmentProfiles"); - testNumberOrBooleanAttribute("subsegmentAlignment"); - testIntegerAttribute("width"); - testFloatAttribute("availabilityTimeOffset"); - - it("should correctly parse an empty baseURLs", () => { - const element1 = new DOMParser().parseFromString( - "", - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - "", - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { attributes: {}, children: { baseURLs: [], representations: [] } }, - [], - ]); - }); - - it("should correctly parse a non-empty baseURLs", () => { - const element1 = new DOMParser().parseFromString( - 'a', - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: {}, - children: { baseURLs: [{ value: "a" }], representations: [] }, - }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - 'foo bar', - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element2)).toEqual([ - { - attributes: {}, - children: { baseURLs: [{ value: "foo bar" }], representations: [] }, - }, - [], - ]); - }); - - it("should correctly parse multiple non-empty baseURLs", () => { - const element1 = new DOMParser().parseFromString( - 'ab', - "text/xml", - ).childNodes[0] as Element; - expect(createAdaptationSetIntermediateRepresentation(element1)).toEqual([ - { - attributes: {}, - children: { - baseURLs: [{ value: "a" }, { value: "b" }], - representations: [], - }, - }, - [], - ]); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentComponent.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentComponent.test.ts deleted file mode 100644 index 4b5b6a58b5..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentComponent.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { describe, it, expect } from "vitest"; -import parseContentComponent from "../ContentComponent"; - -function testStringAttribute(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse a contentComponent element with a correct ${attributeName} attribute`, () => { - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseContentComponent(element1)).toEqual({ - [_variableName]: "foobar", - }); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseContentComponent(element2)).toEqual({ [_variableName]: "" }); - }); -} - -describe("DASH Node Parsers - ContentComponent", () => { - it("should correctly parse a ContentComponent element without attributes", () => { - const element = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(parseContentComponent(element)).toEqual({}); - }); - testStringAttribute("id"); - testStringAttribute("lang", "language"); - testStringAttribute("contentType"); - testStringAttribute("par"); - - it("should correctly parse a contentComponent with every attributes", () => { - const element = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseContentComponent(element)).toEqual({ - id: "foo", - language: "bar", - contentType: "audio/mp5", - par: "3/4", - }); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts deleted file mode 100644 index 740f12d3ba..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IParseContentProtection from "../ContentProtection"; - -function testStringAttribute(attributeName: string, variableName?: string): void { - const _variableName = variableName ?? attributeName; - - it(`should correctly parse a ContentProtection element with a correct ${attributeName} attribute`, async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element1 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseContentProtection(element1)).toEqual([ - { attributes: { [_variableName]: "foobar" }, children: { cencPssh: [] } }, - [], - ]); - - const element2 = new DOMParser().parseFromString( - ``, - "text/xml", - ).childNodes[0] as Element; - expect(parseContentProtection(element2)).toEqual([ - { attributes: { [_variableName]: "" }, children: { cencPssh: [] } }, - [], - ]); - }); -} - -describe("DASH Node Parsers - ContentProtection", () => { - beforeEach(() => { - vi.resetModules(); - }); - - it("should correctly parse a ContentProtection element without attributes", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(parseContentProtection(element)).toEqual([ - { attributes: {}, children: { cencPssh: [] } }, - [], - ]); - }); - - testStringAttribute("schemeIdUri"); - testStringAttribute("value"); - - it("should correctly parse a ContentProtection element with a correct cenc:default_KID attribute", async () => { - const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { - return keyId; - }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element1 = new DOMParser() - .parseFromString( - ` - - - -`, - "text/xml", - ) - .getElementsByTagName("ContentProtection")[0]; - - expect(parseContentProtection(element1)).toEqual([ - { attributes: { keyId }, children: { cencPssh: [] } }, - [], - ]); - expect(mockHexToBytes).toHaveBeenCalledTimes(1); - expect(mockHexToBytes).toHaveBeenCalledWith("deadbeef"); - }); - - it("should correctly parse a ContentProtection with every attributes", async () => { - const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { - return keyId; - }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element = new DOMParser() - .parseFromString( - ` - - - -`, - "text/xml", - ) - .getElementsByTagName("ContentProtection")[0]; - expect(parseContentProtection(element)).toEqual([ - { - attributes: { keyId, schemeIdUri: "foo", value: "bar" }, - children: { cencPssh: [] }, - }, - [], - ]); - }); - - it("should correctly parse a ContentProtection with cenc:pssh children", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element = new DOMParser() - .parseFromString( - ` - - - AABBCC - AAABAC - - -`, - "text/xml", - ) - .getElementsByTagName("ContentProtection")[0]; - expect(parseContentProtection(element)).toEqual([ - { - attributes: {}, - children: { - cencPssh: [new Uint8Array([0, 0, 65, 8]), new Uint8Array([0, 0, 1, 0])], - }, - }, - [], - ]); - }); - - it("should correctly parse a ContentProtection with both cenc:pssh children and every attributes", async () => { - const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { - return keyId; - }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element = new DOMParser() - .parseFromString( - ` - - - AABBCC - AAABAC - - -`, - "text/xml", - ) - .getElementsByTagName("ContentProtection")[0]; - expect(parseContentProtection(element)).toEqual([ - { - attributes: { keyId, schemeIdUri: "foo", value: "bar" }, - children: { - cencPssh: [new Uint8Array([0, 0, 65, 8]), new Uint8Array([0, 0, 1, 0])], - }, - }, - [], - ]); - }); - - it("should return a warning if one of the cenc:pssh is invalid base64", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; - const element = new DOMParser() - .parseFromString( - ` - - - AA!BCC - AAABAC - - -`, - "text/xml", - ) - .getElementsByTagName("ContentProtection")[0]; - const parsed = parseContentProtection(element); - expect(parsed[0]).toEqual({ - attributes: {}, - children: { cencPssh: [new Uint8Array([0, 0, 1, 0])] }, - }); - expect(parsed[1]).not.toBe(null); - expect(parsed[1]).toHaveLength(1); - expect(parsed[1][0]).toBeInstanceOf(Error); - expect(parsed[1][0].message).toEqual( - '`cenc:pssh` is not a valid base64 string: "AA!BCC"', - ); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts deleted file mode 100644 index 252e395494..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IInitialization from "../Initialization"; -import type { MPDError as IMPDError } from "../utils"; - -describe("DASH Node Parsers - Initialization", () => { - beforeEach(() => { - vi.resetModules(); - }); - - it("should correctly parse an element with no known attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; - const element1 = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(parseInitialization(element1)).toEqual([{}, []]); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseInitialization(element2)).toEqual([{}, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with a well-formed `range` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseInitialization(element1)).toEqual([{ range: [0, 1] }, []]); - - const element2 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseInitialization(element2)).toEqual([{ range: [100, 1000] }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with an incorrect `range` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - const error1 = new MPDError('`range` property has an unrecognized format "a"'); - expect(parseInitialization(element1)).toEqual([{}, [error1]]); - - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - const error2 = new MPDError('`range` property has an unrecognized format ""'); - expect(parseInitialization(element2)).toEqual([{}, [error2]]); - - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); - }); - - it("should correctly parse an element with a sourceURL attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseInitialization(element1)).toEqual([{ media: "a" }, []]); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseInitialization(element2)).toEqual([{ media: "" }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with both a sourceURL and range attributes", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseInitialization(element1)).toEqual([{ media: "a", range: [4, 10] }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts deleted file mode 100644 index 10a2a4b687..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type SegmentTimelineParser from "../SegmentTimeline"; - -describe("DASH Node parsers - SegmentTimeline", () => { - beforeEach(() => { - vi.resetModules(); - }); - - it("should return a function to parse lazily the timeline", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - - const element = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - const timeline = parseSegmentTimeline(element); - expect(typeof timeline).toEqual("function"); - expect(timeline.length).toEqual(0); - expect(mockGetElementsByTagName).not.toHaveBeenCalled(); - mockGetElementsByTagName.mockReset(); - }); - - it("should return an empty HTMLCollection if no S element is present", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - - const element = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - - const timeline = parseSegmentTimeline(element); - const res = timeline(); - expect(res).toBeInstanceOf(HTMLCollection); - expect(res).toHaveLength(0); - expect(mockGetElementsByTagName).toHaveBeenCalledTimes(1); - expect(mockGetElementsByTagName).toHaveBeenCalledWith("S"); - mockGetElementsByTagName.mockReset(); - }); - - it("should return an empty HTMLCollection for an Invalid XML", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - - const element = new DOMParser().parseFromString( - "", - "text/xml", - ).childNodes[0] as Element; - const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - - const timeline = parseSegmentTimeline(element); - const res = timeline(); - expect(res).toBeInstanceOf(HTMLCollection); - expect(res).toHaveLength(0); - expect(mockGetElementsByTagName).toHaveBeenCalledTimes(1); - expect(mockGetElementsByTagName).toHaveBeenCalledWith("S"); - mockGetElementsByTagName.mockReset(); - }); - - it("should parse S elements only when called for the first time", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - - const sElement1 = new DOMParser().parseFromString("1", "text/xml") - .childNodes[0] as Element; - const sElement2 = new DOMParser().parseFromString("2", "text/xml") - .childNodes[0] as Element; - const aElement = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - const oElement = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - const element = new DOMParser().parseFromString( - ' & ]]>', - "text/xml", - ).childNodes[0] as Element; - - element.appendChild(sElement1); - element.appendChild(aElement); - element.appendChild(oElement); - element.appendChild(sElement2); - const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - - const timeline = parseSegmentTimeline(element); - const res1 = timeline(); - expect(res1).toBeInstanceOf(HTMLCollection); - expect(res1).toHaveLength(2); - expect(mockGetElementsByTagName).toHaveBeenCalledTimes(1); - expect(mockGetElementsByTagName).toHaveBeenCalledWith("S"); - mockGetElementsByTagName.mockClear(); - const res2 = timeline(); - const res3 = timeline(); - expect(res2).toBe(res1); - expect(res2).toBeInstanceOf(HTMLCollection); - expect(res2).toHaveLength(2); - expect(res3).toBe(res1); - expect(res3).toBeInstanceOf(HTMLCollection); - expect(res3).toHaveLength(2); - expect(mockGetElementsByTagName).not.toHaveBeenCalled(); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts deleted file mode 100644 index c9d00d89c7..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type ISegmentUrl from "../SegmentURL"; -import type { MPDError as IMPDError } from "../utils"; - -describe("DASH Node Parsers - SegmentURL", () => { - beforeEach(() => { - vi.resetModules(); - }); - - it("should correctly parse an element with no known attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const element1 = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(parseSegmentURL(element1)).toEqual([{}, []]); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseSegmentURL(element2)).toEqual([{}, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with a well-formed `mediaRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSegmentURL(element1)).toEqual([{ mediaRange: [10, 100] }, []]); - - const element2 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSegmentURL(element2)).toEqual([{ mediaRange: [0, 1] }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with an incorrect `mediaRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - const error1 = new MPDError('`mediaRange` property has an unrecognized format "a"'); - expect(parseSegmentURL(element1)).toEqual([{}, [error1]]); - - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - const error2 = new MPDError('`mediaRange` property has an unrecognized format ""'); - expect(parseSegmentURL(element2)).toEqual([{}, [error2]]); - - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); - }); - - it("should correctly parse an element with a well-formed `indexRange` attribute", async () => { - const log = { - default: { warn: () => null }, - }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSegmentURL(element1)).toEqual([{ indexRange: [0, 100] }, []]); - - const element2 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseSegmentURL(element2)).toEqual([{ indexRange: [72, 47] }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with an incorrect `indexRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - const error1 = new MPDError('`indexRange` property has an unrecognized format "a"'); - expect(parseSegmentURL(element1)).toEqual([{}, [error1]]); - - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - const error2 = new MPDError('`indexRange` property has an unrecognized format ""'); - expect(parseSegmentURL(element2)).toEqual([{}, [error2]]); - - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); - }); - - it("should correctly parse an element with a media attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseSegmentURL(element1)).toEqual([{ media: "a" }, []]); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseSegmentURL(element2)).toEqual([{ media: "" }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); - - it("should correctly parse an element with a index attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const element1 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseSegmentURL(element1)).toEqual([{ index: "a" }, []]); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseSegmentURL(element2)).toEqual([{ index: "" }, []]); - - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/utils.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/utils.test.ts deleted file mode 100644 index 4146efaaa1..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/utils.test.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { - MPDError, - parseBoolean, - parseByteRange, - parseDateTime, - parseDuration, - parseIntOrBoolean, - parseScheme, -} from "../utils"; - -describe("dash parser helpers", function () { - describe("parseBoolean", () => { - it('should return true if value is "true"', () => { - expect(parseBoolean("true", "toto")).toEqual([true, null]); - }); - - it('should return false if value is "false"', () => { - expect(parseBoolean("false", "titi")).toEqual([false, null]); - }); - - it("should return false for and an error any other value", () => { - const parsed1 = parseBoolean("", "ab"); - const parsed2 = parseBoolean("foo", "ba"); - expect(parsed1[0]).toEqual(false); - expect(parsed2[0]).toEqual(false); - expect(parsed1[1]).toBeInstanceOf(MPDError); - expect(parsed2[1]).toBeInstanceOf(MPDError); - expect(parsed1[1]?.message).toEqual('`ab` property is not a boolean value but ""'); - expect(parsed2[1]?.message).toEqual( - '`ba` property is not a boolean value but "foo"', - ); - }); - }); - - describe("parseIntOrBoolean", () => { - it('should return true if value is "true"', () => { - expect(parseIntOrBoolean("true", "toto")).toEqual([true, null]); - }); - - it('should return false if value is "false"', () => { - expect(parseIntOrBoolean("false", "toto")).toEqual([false, null]); - }); - - it("should return a number for any number", () => { - expect(parseIntOrBoolean("0", "foob1")).toEqual([0, null]); - expect(parseIntOrBoolean("10", "foob2")).toEqual([10, null]); - expect(parseIntOrBoolean("072", "foob3")).toEqual([72, null]); - expect(parseIntOrBoolean("-698", "foob4")).toEqual([-698, null]); - }); - - it("should return null and an error for any other value", () => { - const parsed1 = parseIntOrBoolean("", "ab"); - const parsed2 = parseIntOrBoolean("foo", "ba"); - expect(parsed1[0]).toEqual(null); - expect(parsed2[0]).toEqual(null); - expect(parsed1[1]).toBeInstanceOf(MPDError); - expect(parsed2[1]).toBeInstanceOf(MPDError); - expect(parsed1[1]?.message).toEqual( - '`ab` property is not a boolean nor an integer but ""', - ); - expect(parsed2[1]?.message).toEqual( - '`ba` property is not a boolean nor an integer but "foo"', - ); - }); - }); - - describe("parseDateTime", () => { - it("should correctly parse a given date into a timestamp", () => { - expect(parseDateTime("1970-01-01T00:00:00Z", "a")).toEqual([0, null]); - expect(parseDateTime("1998-11-22T10:40:50Z", "b")).toEqual([911731250, null]); - expect(parseDateTime("1960-01-01T00:00:00Z", "c")).toEqual([-315619200, null]); - }); - - it("should return null and an error when the date is not recognized", () => { - const parsed1 = parseDateTime("foo bar", "ab"); - const parsed2 = parseDateTime("2047-41-52T30:40:50Z", "ba"); - expect(parsed1[0]).toEqual(null); - expect(parsed2[0]).toEqual(null); - expect(parsed1[1]).toBeInstanceOf(MPDError); - expect(parsed2[1]).toBeInstanceOf(MPDError); - expect(parsed1[1]?.message).toEqual('`ab` is in an invalid date format: "foo bar"'); - expect(parsed2[1]?.message).toEqual( - '`ba` is in an invalid date format: "2047-41-52T30:40:50Z"', - ); - }); - }); - - describe("parseDuration", () => { - it("should correctly parse duration in ISO8061 format", function () { - expect(parseDuration("P18Y9M4DT11H9M8S", "fooba")).toEqual([591361748, null]); - }); - - it("should correctly parse duration if missing the year", function () { - expect(parseDuration("P9M4DT11H9M8S", "fooba")).toEqual([23713748, null]); - }); - - it("should correctly parse duration if missing the month", function () { - expect(parseDuration("P18Y4DT11H9M8S", "fooba")).toEqual([568033748, null]); - }); - - it("should correctly parse duration if missing the day", function () { - expect(parseDuration("P18Y9MT11H9M8S", "fooba")).toEqual([591016148, null]); - }); - - it("should correctly parse duration if missing the hours", function () { - expect(parseDuration("P18Y9M4DT9M8S", "fooba")).toEqual([591322148, null]); - }); - - it("should correctly parse duration if missing the minutes", function () { - expect(parseDuration("P18Y9M4DT11H8S", "fooba")).toEqual([591361208, null]); - }); - - it("should correctly parse duration if missing the seconds", function () { - expect(parseDuration("P18Y9M4DT11H9M", "fooba")).toEqual([591361740, null]); - }); - - it("should return null and an error if duration not in ISO8061 format", function () { - const parsed1 = parseDuration("1000", "fooba"); - expect(parsed1[0]).toEqual(null); - expect(parsed1[1]).toBeInstanceOf(MPDError); - expect(parsed1[1]?.message).toEqual( - '`fooba` property has an unrecognized format "1000"', - ); - }); - it("should return 0 and an error if given an empty string", function () { - const parsed = parseDuration("", "fooba"); - expect(parsed[0]).toEqual(0); - expect(parsed[1]).toBeInstanceOf(MPDError); - expect(parsed[1]?.message).toEqual("`fooba` property is empty"); - }); - }); - - describe("parseByteRange", () => { - it("should correctly parse byte range", function () { - const parsedByteRange = parseByteRange("1-1000", "tots"); - expect(parsedByteRange[0]).not.toEqual(null); - expect(parsedByteRange[1]).toEqual(null); - expect((parsedByteRange[0] as [number, number]).length).toEqual(2); - expect((parsedByteRange[0] as [number, number])[0]).toEqual(1); - expect((parsedByteRange[0] as [number, number])[1]).toEqual(1000); - }); - it("should return null and an error if can't parse given byte range", function () { - const parsed1 = parseByteRange("main", "prop"); - expect(parsed1[0]).toEqual(null); - expect(parsed1[1]).toBeInstanceOf(MPDError); - expect(parsed1[1]?.message).toEqual( - '`prop` property has an unrecognized format "main"', - ); - }); - }); - - describe("parseScheme", () => { - it("should correctly parse an element with no known attribute", () => { - const element1 = new DOMParser().parseFromString("", "text/xml") - .childNodes[0] as Element; - expect(parseScheme(element1)).toEqual({}); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseScheme(element2)).toEqual({}); - }); - - it("should correctly parse an element with a correct schemeIdUri attribute", () => { - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseScheme(element1)).toEqual({ schemeIdUri: "foobar " }); - - const element2 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseScheme(element2)).toEqual({ schemeIdUri: "" }); - }); - - it("should correctly parse an element with a correct value attribute", () => { - const element1 = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseScheme(element1)).toEqual({ value: "foobar " }); - - const element2 = new DOMParser().parseFromString('', "text/xml") - .childNodes[0] as Element; - expect(parseScheme(element2)).toEqual({ value: "" }); - }); - - it("should correctly parse an element with both attributes", () => { - const element = new DOMParser().parseFromString( - '', - "text/xml", - ).childNodes[0] as Element; - expect(parseScheme(element)).toEqual({ - schemeIdUri: "baz", - value: "foobar ", - }); - }); - }); -}); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/utils.ts b/src/parsers/manifest/dash/native-parser/node_parsers/utils.ts deleted file mode 100644 index d44375b120..0000000000 --- a/src/parsers/manifest/dash/native-parser/node_parsers/utils.ts +++ /dev/null @@ -1,385 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// XML-Schema -// - -import log from "../../../../../log"; -import { base64ToBytes } from "../../../../../utils/base64"; -import isNonEmptyString from "../../../../../utils/is_non_empty_string"; -import type { IScheme } from "../../node_parser_types"; - -const iso8601Duration = - /^P(([\d.]*)Y)?(([\d.]*)M)?(([\d.]*)D)?T?(([\d.]*)H)?(([\d.]*)M)?(([\d.]*)S)?/; -const rangeRe = /([0-9]+)-([0-9]+)/; - -/** - * Parse MPD boolean attributes. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed boolean - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - The value to parse - * @param {string} displayName - The name of the property. Used for error - * formatting. - * @returns {Array.} - */ -function parseBoolean(val: string, displayName: string): [boolean, MPDError | null] { - if (val === "true") { - return [true, null]; - } - if (val === "false") { - return [false, null]; - } - const error = new MPDError( - `\`${displayName}\` property is not a boolean value but "${val}"`, - ); - return [false, error]; -} - -/** - * Parse MPD integer attributes. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed boolean - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - The value to parse - * @param {string} displayName - The name of the property. Used for error - * formatting. - * @returns {Array.} - */ -function parseMPDInteger( - val: string, - displayName: string, -): [number | null, MPDError | null] { - const toInt = parseInt(val, 10); - if (isNaN(toInt)) { - const error = new MPDError( - `\`${displayName}\` property is not an integer value but "${val}"`, - ); - return [null, error]; - } - return [toInt, null]; -} - -/** - * Parse MPD float attributes. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed boolean - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - The value to parse - * @param {string} displayName - The name of the property. Used for error - * formatting. - * @returns {Array.} - */ -function parseMPDFloat( - val: string, - displayName: string, -): [number | null, MPDError | null] { - if (val === "INF") { - return [Infinity, null]; - } - const toInt = parseFloat(val); - if (isNaN(toInt)) { - const error = new MPDError(`\`${displayName}\` property is invalid: "${val}"`); - return [null, error]; - } - return [toInt, null]; -} - -/** - * Parse MPD attributes which are either integer or boolean values. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed value - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - The value to parse - * @param {string} displayName - The name of the property. Used for error - * formatting. - * @returns {Array.} - */ -function parseIntOrBoolean( - val: string, - displayName: string, -): [boolean | number | null, MPDError | null] { - if (val === "true") { - return [true, null]; - } - if (val === "false") { - return [false, null]; - } - const toInt = parseInt(val, 10); - if (isNaN(toInt)) { - const error = new MPDError( - `\`${displayName}\` property is not a boolean nor an integer but "${val}"`, - ); - return [null, error]; - } - return [toInt, null]; -} - -/** - * Parse MPD date attributes. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed value - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - The value to parse - * @param {string} displayName - The name of the property. Used for error - * formatting. - * @returns {Array.} - */ -function parseDateTime( - val: string, - displayName: string, -): [number | null, MPDError | null] { - const parsed = Date.parse(val); - if (isNaN(parsed)) { - const error = new MPDError( - `\`${displayName}\` is in an invalid date format: "${val}"`, - ); - return [null, error]; - } - return [new Date(Date.parse(val)).getTime() / 1000, null]; -} - -/** - * Parse MPD ISO8601 duration attributes into seconds. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed value - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - The value to parse - * @param {string} displayName - The name of the property. Used for error - * formatting. - * @returns {Array.} - */ -function parseDuration( - val: string, - displayName: string, -): [number | null, MPDError | null] { - if (!isNonEmptyString(val)) { - const error = new MPDError(`\`${displayName}\` property is empty`); - return [0, error]; - } - - const match = iso8601Duration.exec(val) as RegExpExecArray; - if (match === null) { - const error = new MPDError( - `\`${displayName}\` property has an unrecognized format "${val}"`, - ); - return [null, error]; - } - - const duration = - parseFloat(isNonEmptyString(match[2]) ? match[2] : "0") * 365 * 24 * 60 * 60 + - parseFloat(isNonEmptyString(match[4]) ? match[4] : "0") * 30 * 24 * 60 * 60 + - parseFloat(isNonEmptyString(match[6]) ? match[6] : "0") * 24 * 60 * 60 + - parseFloat(isNonEmptyString(match[8]) ? match[8] : "0") * 60 * 60 + - parseFloat(isNonEmptyString(match[10]) ? match[10] : "0") * 60 + - parseFloat(isNonEmptyString(match[12]) ? match[12] : "0"); - return [duration, null]; -} - -/** - * Parse MPD byterange attributes into arrays of two elements: the start and - * the end. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed value - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - * @param {string} displayName - * @returns {Array. | Error | null>} - */ -function parseByteRange( - val: string, - displayName: string, -): [[number, number] | null, MPDError | null] { - const match = rangeRe.exec(val); - if (match === null) { - const error = new MPDError( - `\`${displayName}\` property has an unrecognized format "${val}"`, - ); - return [null, error]; - } else { - return [[+match[1], +match[2]], null]; - } -} - -/** - * Parse MPD base64 attribute into an Uint8Array. - * the end. - * - * The returned value is a tuple of two elements where: - * 1. the first value is the parsed value - or `null` if we could not parse - * it - * 2. the second value is a possible error encountered while parsing this - * value - set to `null` if no error was encountered. - * @param {string} val - * @param {string} displayName - * @returns {Uint8Array | Error | null>} - */ -function parseBase64( - val: string, - displayName: string, -): [Uint8Array | null, MPDError | null] { - try { - return [base64ToBytes(val), null]; - } catch (_) { - const error = new MPDError( - `\`${displayName}\` is not a valid base64 string: "${val}"`, - ); - return [null, error]; - } -} - -/** - * Some values in the MPD can be expressed as divisions of integers (e.g. frame - * rates). - * This function tries to convert it to a floating point value. - * @param {string} val - * @param {string} displayName - * @returns {Array.} - */ -function parseMaybeDividedNumber( - val: string, - displayName: string, -): [number | null, MPDError | null] { - const matches = /^(\d+)\/(\d+)$/.exec(val); - if (matches !== null) { - // No need to check, we know both are numbers - return [+matches[1] / +matches[2], null]; - } - return parseMPDFloat(val, displayName); -} - -/** - * @param {Element} root - * @returns {Object} - */ -function parseScheme(root: Element): IScheme { - let schemeIdUri: string | undefined; - let value: string | undefined; - for (let i = 0; i < root.attributes.length; i++) { - const attribute = root.attributes[i]; - - switch (attribute.name) { - case "schemeIdUri": - schemeIdUri = attribute.value; - break; - case "value": - value = attribute.value; - break; - } - } - - return { schemeIdUri, value }; -} - -/** - * Create a function to factorize the MPD parsing logic. - * @param {Object} dest - The destination object which will contain the parsed - * values. - * @param {Array.} warnings - An array which will contain every parsing - * error encountered. - * @return {Function} - */ -function ValueParser(dest: T, warnings: Error[]) { - /** - * Parse a single value and add it to the `dest` objects. - * If an error arised while parsing, add it at the end of the `warnings` array. - * @param {string} objKey - The key which will be added to the `dest` object. - * @param {string} val - The value found in the MPD which we should parse. - * @param {Function} parsingFn - The parsing function adapted for this value. - * @param {string} displayName - The name of the key as it appears in the MPD. - * This is used only in error formatting, - */ - return function ( - val: string, - { - asKey, - parser, - dashName, - }: { - asKey: keyof T; - parser: ( - value: string, - displayName: string, - ) => [T[keyof T] | null, MPDError | null]; - dashName: string; - }, - ): void { - const [parsingResult, parsingError] = parser(val, dashName); - if (parsingError !== null) { - log.warn(parsingError.message); - warnings.push(parsingError); - } - - if (parsingResult !== null) { - dest[asKey] = parsingResult; - } - }; -} - -/** - * Error arising when parsing the MPD. - * @class MPDError - * @extends Error - */ -class MPDError extends Error { - public readonly name: "MPDError"; - /** - * @param {string} message - */ - constructor(message: string) { - super(message); - // @see https://stackoverflow.com/questions/41102060/typescript-extending-error-class - Object.setPrototypeOf(this, MPDError.prototype); - - this.name = "MPDError"; - } -} - -export { - MPDError, - ValueParser, - parseBase64, - parseBoolean, - parseByteRange, - parseDateTime, - parseDuration, - parseIntOrBoolean, - parseMaybeDividedNumber, - parseMPDFloat, - parseMPDInteger, - parseScheme, -}; diff --git a/src/parsers/manifest/dash/native-parser/parse_from_document.ts b/src/parsers/manifest/dash/native-parser/parse_from_document.ts deleted file mode 100644 index ed67c41c7d..0000000000 --- a/src/parsers/manifest/dash/native-parser/parse_from_document.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright 2015 CANAL+ Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { assertUnreachable } from "../../../../utils/assert"; -import isNullOrUndefined from "../../../../utils/is_null_or_undefined"; -import type { IIrParserResponse, ILoadedXlinkData, IMPDParserArguments } from "../common"; -import parseMpdIr from "../common"; -import type { IPeriodIntermediateRepresentation } from "../node_parser_types"; -import type { IDashParserResponse, ILoadedResource } from "../parsers_types"; -import { createMPDIntermediateRepresentation } from "./node_parsers/MPD"; -import { createPeriodIntermediateRepresentation } from "./node_parsers/Period"; - -/** - * Parse MPD through the JS parser, on a `Document` instance. - * @param {Document} document - Original manifest as returned by the server - * @param {Object} args - Various parsing options and information. - * @returns {Object} - Response returned by the DASH-JS parser. - */ -export default function parseFromDocument( - document: Document, - args: IMPDParserArguments, -): IDashParserResponse { - const root = document.documentElement; - if (isNullOrUndefined(root) || root.nodeName !== "MPD") { - throw new Error("DASH Parser: document root should be MPD"); - } - - const [mpdIR, warnings] = createMPDIntermediateRepresentation(root); - const ret = parseMpdIr(mpdIR, args, warnings); - return processReturn(ret); - - /** - * Handle `parseMpdIr` return values, asking for resources if they are needed - * and pre-processing them before continuing parsing. - * - * @param {Object} initialRes - * @returns {Object} - */ - function processReturn(initialRes: IIrParserResponse): IDashParserResponse { - if (initialRes.type === "done") { - return initialRes; - } else if (initialRes.type === "needs-clock") { - return { - type: "needs-resources", - value: { - urls: [initialRes.value.url], - format: "string", - continue( - loadedClock: Array>, - ): IDashParserResponse { - if (loadedClock.length !== 1) { - throw new Error("DASH parser: wrong number of loaded ressources."); - } - const newRet = initialRes.value.continue(loadedClock[0].responseData); - return processReturn(newRet); - }, - }, - }; - } else if (initialRes.type === "needs-xlinks") { - return { - type: "needs-resources", - value: { - urls: initialRes.value.xlinksUrls, - format: "string", - continue( - loadedXlinks: Array>, - ): IDashParserResponse { - const resourceInfos: ILoadedXlinkData[] = []; - for (let i = 0; i < loadedXlinks.length; i++) { - const { - responseData: xlinkResp, - receivedTime, - sendingTime, - url, - } = loadedXlinks[i]; - if (!xlinkResp.success) { - throw xlinkResp.error; - } - const wrappedData = "" + xlinkResp.data + ""; - const dataAsXML = new DOMParser().parseFromString(wrappedData, "text/xml"); - if (isNullOrUndefined(dataAsXML) || dataAsXML.children.length === 0) { - throw new Error("DASH parser: Invalid external ressources"); - } - const periods = dataAsXML.children[0].children; - const periodsIR: IPeriodIntermediateRepresentation[] = []; - const periodsIRWarnings: Error[] = []; - for (let j = 0; j < periods.length; j++) { - if (periods[j].nodeType === Node.ELEMENT_NODE) { - const [periodIR, periodWarnings] = - createPeriodIntermediateRepresentation(periods[j]); - periodsIRWarnings.push(...periodWarnings); - periodsIR.push(periodIR); - } - } - resourceInfos.push({ - url, - receivedTime, - sendingTime, - parsed: periodsIR, - warnings: periodsIRWarnings, - }); - } - const newRet = initialRes.value.continue(resourceInfos); - return processReturn(newRet); - }, - }, - }; - } else { - assertUnreachable(initialRes); - } - } -} diff --git a/src/parsers/manifest/dash/node_parser_types.ts b/src/parsers/manifest/dash/node_parser_types.ts index 70083f2fff..eb612039ac 100644 --- a/src/parsers/manifest/dash/node_parser_types.ts +++ b/src/parsers/manifest/dash/node_parser_types.ts @@ -100,9 +100,8 @@ export interface IMPDAttributes { /** * XML namespaces linked to the `` element. * - * This property is only needed when the EventStream's `` elements are - * not parsed through the browser's DOMParser API, and thus might depend on - * parent namespaces to be parsed correctly. + * This property is needed when the EventStream's `` elements depend + * on parent namespaces to be parsed / reconstructed correctly. */ namespaces?: Array<{ key: string; value: string }>; } @@ -174,9 +173,8 @@ export interface IPeriodAttributes { /** * XML namespaces linked to the `` element. * - * This property is only needed when the EventStream's `` elements are - * not parsed through the browser's DOMParser API, and thus might depend on - * parent namespaces to be parsed correctly. + * This property is needed when the EventStream's `` elements depend + * on parent namespaces to be parsed / reconstructed correctly. */ namespaces?: Array<{ key: string; value: string }>; } @@ -411,9 +409,8 @@ export interface IEventStreamAttributes { /** * XML namespaces linked to the `` element. * - * This property is only needed when the EventStream's `` elements are - * not parsed through the browser's DOMParser API, and thus might depend on - * parent namespaces to be parsed correctly. + * This property is needed when the EventStream's `` elements depend + * on parent namespaces to be parsed / reconstructed correctly. */ namespaces?: Array<{ key: string; value: string }> | undefined; } @@ -434,7 +431,7 @@ export interface IEventStreamEventIntermediateRepresentation { * - Either as the Element's UTF-8 textual representation. * - Either as the Element's string representation. */ - eventStreamData?: Element | ArrayBuffer | string; + eventStreamData?: ArrayBuffer | string; } -export type ITimelineParser = () => ITNode[] | HTMLCollection; +export type ITimelineParser = () => ITNode[]; diff --git a/src/transports/dash/manifest_parser.ts b/src/transports/dash/manifest_parser.ts index 5b8345f743..4f72396223 100644 --- a/src/transports/dash/manifest_parser.ts +++ b/src/transports/dash/manifest_parser.ts @@ -123,13 +123,9 @@ export default function generateManifestParser( function runDefaultJsParser(): | IManifestParserResult | Promise { - if (parsers.fastJs !== null) { + if (parsers.js !== null) { const manifestStr = getManifestAsString(responseData); - const parsedManifest = parsers.fastJs(manifestStr, dashParserOpts); - return processMpdParserResponse(parsedManifest); - } else if (parsers.native !== null) { - const manifestDocument = getManifestAsDocument(responseData); - const parsedManifest = parsers.native(manifestDocument, dashParserOpts); + const parsedManifest = parsers.js(manifestStr, dashParserOpts); return processMpdParserResponse(parsedManifest); } else { throw new Error("No MPD parser is imported"); @@ -311,29 +307,6 @@ function getManifestAsString(manifestSrc: unknown): string { } } -/** - * Try to convert a Manifest from an unknown format to a `Document` format. - * Useful to exploit DOM-parsing APIs to quickly parse an XML Manifest. - * - * Throws if the format cannot be converted. - * @param {*} manifestSrc - * @returns {Document} - */ -function getManifestAsDocument(manifestSrc: unknown): Document { - if (manifestSrc instanceof ArrayBuffer) { - return new DOMParser().parseFromString( - utf8ToStr(new Uint8Array(manifestSrc)), - "text/xml", - ); - } else if (typeof manifestSrc === "string") { - return new DOMParser().parseFromString(manifestSrc, "text/xml"); - } else if (manifestSrc instanceof Document) { - return manifestSrc; - } else { - throw new Error("DASH Manifest Parser: Unrecognized Manifest format"); - } -} - /** * Try to convert a Manifest from an unknown format to an `ArrayBuffer` format. * Throws if the format cannot be converted.