@svta/cml-cmaf-ham 0.23.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +262 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +239 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,98 @@
|
|
|
1
|
+
//#region src/utils/byteRange.ts
|
|
2
|
+
/**
|
|
3
|
+
* Parses a byteRange string in either HLS format (length@offset) or DASH format (start-end)
|
|
4
|
+
* and converts it to an object with start and end properties.
|
|
5
|
+
*
|
|
6
|
+
* @param byteRangeString - String in format "length@offset" or "start-end"
|
|
7
|
+
* @returns Object with start and end properties, or undefined if input is invalid
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* parseByteRangeString("1234@0") // { start: 0, end: 1233 }
|
|
12
|
+
* parseByteRangeString("0-1233") // { start: 0, end: 1233 }
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
function parseByteRangeString(byteRangeString) {
|
|
18
|
+
if (!byteRangeString) return;
|
|
19
|
+
if (byteRangeString.includes("@")) {
|
|
20
|
+
const [lengthStr, offsetStr] = byteRangeString.split("@");
|
|
21
|
+
const length = parseInt(lengthStr, 10);
|
|
22
|
+
const offset = parseInt(offsetStr, 10);
|
|
23
|
+
if (isNaN(length) || isNaN(offset)) return;
|
|
24
|
+
return {
|
|
25
|
+
start: offset,
|
|
26
|
+
end: offset + length - 1
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (byteRangeString.includes("-")) {
|
|
30
|
+
const [startStr, endStr] = byteRangeString.split("-");
|
|
31
|
+
const start = parseInt(startStr, 10);
|
|
32
|
+
const end = parseInt(endStr, 10);
|
|
33
|
+
if (isNaN(start) || isNaN(end)) return;
|
|
34
|
+
return {
|
|
35
|
+
start,
|
|
36
|
+
end
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Converts a ByteRangeObject to HLS format string (length@offset)
|
|
42
|
+
*
|
|
43
|
+
* @param byteRange - Object with start and end properties
|
|
44
|
+
* @returns String in format "length@offset"
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* byteRangeToHlsString({ start: 0, end: 1233 }) // "1234@0"
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @alpha
|
|
52
|
+
*/
|
|
53
|
+
function byteRangeToHlsString(byteRange) {
|
|
54
|
+
if (!byteRange) return "";
|
|
55
|
+
return `${byteRange.end - byteRange.start + 1}@${byteRange.start}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Converts a ByteRangeObject to DASH format string (start-end)
|
|
59
|
+
*
|
|
60
|
+
* @param byteRange - Object with start and end properties
|
|
61
|
+
* @returns String in format "start-end"
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* byteRangeToDashString({ start: 0, end: 1233 }) // "0-1233"
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @alpha
|
|
69
|
+
*/
|
|
70
|
+
function byteRangeToDashString(byteRange) {
|
|
71
|
+
if (!byteRange) return "";
|
|
72
|
+
return `${byteRange.start}-${byteRange.end}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Converts HLS Byterange object (with length and offset) to ByteRangeObject
|
|
76
|
+
*
|
|
77
|
+
* @param byterange - Object with length and offset properties (from HLS parser)
|
|
78
|
+
* @returns Object with start and end properties
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* hlsByterangeToByteRangeObject({ length: 1234, offset: 0 }) // { start: 0, end: 1233 }
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @alpha
|
|
86
|
+
*/
|
|
87
|
+
function hlsByterangeToByteRangeObject(byterange) {
|
|
88
|
+
if (!byterange) return;
|
|
89
|
+
return {
|
|
90
|
+
start: byterange.offset,
|
|
91
|
+
end: byterange.offset + byterange.length - 1
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
1
96
|
//#region src/mapper/dash/mapDashToHam/mapSegmentBase.ts
|
|
2
97
|
/**
|
|
3
98
|
* @internal
|
|
@@ -9,12 +104,19 @@
|
|
|
9
104
|
* @returns list of ham segments
|
|
10
105
|
*/
|
|
11
106
|
function mapSegmentBase(representation, duration) {
|
|
12
|
-
|
|
13
|
-
|
|
107
|
+
let cumulativeTime = 0;
|
|
108
|
+
return representation.SegmentBase?.map((segment, index) => {
|
|
109
|
+
const startTime = cumulativeTime;
|
|
110
|
+
cumulativeTime += duration;
|
|
111
|
+
const byteRange = parseByteRangeString(segment.$.indexRange);
|
|
112
|
+
const result = {
|
|
113
|
+
id: `${representation.$.id}-segment-${index}`,
|
|
14
114
|
duration,
|
|
15
115
|
url: representation.BaseURL?.[0] ?? "",
|
|
16
|
-
|
|
116
|
+
startTime
|
|
17
117
|
};
|
|
118
|
+
if (byteRange !== void 0) result.byteRange = byteRange;
|
|
119
|
+
return result;
|
|
18
120
|
}) ?? [];
|
|
19
121
|
}
|
|
20
122
|
|
|
@@ -48,11 +150,18 @@ function calculateDuration(duration, timescale) {
|
|
|
48
150
|
*/
|
|
49
151
|
function mapSegmentList(segmentList) {
|
|
50
152
|
const segments = [];
|
|
153
|
+
let segmentIndex = 0;
|
|
154
|
+
let cumulativeTime = 0;
|
|
51
155
|
segmentList.map((segment) => {
|
|
52
156
|
if (segment.SegmentURL) return segment.SegmentURL.forEach((segmentURL) => {
|
|
157
|
+
const duration = calculateDuration(segment.$.duration, segment.$.timescale);
|
|
158
|
+
const startTime = cumulativeTime;
|
|
159
|
+
cumulativeTime += duration;
|
|
53
160
|
segments.push({
|
|
54
|
-
|
|
55
|
-
|
|
161
|
+
id: `segment-${segmentIndex++}`,
|
|
162
|
+
duration,
|
|
163
|
+
url: segmentURL.$.media ?? "",
|
|
164
|
+
startTime
|
|
56
165
|
});
|
|
57
166
|
});
|
|
58
167
|
});
|
|
@@ -124,10 +233,18 @@ function mapSegmentTemplate(representation, duration, segmentTemplate) {
|
|
|
124
233
|
const numberOfSegments = getNumberOfSegments(segmentTemplate, duration);
|
|
125
234
|
const init = +(segmentTemplate.$.startNumber ?? 0);
|
|
126
235
|
const segments = [];
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
236
|
+
let cumulativeTime = 0;
|
|
237
|
+
for (let id = init; id < numberOfSegments + init; id++) {
|
|
238
|
+
const segmentDuration = calculateDuration(segmentTemplate.$.duration, segmentTemplate.$.timescale);
|
|
239
|
+
const startTime = cumulativeTime;
|
|
240
|
+
cumulativeTime += segmentDuration;
|
|
241
|
+
segments.push({
|
|
242
|
+
id: `${representation.$.id}-segment-${id}`,
|
|
243
|
+
duration: segmentDuration,
|
|
244
|
+
url: getUrlFromTemplate(representation, segmentTemplate, id),
|
|
245
|
+
startTime
|
|
246
|
+
});
|
|
247
|
+
}
|
|
131
248
|
return segments;
|
|
132
249
|
}
|
|
133
250
|
|
|
@@ -229,8 +346,6 @@ const TEXT_SAMPLE_RATE = 1e3;
|
|
|
229
346
|
const FRAME_RATE_NUMERATOR_30 = 30;
|
|
230
347
|
const WHITE_SPACE = " ";
|
|
231
348
|
const WHITE_SPACE_ENCODED = "%20";
|
|
232
|
-
const HYPHEN_MINUS_SEPARATOR = "-";
|
|
233
|
-
const AT_SEPARATOR = "@";
|
|
234
349
|
const FRAME_RATE_SEPARATOR = "/";
|
|
235
350
|
const NUMERATOR = 0;
|
|
236
351
|
const DENOMINATOR = 1;
|
|
@@ -396,8 +511,13 @@ function getTimescale(track) {
|
|
|
396
511
|
* @alpha
|
|
397
512
|
*/
|
|
398
513
|
function encodeByteRange(track) {
|
|
399
|
-
if (track.byteRange)
|
|
400
|
-
|
|
514
|
+
if (track.initialization?.byteRange) {
|
|
515
|
+
const initByteRange = track.initialization.byteRange;
|
|
516
|
+
return `BYTERANGE:${initByteRange.end - initByteRange.start + 1}@${initByteRange.start}\n`;
|
|
517
|
+
} else if (track.segments?.at(0)?.byteRange) {
|
|
518
|
+
const firstSegmentByteRange = track.segments.at(0)?.byteRange;
|
|
519
|
+
if (firstSegmentByteRange) return `BYTERANGE:0@${firstSegmentByteRange.start - 1}\n`;
|
|
520
|
+
}
|
|
401
521
|
return "";
|
|
402
522
|
}
|
|
403
523
|
|
|
@@ -412,7 +532,7 @@ function encodeByteRange(track) {
|
|
|
412
532
|
* @alpha
|
|
413
533
|
*/
|
|
414
534
|
function getUrlInitialization(track) {
|
|
415
|
-
return track.
|
|
535
|
+
return track.initialization?.url?.replaceAll(WHITE_SPACE, WHITE_SPACE_ENCODED) ?? "";
|
|
416
536
|
}
|
|
417
537
|
|
|
418
538
|
//#endregion
|
|
@@ -441,9 +561,9 @@ function getPlaylistData(track) {
|
|
|
441
561
|
*/
|
|
442
562
|
function getSegments(segments) {
|
|
443
563
|
return segments.map((segment) => {
|
|
444
|
-
const
|
|
564
|
+
const byteRangeStr = segment.byteRange ? `#EXT-X-BYTERANGE:${byteRangeToHlsString(segment.byteRange)}\n` : "";
|
|
445
565
|
const url = segment.url.replaceAll(WHITE_SPACE, WHITE_SPACE_ENCODED);
|
|
446
|
-
return `#EXTINF:${segment.duration},\n${
|
|
566
|
+
return `#EXTINF:${segment.duration},\n${byteRangeStr}\n${url}`;
|
|
447
567
|
}).join("\n");
|
|
448
568
|
}
|
|
449
569
|
|
|
@@ -473,13 +593,19 @@ function decodeByteRange(byteRange) {
|
|
|
473
593
|
* @alpha
|
|
474
594
|
*/
|
|
475
595
|
function formatSegments(segments) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
596
|
+
let cumulativeTime = 0;
|
|
597
|
+
return segments?.map((segment, index) => {
|
|
598
|
+
const byteRange = hlsByterangeToByteRangeObject(segment?.byterange);
|
|
599
|
+
const startTime = cumulativeTime;
|
|
600
|
+
cumulativeTime += segment.duration;
|
|
601
|
+
const result = {
|
|
602
|
+
id: `segment-${index}`,
|
|
479
603
|
duration: segment.duration,
|
|
480
604
|
url: segment.uri,
|
|
481
|
-
|
|
605
|
+
startTime
|
|
482
606
|
};
|
|
607
|
+
if (byteRange !== void 0) result.byteRange = byteRange;
|
|
608
|
+
return result;
|
|
483
609
|
}) ?? [];
|
|
484
610
|
}
|
|
485
611
|
|
|
@@ -576,9 +702,13 @@ function getInitializationUrl(adaptationSet, representation) {
|
|
|
576
702
|
function mapTracks(adaptationSet, representation, segments, initializationUrl) {
|
|
577
703
|
if (!adaptationSet) throw new Error("Error: AdaptationSet is undefined");
|
|
578
704
|
const type = getContentType(adaptationSet, representation);
|
|
705
|
+
const codec = getCodec(adaptationSet, representation);
|
|
706
|
+
const mimeType = representation.$.mimeType ?? adaptationSet.$.mimeType ?? "";
|
|
579
707
|
if (type === "video") return {
|
|
708
|
+
url: "",
|
|
580
709
|
bandwidth: +(representation.$.bandwidth ?? 0),
|
|
581
|
-
codec:
|
|
710
|
+
codecs: codec ? [codec] : [],
|
|
711
|
+
mimeType,
|
|
582
712
|
duration: getTrackDuration(segments),
|
|
583
713
|
frameRate: getFrameRate(adaptationSet, representation),
|
|
584
714
|
height: +(representation.$.height ?? 0),
|
|
@@ -590,29 +720,36 @@ function mapTracks(adaptationSet, representation, segments, initializationUrl) {
|
|
|
590
720
|
segments,
|
|
591
721
|
type,
|
|
592
722
|
width: +(representation.$.width ?? 0),
|
|
593
|
-
|
|
723
|
+
initialization: { url: initializationUrl ?? "" },
|
|
724
|
+
baseUrls: []
|
|
594
725
|
};
|
|
595
726
|
else if (type === "audio") return {
|
|
727
|
+
url: "",
|
|
596
728
|
bandwidth: +(representation.$.bandwidth ?? 0),
|
|
597
729
|
channels: getChannels(adaptationSet, representation),
|
|
598
|
-
codec:
|
|
730
|
+
codecs: codec ? [codec] : [],
|
|
731
|
+
mimeType,
|
|
599
732
|
duration: getTrackDuration(segments),
|
|
600
733
|
id: representation.$.id ?? "",
|
|
601
734
|
language: getLanguage(adaptationSet),
|
|
602
735
|
sampleRate: getSampleRate(adaptationSet, representation),
|
|
603
736
|
segments,
|
|
604
737
|
type,
|
|
605
|
-
|
|
738
|
+
initialization: { url: initializationUrl ?? "" },
|
|
739
|
+
baseUrls: []
|
|
606
740
|
};
|
|
607
741
|
else return {
|
|
742
|
+
url: "",
|
|
608
743
|
bandwidth: +(representation.$.bandwidth ?? 0),
|
|
609
|
-
codec:
|
|
744
|
+
codecs: codec ? [codec] : [],
|
|
745
|
+
mimeType,
|
|
610
746
|
duration: getTrackDuration(segments),
|
|
611
747
|
id: representation.$.id ?? "",
|
|
612
748
|
language: getLanguage(adaptationSet),
|
|
613
749
|
segments,
|
|
614
750
|
type,
|
|
615
|
-
|
|
751
|
+
initialization: { url: initializationUrl ?? "" },
|
|
752
|
+
baseUrls: []
|
|
616
753
|
};
|
|
617
754
|
}
|
|
618
755
|
|
|
@@ -636,18 +773,25 @@ function mapDashToHam(dash) {
|
|
|
636
773
|
return mapTracks(adaptationSet, representation, mapSegments(adaptationSet, representation, duration), getInitializationUrl(adaptationSet, representation));
|
|
637
774
|
});
|
|
638
775
|
const group = getGroup(adaptationSet);
|
|
776
|
+
const contentType = getContentType(adaptationSet, adaptationSet.Representation[0]);
|
|
639
777
|
if (!selectionSetGroups[group]) selectionSetGroups[group] = {
|
|
640
778
|
id: group,
|
|
641
|
-
switchingSets: []
|
|
779
|
+
switchingSets: [],
|
|
780
|
+
type: contentType
|
|
642
781
|
};
|
|
643
782
|
selectionSetGroups[group].switchingSets.push({
|
|
644
783
|
id: adaptationSet.$.id ?? adaptationSet.ContentComponent?.at(0)?.$.id ?? group,
|
|
645
|
-
tracks
|
|
784
|
+
tracks,
|
|
785
|
+
baseUrls: []
|
|
646
786
|
});
|
|
647
787
|
});
|
|
648
788
|
return {
|
|
649
789
|
id: presentationId,
|
|
650
|
-
selectionSets: Object.values(selectionSetGroups)
|
|
790
|
+
selectionSets: Object.values(selectionSetGroups),
|
|
791
|
+
duration,
|
|
792
|
+
startTime: 0,
|
|
793
|
+
endTime: duration,
|
|
794
|
+
baseUrls: []
|
|
651
795
|
};
|
|
652
796
|
});
|
|
653
797
|
}
|
|
@@ -656,12 +800,13 @@ function mapDashToHam(dash) {
|
|
|
656
800
|
//#region src/mapper/dash/mapHamToDash/trackToSegmentBase.ts
|
|
657
801
|
function trackToSegmentBase(track) {
|
|
658
802
|
const segments = [];
|
|
659
|
-
if (track.segments.length > 0 && track.
|
|
803
|
+
if (track.segments.length > 0 && track.initialization.byteRange && track.segments[0].byteRange) {
|
|
660
804
|
let firstSegment = void 0;
|
|
661
|
-
const initByteRange = track.
|
|
662
|
-
const initRange =
|
|
805
|
+
const initByteRange = track.initialization.byteRange;
|
|
806
|
+
const initRange = initByteRange.end;
|
|
807
|
+
const numberFirstByteRange = track.segments[0].byteRange.start - 1;
|
|
663
808
|
firstSegment = {
|
|
664
|
-
$: { indexRange: `${initByteRange}-${
|
|
809
|
+
$: { indexRange: `${initByteRange.end}-${numberFirstByteRange}` },
|
|
665
810
|
Initialization: [{ $: { range: `0-${initRange}` } }]
|
|
666
811
|
};
|
|
667
812
|
if (firstSegment && track.type === "audio") {
|
|
@@ -672,9 +817,9 @@ function trackToSegmentBase(track) {
|
|
|
672
817
|
} else track.segments.forEach((segment) => {
|
|
673
818
|
let newSegment;
|
|
674
819
|
if (segment.byteRange) {
|
|
675
|
-
const initRange =
|
|
820
|
+
const initRange = segment.byteRange.start - 1;
|
|
676
821
|
newSegment = {
|
|
677
|
-
$: { indexRange: segment.byteRange },
|
|
822
|
+
$: { indexRange: byteRangeToDashString(segment.byteRange) },
|
|
678
823
|
Initialization: [{ $: { range: `0-${initRange}` } }]
|
|
679
824
|
};
|
|
680
825
|
}
|
|
@@ -702,7 +847,7 @@ function trackToSegmentList(track) {
|
|
|
702
847
|
duration: (track.duration * timescale / segmentURLs.length).toString(),
|
|
703
848
|
timescale: timescale.toString()
|
|
704
849
|
},
|
|
705
|
-
Initialization: [{ $: { sourceURL: track.
|
|
850
|
+
Initialization: [{ $: { sourceURL: track.initialization.url } }],
|
|
706
851
|
SegmentURL: segmentURLs
|
|
707
852
|
});
|
|
708
853
|
}
|
|
@@ -743,7 +888,7 @@ function tracksToRepresentation(tracks) {
|
|
|
743
888
|
SegmentBase: trackToSegmentBase(track),
|
|
744
889
|
SegmentList: trackToSegmentList(track)
|
|
745
890
|
};
|
|
746
|
-
representation.$.mimeType = `${track.type}/mp4`;
|
|
891
|
+
representation.$.mimeType = track.mimeType ?? `${track.type}/mp4`;
|
|
747
892
|
if (track.type === "video") {
|
|
748
893
|
const videoTrack = track;
|
|
749
894
|
representation.$ = {
|
|
@@ -751,7 +896,7 @@ function tracksToRepresentation(tracks) {
|
|
|
751
896
|
frameRate: getFrameRate$1(track),
|
|
752
897
|
width: videoTrack.width.toString(),
|
|
753
898
|
height: videoTrack.height.toString(),
|
|
754
|
-
codecs: videoTrack.
|
|
899
|
+
codecs: videoTrack.codecs?.join(",")
|
|
755
900
|
};
|
|
756
901
|
if (videoTrack.scanType) representation.$.scanType = videoTrack.scanType;
|
|
757
902
|
}
|
|
@@ -760,7 +905,7 @@ function tracksToRepresentation(tracks) {
|
|
|
760
905
|
representation.$ = {
|
|
761
906
|
...representation.$,
|
|
762
907
|
audioSamplingRate: audioTrack.sampleRate.toString(),
|
|
763
|
-
codecs: audioTrack.
|
|
908
|
+
codecs: audioTrack.codecs?.join(",")
|
|
764
909
|
};
|
|
765
910
|
representation.AudioChannelConfiguration = [{ $: {
|
|
766
911
|
schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
|
|
@@ -783,10 +928,10 @@ function selectionSetsToAdaptationSet(selectionsSets) {
|
|
|
783
928
|
id: switchingSet.id,
|
|
784
929
|
group: selectionSet.id,
|
|
785
930
|
contentType: track?.type,
|
|
786
|
-
mimeType: `${track?.type}/mp4`,
|
|
931
|
+
mimeType: track?.mimeType ?? `${track?.type}/mp4`,
|
|
787
932
|
frameRate: getFrameRate$1(track),
|
|
788
933
|
lang: track?.language,
|
|
789
|
-
codecs: track?.
|
|
934
|
+
codecs: track?.codecs?.join(",")
|
|
790
935
|
},
|
|
791
936
|
Representation: tracksToRepresentation(switchingSet.tracks)
|
|
792
937
|
};
|
|
@@ -999,12 +1144,12 @@ function hamToDash(presentation) {
|
|
|
999
1144
|
//#region src/mapper/hls/mapHamToHls/generateManifestPlaylistPiece.ts
|
|
1000
1145
|
function generateManifestPlaylistPiece(track) {
|
|
1001
1146
|
const mediaSequence = 0;
|
|
1002
|
-
const trackFileName = track.
|
|
1147
|
+
const trackFileName = track.url ?? `${track.id}.m3u8`;
|
|
1003
1148
|
let mainRef = "";
|
|
1004
1149
|
let playlist = `#EXTM3U\n#EXT-X-TARGETDURATION:${track.duration / track.segments.length}\n#EXT-X-PLAYLIST-TYPE:VOD\n#EXT-X-MEDIA-SEQUENCE:${mediaSequence}\n`;
|
|
1005
1150
|
if (track.type.toLowerCase() === "video") {
|
|
1006
1151
|
const videoTrack = track;
|
|
1007
|
-
mainRef += `#EXT-X-STREAM-INF:BANDWIDTH=${videoTrack.bandwidth},CODECS="${videoTrack.
|
|
1152
|
+
mainRef += `#EXT-X-STREAM-INF:BANDWIDTH=${videoTrack.bandwidth},CODECS="${videoTrack.codecs?.join(",") ?? ""}",RESOLUTION=${videoTrack.width}x${videoTrack.height}\n${trackFileName}\n`;
|
|
1008
1153
|
playlist += getPlaylistData(videoTrack);
|
|
1009
1154
|
} else if (track.type.toLowerCase() === "audio") {
|
|
1010
1155
|
const audioTrack = track;
|
|
@@ -1032,7 +1177,7 @@ function mapHamToHls(presentations) {
|
|
|
1032
1177
|
switchingSet.tracks.map((track) => {
|
|
1033
1178
|
const { mainRef, playlist } = generateManifestPlaylistPiece(track);
|
|
1034
1179
|
mainManifest += mainRef;
|
|
1035
|
-
const manifestFileName = track.
|
|
1180
|
+
const manifestFileName = track.url ?? `${track.id}.m3u8`;
|
|
1036
1181
|
playlists.push({
|
|
1037
1182
|
manifest: playlist,
|
|
1038
1183
|
type: "hls",
|
|
@@ -1100,25 +1245,31 @@ function audioGroupsToSwitchingSets(mediaGroupsAudio, manifestPlaylists) {
|
|
|
1100
1245
|
const map = audioParsed?.segments[0]?.map;
|
|
1101
1246
|
const segments = formatSegments(audioParsed?.segments);
|
|
1102
1247
|
const byteRange = decodeByteRange(map?.byterange);
|
|
1248
|
+
const codec = getHlsCodec("audio");
|
|
1103
1249
|
audioTracks.push({
|
|
1104
1250
|
id: audio,
|
|
1105
1251
|
type: "audio",
|
|
1106
|
-
|
|
1107
|
-
codec:
|
|
1252
|
+
url: uri,
|
|
1253
|
+
codecs: codec ? [codec] : [],
|
|
1254
|
+
mimeType: "audio/mp4",
|
|
1108
1255
|
duration: getDuration(audioParsed, segments),
|
|
1109
1256
|
language,
|
|
1110
1257
|
bandwidth: 0,
|
|
1111
1258
|
segments,
|
|
1112
1259
|
sampleRate: 0,
|
|
1113
1260
|
channels: 2,
|
|
1114
|
-
|
|
1115
|
-
|
|
1261
|
+
initialization: {
|
|
1262
|
+
url: map?.uri ?? "",
|
|
1263
|
+
...byteRange && { byteRange }
|
|
1264
|
+
},
|
|
1265
|
+
baseUrls: []
|
|
1116
1266
|
});
|
|
1117
1267
|
}
|
|
1118
1268
|
}
|
|
1119
1269
|
audioSwitchingSets.push({
|
|
1120
1270
|
id: "audio",
|
|
1121
|
-
tracks: audioTracks
|
|
1271
|
+
tracks: audioTracks,
|
|
1272
|
+
baseUrls: []
|
|
1122
1273
|
});
|
|
1123
1274
|
return audioSwitchingSets;
|
|
1124
1275
|
}
|
|
@@ -1134,21 +1285,26 @@ function subtitleGroupsToSwitchingSets(mediaGroupsSubtitles, manifestPlaylists)
|
|
|
1134
1285
|
const { language, uri } = encodings[subtitle];
|
|
1135
1286
|
const subtitleParsed = parseHlsManifest(manifestPlaylists.shift()?.manifest);
|
|
1136
1287
|
const segments = formatSegments(subtitleParsed?.segments);
|
|
1288
|
+
const codec = getHlsCodec("text");
|
|
1137
1289
|
textTracks.push({
|
|
1138
1290
|
id: subtitle,
|
|
1139
1291
|
type: "text",
|
|
1140
|
-
|
|
1141
|
-
codec:
|
|
1292
|
+
url: uri,
|
|
1293
|
+
codecs: codec ? [codec] : [],
|
|
1294
|
+
mimeType: "text/vtt",
|
|
1142
1295
|
duration: getDuration(subtitleParsed, segments),
|
|
1143
1296
|
language,
|
|
1144
1297
|
bandwidth: 0,
|
|
1145
|
-
segments
|
|
1298
|
+
segments,
|
|
1299
|
+
initialization: { url: "" },
|
|
1300
|
+
baseUrls: []
|
|
1146
1301
|
});
|
|
1147
1302
|
}
|
|
1148
1303
|
}
|
|
1149
1304
|
subtitleSwitchingSets.push({
|
|
1150
1305
|
id: "text",
|
|
1151
|
-
tracks: textTracks
|
|
1306
|
+
tracks: textTracks,
|
|
1307
|
+
baseUrls: []
|
|
1152
1308
|
});
|
|
1153
1309
|
return subtitleSwitchingSets;
|
|
1154
1310
|
}
|
|
@@ -1165,13 +1321,15 @@ function videoPlaylistsToSwitchingSets(playlists, manifestPlaylists) {
|
|
|
1165
1321
|
const { LANGUAGE, CODECS, BANDWIDTH } = playlist.attributes;
|
|
1166
1322
|
const map = parsedHlsManifest?.segments?.at(0)?.map;
|
|
1167
1323
|
const byteRange = decodeByteRange(map?.byterange);
|
|
1324
|
+
const codec = getHlsCodec("video", CODECS);
|
|
1168
1325
|
videoTracks.push({
|
|
1169
1326
|
id: `video-${videoTrackId++}`,
|
|
1170
1327
|
type: "video",
|
|
1171
|
-
|
|
1172
|
-
codec:
|
|
1328
|
+
url: playlist.uri,
|
|
1329
|
+
codecs: codec ? [codec] : [],
|
|
1330
|
+
mimeType: "video/mp4",
|
|
1173
1331
|
duration: getDuration(parsedHlsManifest, segments),
|
|
1174
|
-
language: LANGUAGE
|
|
1332
|
+
...LANGUAGE && { language: LANGUAGE },
|
|
1175
1333
|
bandwidth: BANDWIDTH,
|
|
1176
1334
|
segments,
|
|
1177
1335
|
width: playlist.attributes.RESOLUTION.width,
|
|
@@ -1183,13 +1341,17 @@ function videoPlaylistsToSwitchingSets(playlists, manifestPlaylists) {
|
|
|
1183
1341
|
par: "",
|
|
1184
1342
|
sar: "",
|
|
1185
1343
|
scanType: "",
|
|
1186
|
-
|
|
1187
|
-
|
|
1344
|
+
initialization: {
|
|
1345
|
+
url: map?.uri ?? "",
|
|
1346
|
+
...byteRange && { byteRange }
|
|
1347
|
+
},
|
|
1348
|
+
baseUrls: []
|
|
1188
1349
|
});
|
|
1189
1350
|
});
|
|
1190
1351
|
switchingSetVideos.push({
|
|
1191
1352
|
id: `video`,
|
|
1192
|
-
tracks: videoTracks
|
|
1353
|
+
tracks: videoTracks,
|
|
1354
|
+
baseUrls: []
|
|
1193
1355
|
});
|
|
1194
1356
|
return switchingSetVideos;
|
|
1195
1357
|
}
|
|
@@ -1216,20 +1378,29 @@ function mapHlsToHam(manifest) {
|
|
|
1216
1378
|
let selectionSetId = 0;
|
|
1217
1379
|
if (audioSwitchingSets.length > 0) selectionSets.push({
|
|
1218
1380
|
id: (selectionSetId++).toString(),
|
|
1219
|
-
switchingSets: audioSwitchingSets
|
|
1381
|
+
switchingSets: audioSwitchingSets,
|
|
1382
|
+
type: "audio"
|
|
1220
1383
|
});
|
|
1221
1384
|
if (subtitleSwitchingSets.length > 0) selectionSets.push({
|
|
1222
1385
|
id: (selectionSetId++).toString(),
|
|
1223
|
-
switchingSets: subtitleSwitchingSets
|
|
1386
|
+
switchingSets: subtitleSwitchingSets,
|
|
1387
|
+
type: "text"
|
|
1224
1388
|
});
|
|
1225
1389
|
if (videoSwitchingSets.length > 0) selectionSets.push({
|
|
1226
1390
|
id: (selectionSetId++).toString(),
|
|
1227
|
-
switchingSets: videoSwitchingSets
|
|
1391
|
+
switchingSets: videoSwitchingSets,
|
|
1392
|
+
type: "video"
|
|
1228
1393
|
});
|
|
1394
|
+
let duration = 0;
|
|
1395
|
+
for (const selectionSet of selectionSets) for (const switchingSet of selectionSet.switchingSets) for (const track of switchingSet.tracks) if (track.duration > duration) duration = track.duration;
|
|
1229
1396
|
let presentationId = 0;
|
|
1230
1397
|
return [{
|
|
1231
1398
|
id: (presentationId++).toString(),
|
|
1232
|
-
selectionSets
|
|
1399
|
+
selectionSets,
|
|
1400
|
+
duration,
|
|
1401
|
+
startTime: 0,
|
|
1402
|
+
endTime: duration,
|
|
1403
|
+
baseUrls: []
|
|
1233
1404
|
}];
|
|
1234
1405
|
}
|
|
1235
1406
|
|
|
@@ -1498,9 +1669,9 @@ function _validateVideoTrack(videoTrack, switchingSetId, prevValidation) {
|
|
|
1498
1669
|
errorMessages: []
|
|
1499
1670
|
};
|
|
1500
1671
|
const moreInformation = switchingSetId ? ` in the switching set with id = ${switchingSetId}` : ".";
|
|
1501
|
-
if (!videoTrack.
|
|
1672
|
+
if (!videoTrack.codecs || videoTrack.codecs.length === 0) {
|
|
1502
1673
|
validation.status = false;
|
|
1503
|
-
validation.errorMessages.push(`VideoTrack with id: ${videoTrack.id} does not have
|
|
1674
|
+
validation.errorMessages.push(`VideoTrack with id: ${videoTrack.id} does not have codecs${moreInformation}`);
|
|
1504
1675
|
}
|
|
1505
1676
|
return validation;
|
|
1506
1677
|
}
|
|
@@ -1524,9 +1695,9 @@ function _validateAudioTrack(audioTrack, switchingSetId, prevValidation) {
|
|
|
1524
1695
|
errorMessages: []
|
|
1525
1696
|
};
|
|
1526
1697
|
const moreInformation = switchingSetId ? ` in the switching set with id = ${switchingSetId}` : ".";
|
|
1527
|
-
if (!audioTrack.
|
|
1698
|
+
if (!audioTrack.codecs || audioTrack.codecs.length === 0) {
|
|
1528
1699
|
validation.status = false;
|
|
1529
|
-
validation.errorMessages.push(`AudioTrack with id: ${audioTrack.id} does not have
|
|
1700
|
+
validation.errorMessages.push(`AudioTrack with id: ${audioTrack.id} does not have codecs${moreInformation}`);
|
|
1530
1701
|
}
|
|
1531
1702
|
return validation;
|
|
1532
1703
|
}
|
|
@@ -1802,5 +1973,5 @@ function validatePresentation(presentation) {
|
|
|
1802
1973
|
}
|
|
1803
1974
|
|
|
1804
1975
|
//#endregion
|
|
1805
|
-
export { calculateDuration, dashToHam, decodeByteRange, encodeByteRange, formatSegments, getChannels, getCodec, getContentType, getDashParser, getDashSerializer, getDuration, getFrameRate, getGroup, getHlsCodec, getHlsParser, getLanguage, getNumberOfSegments, getPlaylistData, getPresentationId, getSampleRate, getSar, getSegments, getTimescale, getTrackDuration, getTracksFromPresentation, getTracksFromSelectionSet, getTracksFromSwitchingSet, getUrlFromTemplate, getUrlInitialization, hamToDash, hamToHls, hlsToHam, iso8601DurationToNumber, mapSegmentBase, mapSegmentList, mapSegmentTemplate, mapSegments, numberToIso8601Duration, parseDashManifest, parseHlsManifest, serializeDashManifest, setDashParser, setDashSerializer, setHlsParser, validatePresentation, validateSegment, validateSegments, validateSelectionSet, validateSelectionSets, validateSwitchingSet, validateSwitchingSets, validateTrack, validateTracks };
|
|
1976
|
+
export { byteRangeToDashString, byteRangeToHlsString, calculateDuration, dashToHam, decodeByteRange, encodeByteRange, formatSegments, getChannels, getCodec, getContentType, getDashParser, getDashSerializer, getDuration, getFrameRate, getGroup, getHlsCodec, getHlsParser, getLanguage, getNumberOfSegments, getPlaylistData, getPresentationId, getSampleRate, getSar, getSegments, getTimescale, getTrackDuration, getTracksFromPresentation, getTracksFromSelectionSet, getTracksFromSwitchingSet, getUrlFromTemplate, getUrlInitialization, hamToDash, hamToHls, hlsByterangeToByteRangeObject, hlsToHam, iso8601DurationToNumber, mapSegmentBase, mapSegmentList, mapSegmentTemplate, mapSegments, numberToIso8601Duration, parseByteRangeString, parseDashManifest, parseHlsManifest, serializeDashManifest, setDashParser, setDashSerializer, setHlsParser, validatePresentation, validateSegment, validateSegments, validateSelectionSet, validateSelectionSets, validateSwitchingSet, validateSwitchingSets, validateTrack, validateTracks };
|
|
1806
1977
|
//# sourceMappingURL=index.js.map
|