@remotion/media-parser 4.0.268 → 4.0.270
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/containers/flac/get-channel-count.d.ts +1 -1
- package/dist/containers/iso-base-media/get-moov-atom.js +1 -0
- package/dist/containers/m3u/after-manifest-fetch.d.ts +5 -7
- package/dist/containers/m3u/after-manifest-fetch.js +29 -43
- package/dist/containers/m3u/fetch-m3u8-stream.d.ts +1 -2
- package/dist/containers/m3u/fetch-m3u8-stream.js +4 -4
- package/dist/containers/m3u/get-duration-from-m3u.d.ts +2 -2
- package/dist/containers/m3u/get-duration-from-m3u.js +8 -3
- package/dist/containers/m3u/get-playlist.d.ts +6 -1
- package/dist/containers/m3u/get-playlist.js +18 -9
- package/dist/containers/m3u/get-streams.d.ts +3 -2
- package/dist/containers/m3u/get-streams.js +10 -3
- package/dist/containers/m3u/m3u-child-stream.d.ts +0 -0
- package/dist/containers/m3u/m3u-child-stream.js +1 -0
- package/dist/containers/m3u/parse-directive.js +28 -1
- package/dist/containers/m3u/parse-m3u-manifest.js +1 -1
- package/dist/containers/m3u/parse-m3u.js +8 -1
- package/dist/containers/m3u/return-packets.d.ts +3 -2
- package/dist/containers/m3u/return-packets.js +83 -54
- package/dist/containers/m3u/run-over-m3u.d.ts +9 -0
- package/dist/containers/m3u/run-over-m3u.js +88 -0
- package/dist/containers/m3u/sample-sorter.d.ts +13 -0
- package/dist/containers/m3u/sample-sorter.js +64 -0
- package/dist/containers/m3u/select-stream.d.ts +9 -1
- package/dist/containers/m3u/select-stream.js +21 -1
- package/dist/containers/m3u/types.d.ts +15 -1
- package/dist/containers/wav/parse-list.js +9 -1
- package/dist/download-and-parse-media.js +31 -30
- package/dist/esm/index.mjs +542 -212
- package/dist/get-duration.js +1 -1
- package/dist/index.d.ts +30 -26
- package/dist/index.js +2 -1
- package/dist/internal-parse-media.js +4 -2
- package/dist/options.d.ts +2 -1
- package/dist/parse-media.js +2 -1
- package/dist/state/m3u-state.d.ts +34 -16
- package/dist/state/m3u-state.js +89 -25
- package/dist/state/parser-state.d.ts +30 -26
- package/dist/state/parser-state.js +3 -2
- package/dist/throttled-progress.js +20 -9
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
-
export declare const getChannelCount: (iterator: BufferIterator) =>
|
|
2
|
+
export declare const getChannelCount: (iterator: BufferIterator) => 2 | 8 | 1 | 7 | 3 | 4 | 5 | 6;
|
|
@@ -39,6 +39,7 @@ const getMoovAtom = async ({ endOfMdat, state, }) => {
|
|
|
39
39
|
src: state.src,
|
|
40
40
|
onDiscardedData: null,
|
|
41
41
|
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
42
|
+
selectM3uAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
|
|
42
43
|
});
|
|
43
44
|
while (true) {
|
|
44
45
|
const result = await reader.reader.read();
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
+
import type { LogLevel } from '../../log';
|
|
1
2
|
import type { M3uState } from '../../state/m3u-state';
|
|
2
|
-
import type {
|
|
3
|
-
import type { SelectM3uStreamFn } from './select-stream';
|
|
3
|
+
import type { SelectM3uAssociatedPlaylistsFn, SelectM3uStreamFn } from './select-stream';
|
|
4
4
|
import type { M3uStructure } from './types';
|
|
5
|
-
export declare const afterManifestFetch: ({ structure, m3uState, src, selectM3uStreamFn, }: {
|
|
5
|
+
export declare const afterManifestFetch: ({ structure, m3uState, src, selectM3uStreamFn, logLevel, selectAssociatedPlaylists: selectAssociatedPlaylistsFn, }: {
|
|
6
6
|
structure: M3uStructure;
|
|
7
7
|
m3uState: M3uState;
|
|
8
8
|
src: string | null;
|
|
9
9
|
selectM3uStreamFn: SelectM3uStreamFn;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
state: ParserState;
|
|
13
|
-
structure: M3uStructure;
|
|
10
|
+
selectAssociatedPlaylists: SelectM3uAssociatedPlaylistsFn;
|
|
11
|
+
logLevel: LogLevel;
|
|
14
12
|
}) => Promise<void>;
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
3
|
+
exports.afterManifestFetch = void 0;
|
|
4
|
+
const log_1 = require("../../log");
|
|
5
5
|
const fetch_m3u8_stream_1 = require("./fetch-m3u8-stream");
|
|
6
6
|
const get_streams_1 = require("./get-streams");
|
|
7
|
-
const return_packets_1 = require("./return-packets");
|
|
8
7
|
const select_stream_1 = require("./select-stream");
|
|
9
|
-
const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn, }) => {
|
|
8
|
+
const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn, logLevel, selectAssociatedPlaylists: selectAssociatedPlaylistsFn, }) => {
|
|
10
9
|
const independentSegments = (0, get_streams_1.isIndependentSegments)(structure);
|
|
11
10
|
if (!independentSegments) {
|
|
12
11
|
if (!src) {
|
|
13
12
|
throw new Error('No src');
|
|
14
13
|
}
|
|
15
|
-
m3uState.
|
|
14
|
+
m3uState.setSelectedMainPlaylist({
|
|
16
15
|
type: 'initial-url',
|
|
17
16
|
url: src,
|
|
18
17
|
});
|
|
@@ -22,46 +21,33 @@ const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn,
|
|
|
22
21
|
if (streams === null) {
|
|
23
22
|
throw new Error('No streams found');
|
|
24
23
|
}
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
if (!selectedStream.resolution) {
|
|
24
|
+
const selectedPlaylist = await (0, select_stream_1.selectStream)({ streams, fn: selectM3uStreamFn });
|
|
25
|
+
if (!selectedPlaylist.resolution) {
|
|
28
26
|
throw new Error('Stream does not have a resolution');
|
|
29
27
|
}
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
m3uState.setSelectedMainPlaylist({
|
|
29
|
+
type: 'selected-stream',
|
|
30
|
+
stream: selectedPlaylist,
|
|
31
|
+
});
|
|
32
|
+
const associatedPlaylists = await (0, select_stream_1.selectAssociatedPlaylists)({
|
|
33
|
+
playlists: selectedPlaylist.associatedPlaylists,
|
|
34
|
+
fn: selectAssociatedPlaylistsFn,
|
|
35
|
+
});
|
|
36
|
+
m3uState.setAssociatedPlaylists(associatedPlaylists);
|
|
37
|
+
const playlistUrls = [
|
|
38
|
+
selectedPlaylist.url,
|
|
39
|
+
...associatedPlaylists.map((p) => p.url),
|
|
40
|
+
];
|
|
41
|
+
const struc = await Promise.all(playlistUrls.map(async (url) => {
|
|
42
|
+
log_1.Log.verbose(logLevel, `Fetching playlist ${url}`);
|
|
43
|
+
const boxes = await (0, fetch_m3u8_stream_1.fetchM3u8Stream)(url);
|
|
44
|
+
return {
|
|
45
|
+
type: 'm3u-playlist',
|
|
46
|
+
boxes,
|
|
47
|
+
src: url,
|
|
48
|
+
};
|
|
49
|
+
}));
|
|
50
|
+
structure.boxes.push(...struc);
|
|
32
51
|
m3uState.setReadyToIterateOverM3u();
|
|
33
52
|
};
|
|
34
53
|
exports.afterManifestFetch = afterManifestFetch;
|
|
35
|
-
const runOverM3u = async ({ state, structure, }) => {
|
|
36
|
-
const selectedStream = state.m3u.getSelectedStream();
|
|
37
|
-
if (!selectedStream) {
|
|
38
|
-
throw new Error('No stream selected');
|
|
39
|
-
}
|
|
40
|
-
await (0, return_packets_1.iteratorOverTsFiles)({
|
|
41
|
-
playlistUrl: selectedStream.type === 'initial-url'
|
|
42
|
-
? selectedStream.url
|
|
43
|
-
: selectedStream.stream.url,
|
|
44
|
-
structure,
|
|
45
|
-
logLevel: state.logLevel,
|
|
46
|
-
onDoneWithTracks() {
|
|
47
|
-
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
48
|
-
},
|
|
49
|
-
onAudioTrack: (track) => {
|
|
50
|
-
return (0, register_track_1.registerAudioTrack)({
|
|
51
|
-
container: 'm3u8',
|
|
52
|
-
state,
|
|
53
|
-
track,
|
|
54
|
-
});
|
|
55
|
-
},
|
|
56
|
-
onVideoTrack: (track) => {
|
|
57
|
-
return (0, register_track_1.registerVideoTrack)({
|
|
58
|
-
container: 'm3u8',
|
|
59
|
-
state,
|
|
60
|
-
track,
|
|
61
|
-
});
|
|
62
|
-
},
|
|
63
|
-
m3uState: state.m3u,
|
|
64
|
-
parentController: state.controller,
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
exports.runOverM3u = runOverM3u;
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fetchM3u8Stream = void 0;
|
|
4
4
|
const parse_m3u8_text_1 = require("./parse-m3u8-text");
|
|
5
|
-
const fetchM3u8Stream = async (
|
|
6
|
-
const res = await fetch(
|
|
5
|
+
const fetchM3u8Stream = async (url) => {
|
|
6
|
+
const res = await fetch(url);
|
|
7
7
|
if (!res.ok) {
|
|
8
|
-
throw new Error(`Failed to fetch ${
|
|
8
|
+
throw new Error(`Failed to fetch ${url} (HTTP code: ${res.status})`);
|
|
9
9
|
}
|
|
10
10
|
const text = await res.text();
|
|
11
11
|
const lines = text.split('\n');
|
|
12
12
|
const boxes = [];
|
|
13
13
|
for (const line of lines) {
|
|
14
|
-
(0, parse_m3u8_text_1.parseM3u8Text)(line, boxes);
|
|
14
|
+
(0, parse_m3u8_text_1.parseM3u8Text)(line.trim(), boxes);
|
|
15
15
|
}
|
|
16
16
|
return boxes;
|
|
17
17
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const getDurationFromM3u: (
|
|
1
|
+
import type { ParserState } from '../../state/parser-state';
|
|
2
|
+
export declare const getDurationFromM3u: (state: ParserState) => number | null;
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getDurationFromM3u = void 0;
|
|
4
4
|
const get_playlist_1 = require("./get-playlist");
|
|
5
|
-
const getDurationFromM3u = (
|
|
6
|
-
const
|
|
7
|
-
|
|
5
|
+
const getDurationFromM3u = (state) => {
|
|
6
|
+
const playlists = (0, get_playlist_1.getAllPlaylists)({
|
|
7
|
+
structure: state.getM3uStructure(),
|
|
8
|
+
src: state.src,
|
|
9
|
+
});
|
|
10
|
+
return Math.max(...playlists.map((p) => {
|
|
11
|
+
return (0, get_playlist_1.getDurationFromPlaylist)(p);
|
|
12
|
+
}));
|
|
8
13
|
};
|
|
9
14
|
exports.getDurationFromM3u = getDurationFromM3u;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import type { ParseMediaSrc } from '../../options';
|
|
1
2
|
import type { M3uPlaylist, M3uStructure } from './types';
|
|
2
|
-
export declare const
|
|
3
|
+
export declare const getAllPlaylists: ({ structure, src, }: {
|
|
4
|
+
structure: M3uStructure;
|
|
5
|
+
src: ParseMediaSrc;
|
|
6
|
+
}) => M3uPlaylist[];
|
|
7
|
+
export declare const getPlaylist: (structure: M3uStructure, src: string) => M3uPlaylist;
|
|
3
8
|
export declare const getDurationFromPlaylist: (playlist: M3uPlaylist) => number;
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDurationFromPlaylist = exports.getPlaylist = void 0;
|
|
3
|
+
exports.getDurationFromPlaylist = exports.getPlaylist = exports.getAllPlaylists = void 0;
|
|
4
4
|
const get_streams_1 = require("./get-streams");
|
|
5
|
-
const
|
|
5
|
+
const getAllPlaylists = ({ structure, src, }) => {
|
|
6
6
|
const isIndependent = (0, get_streams_1.isIndependentSegments)(structure);
|
|
7
7
|
if (!isIndependent) {
|
|
8
|
-
return
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
type: 'm3u-playlist',
|
|
11
|
+
boxes: structure.boxes,
|
|
12
|
+
src,
|
|
13
|
+
},
|
|
14
|
+
];
|
|
12
15
|
}
|
|
13
16
|
const playlists = structure.boxes.filter((box) => box.type === 'm3u-playlist');
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
return playlists;
|
|
18
|
+
};
|
|
19
|
+
exports.getAllPlaylists = getAllPlaylists;
|
|
20
|
+
const getPlaylist = (structure, src) => {
|
|
21
|
+
const allPlaylists = (0, exports.getAllPlaylists)({ structure, src });
|
|
22
|
+
const playlists = allPlaylists.find((box) => box.src === src);
|
|
23
|
+
if (!playlists) {
|
|
24
|
+
throw new Error(`Expected m3u-playlist with src ${src}`);
|
|
16
25
|
}
|
|
17
|
-
return playlists
|
|
26
|
+
return playlists;
|
|
18
27
|
};
|
|
19
28
|
exports.getPlaylist = getPlaylist;
|
|
20
29
|
const getDurationFromPlaylist = (playlist) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Dimensions } from '../../get-dimensions';
|
|
2
2
|
import type { Structure } from '../../parse-result';
|
|
3
3
|
import type { ParserState } from '../../state/parser-state';
|
|
4
|
-
export type
|
|
4
|
+
export type M3uAssociatedPlaylist = {
|
|
5
5
|
groupId: string;
|
|
6
6
|
language: string | null;
|
|
7
7
|
name: string | null;
|
|
@@ -9,6 +9,7 @@ export type M3uStreamAudioTrack = {
|
|
|
9
9
|
default: boolean;
|
|
10
10
|
channels: number | null;
|
|
11
11
|
url: string;
|
|
12
|
+
id: number;
|
|
12
13
|
};
|
|
13
14
|
export type M3uStream = {
|
|
14
15
|
url: string;
|
|
@@ -17,7 +18,7 @@ export type M3uStream = {
|
|
|
17
18
|
resolution: Dimensions | null;
|
|
18
19
|
codecs: string[] | null;
|
|
19
20
|
id: number;
|
|
20
|
-
|
|
21
|
+
associatedPlaylists: M3uAssociatedPlaylist[];
|
|
21
22
|
};
|
|
22
23
|
export declare const isIndependentSegments: (structure: Structure | null) => boolean;
|
|
23
24
|
export declare const getM3uStreams: (structure: Structure | null, originalSrc: string | null) => M3uStream[] | null;
|
|
@@ -20,13 +20,13 @@ const getM3uStreams = (structure, originalSrc) => {
|
|
|
20
20
|
if (next.type !== 'm3u-text-value') {
|
|
21
21
|
throw new Error('Expected m3u-text-value');
|
|
22
22
|
}
|
|
23
|
-
const
|
|
23
|
+
const associatedPlaylists = [];
|
|
24
24
|
if (str.audio) {
|
|
25
25
|
const match = structure.boxes.filter((box) => {
|
|
26
26
|
return box.type === 'm3u-media-info' && box.groupId === str.audio;
|
|
27
27
|
});
|
|
28
28
|
for (const audioTrack of match) {
|
|
29
|
-
|
|
29
|
+
associatedPlaylists.push({
|
|
30
30
|
autoselect: audioTrack.autoselect,
|
|
31
31
|
channels: audioTrack.channels,
|
|
32
32
|
default: audioTrack.default,
|
|
@@ -36,6 +36,7 @@ const getM3uStreams = (structure, originalSrc) => {
|
|
|
36
36
|
url: originalSrc && originalSrc.startsWith('http')
|
|
37
37
|
? new URL(audioTrack.uri, originalSrc).href
|
|
38
38
|
: audioTrack.uri,
|
|
39
|
+
id: associatedPlaylists.length,
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
42
|
}
|
|
@@ -47,7 +48,7 @@ const getM3uStreams = (structure, originalSrc) => {
|
|
|
47
48
|
bandwidth: str.bandwidth,
|
|
48
49
|
codecs: str.codecs,
|
|
49
50
|
resolution: str.resolution,
|
|
50
|
-
|
|
51
|
+
associatedPlaylists,
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
}
|
|
@@ -56,12 +57,18 @@ const getM3uStreams = (structure, originalSrc) => {
|
|
|
56
57
|
return null;
|
|
57
58
|
}
|
|
58
59
|
const sorted = boxes.slice().sort((a, b) => {
|
|
60
|
+
var _a, _b, _c, _d;
|
|
59
61
|
const aResolution = a.resolution
|
|
60
62
|
? a.resolution.width * a.resolution.height
|
|
61
63
|
: 0;
|
|
62
64
|
const bResolution = b.resolution
|
|
63
65
|
? b.resolution.width * b.resolution.height
|
|
64
66
|
: 0;
|
|
67
|
+
if (aResolution === bResolution) {
|
|
68
|
+
const bandwidthA = (_b = (_a = a.averageBandwidth) !== null && _a !== void 0 ? _a : a.bandwidth) !== null && _b !== void 0 ? _b : 0;
|
|
69
|
+
const bandwidthB = (_d = (_c = b.averageBandwidth) !== null && _c !== void 0 ? _c : b.bandwidth) !== null && _d !== void 0 ? _d : 0;
|
|
70
|
+
return bandwidthB - bandwidthA;
|
|
71
|
+
}
|
|
65
72
|
return bResolution - aResolution;
|
|
66
73
|
});
|
|
67
74
|
return sorted.map((box, index) => ({ ...box, id: index }));
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -5,7 +5,7 @@ const parse_m3u_media_directive_1 = require("./parse-m3u-media-directive");
|
|
|
5
5
|
const parse_stream_inf_1 = require("./parse-stream-inf");
|
|
6
6
|
const parseM3uDirective = (str) => {
|
|
7
7
|
const firstColon = str.indexOf(':');
|
|
8
|
-
const directive = firstColon === -1 ? str : str.slice(0, firstColon);
|
|
8
|
+
const directive = (firstColon === -1 ? str : str.slice(0, firstColon)).trim();
|
|
9
9
|
const value = firstColon === -1 ? null : str.slice(firstColon + 1);
|
|
10
10
|
if (directive === '#EXT-X-VERSION') {
|
|
11
11
|
if (!value) {
|
|
@@ -60,6 +60,24 @@ const parseM3uDirective = (str) => {
|
|
|
60
60
|
playlistType: value,
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
+
if (directive === '#EXT-X-MEDIA-SEQUENCE') {
|
|
64
|
+
if (!value) {
|
|
65
|
+
throw new Error('#EXT-X-MEDIA-SEQUENCE directive must have a value');
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
type: 'm3u-media-sequence',
|
|
69
|
+
value: Number(value),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (directive === '#EXT-X-DISCONTINUITY-SEQUENCE') {
|
|
73
|
+
if (!value) {
|
|
74
|
+
throw new Error('#EXT-X-DISCONTINUITY-SEQUENCE directive must have a value');
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
type: 'm3u-discontinuity-sequence',
|
|
78
|
+
value: Number(value),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
63
81
|
if (directive === '#EXT-X-STREAM-INF') {
|
|
64
82
|
if (!value) {
|
|
65
83
|
throw new Error('EXT-X-STREAM-INF directive must have a value');
|
|
@@ -67,6 +85,15 @@ const parseM3uDirective = (str) => {
|
|
|
67
85
|
const res = (0, parse_stream_inf_1.parseStreamInf)(value);
|
|
68
86
|
return res;
|
|
69
87
|
}
|
|
88
|
+
if (directive === '#EXT-X-MAP') {
|
|
89
|
+
if (!value) {
|
|
90
|
+
throw new Error('#EXT-X-MAP directive must have a value');
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
type: 'm3u-map',
|
|
94
|
+
value: Number(value),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
70
97
|
throw new Error(`Unknown directive ${directive}. Value: ${value}`);
|
|
71
98
|
};
|
|
72
99
|
exports.parseM3uDirective = parseM3uDirective;
|
|
@@ -12,7 +12,7 @@ const parseM3uManifest = ({ iterator, structure, contentLength, }) => {
|
|
|
12
12
|
start.returnToCheckpoint();
|
|
13
13
|
return Promise.resolve(null);
|
|
14
14
|
}
|
|
15
|
-
(0, parse_m3u8_text_1.parseM3u8Text)(line, structure.boxes);
|
|
15
|
+
(0, parse_m3u8_text_1.parseM3u8Text)(line.trim(), structure.boxes);
|
|
16
16
|
return Promise.resolve(null);
|
|
17
17
|
};
|
|
18
18
|
exports.parseM3uManifest = parseM3uManifest;
|
|
@@ -3,12 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseM3u = void 0;
|
|
4
4
|
const after_manifest_fetch_1 = require("./after-manifest-fetch");
|
|
5
5
|
const parse_m3u_manifest_1 = require("./parse-m3u-manifest");
|
|
6
|
+
const run_over_m3u_1 = require("./run-over-m3u");
|
|
6
7
|
const parseM3u = async ({ state }) => {
|
|
7
8
|
const structure = state.getM3uStructure();
|
|
8
9
|
if (state.m3u.isReadyToIterateOverM3u()) {
|
|
9
|
-
|
|
10
|
+
const selectedPlaylists = state.m3u.getSelectedPlaylists();
|
|
11
|
+
const whichPlaylistToRunOver = state.m3u.sampleSorter.getNextStreamToRun(selectedPlaylists);
|
|
12
|
+
await (0, run_over_m3u_1.runOverM3u)({
|
|
10
13
|
state,
|
|
11
14
|
structure,
|
|
15
|
+
playlistUrl: whichPlaylistToRunOver,
|
|
16
|
+
logLevel: state.logLevel,
|
|
12
17
|
});
|
|
13
18
|
return null;
|
|
14
19
|
}
|
|
@@ -18,6 +23,8 @@ const parseM3u = async ({ state }) => {
|
|
|
18
23
|
m3uState: state.m3u,
|
|
19
24
|
src: typeof state.src === 'string' ? state.src : null,
|
|
20
25
|
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
26
|
+
logLevel: state.logLevel,
|
|
27
|
+
selectAssociatedPlaylists: state.selectM3uAssociatedPlaylistsFn,
|
|
21
28
|
});
|
|
22
29
|
return null;
|
|
23
30
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AudioTrack, VideoTrack } from '../../get-tracks';
|
|
2
2
|
import type { LogLevel } from '../../log';
|
|
3
3
|
import type { MediaParserController } from '../../media-parser-controller';
|
|
4
|
-
import type { M3uState } from '../../state/m3u-state';
|
|
4
|
+
import type { ExistingM3uRun, M3uState } from '../../state/m3u-state';
|
|
5
5
|
import type { OnAudioSample, OnVideoSample } from '../../webcodec-sample-types';
|
|
6
6
|
import type { M3uStructure } from './types';
|
|
7
|
-
export declare const iteratorOverTsFiles: ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, }: {
|
|
7
|
+
export declare const iteratorOverTsFiles: ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, onInitialProgress, }: {
|
|
8
8
|
structure: M3uStructure;
|
|
9
9
|
onVideoTrack: (track: VideoTrack) => Promise<OnVideoSample | null>;
|
|
10
10
|
onAudioTrack: (track: AudioTrack) => Promise<OnAudioSample | null>;
|
|
@@ -13,4 +13,5 @@ export declare const iteratorOverTsFiles: ({ structure, onVideoTrack, m3uState,
|
|
|
13
13
|
playlistUrl: string;
|
|
14
14
|
logLevel: LogLevel;
|
|
15
15
|
parentController: MediaParserController;
|
|
16
|
+
onInitialProgress: (run: ExistingM3uRun | null) => void;
|
|
16
17
|
}) => Promise<void>;
|
|
@@ -6,66 +6,95 @@ const media_parser_controller_1 = require("../../media-parser-controller");
|
|
|
6
6
|
const parse_media_1 = require("../../parse-media");
|
|
7
7
|
const get_chunks_1 = require("./get-chunks");
|
|
8
8
|
const get_playlist_1 = require("./get-playlist");
|
|
9
|
-
const iteratorOverTsFiles = async ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, }) => {
|
|
10
|
-
const playlist = (0, get_playlist_1.getPlaylist)(structure);
|
|
9
|
+
const iteratorOverTsFiles = async ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, onInitialProgress, }) => {
|
|
10
|
+
const playlist = (0, get_playlist_1.getPlaylist)(structure, playlistUrl);
|
|
11
11
|
const chunks = (0, get_chunks_1.getChunks)(playlist);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const isLastChunk = chunkIndex === chunks.length - 1;
|
|
16
|
-
const src = new URL(chunk.url, playlistUrl).toString();
|
|
12
|
+
let resolver = onInitialProgress;
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
+
let rejector = (_e) => { };
|
|
17
15
|
const childController = (0, media_parser_controller_1.mediaParserController)();
|
|
18
16
|
const forwarded = (0, forward_controller_1.forwardMediaParserController)({
|
|
19
17
|
childController,
|
|
20
18
|
parentController,
|
|
21
19
|
});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
20
|
+
const makeContinuationFn = () => {
|
|
21
|
+
return {
|
|
22
|
+
continue() {
|
|
23
|
+
const { promise, reject, resolve } = Promise.withResolvers();
|
|
24
|
+
resolver = resolve;
|
|
25
|
+
rejector = reject;
|
|
26
|
+
childController.resume();
|
|
27
|
+
return promise;
|
|
28
|
+
},
|
|
29
|
+
abort() {
|
|
30
|
+
childController.abort();
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
for (const chunk of chunks) {
|
|
35
|
+
const isLastChunk = chunk === chunks[chunks.length - 1];
|
|
36
|
+
await childController._internals.checkForAbortAndPause();
|
|
37
|
+
const src = new URL(chunk.url, playlistUrl).toString();
|
|
38
|
+
try {
|
|
39
|
+
await (0, parse_media_1.parseMedia)({
|
|
40
|
+
src,
|
|
41
|
+
acknowledgeRemotionLicense: true,
|
|
42
|
+
logLevel,
|
|
43
|
+
controller: childController,
|
|
44
|
+
progressIntervalInMs: 0,
|
|
45
|
+
onParseProgress: () => {
|
|
46
|
+
childController.pause();
|
|
47
|
+
resolver(makeContinuationFn());
|
|
48
|
+
},
|
|
49
|
+
onTracks: () => {
|
|
50
|
+
if (!m3uState.hasEmittedDoneWithTracks(playlistUrl)) {
|
|
51
|
+
m3uState.setHasEmittedDoneWithTracks(playlistUrl);
|
|
52
|
+
onDoneWithTracks();
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
onAudioTrack: async ({ track }) => {
|
|
57
|
+
const callbackOrFalse = m3uState.hasEmittedAudioTrack(playlistUrl);
|
|
58
|
+
if (callbackOrFalse === false) {
|
|
59
|
+
const callback = await onAudioTrack(track);
|
|
60
|
+
if (!callback) {
|
|
61
|
+
m3uState.setHasEmittedAudioTrack(playlistUrl, null);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
m3uState.setHasEmittedAudioTrack(playlistUrl, callback);
|
|
65
|
+
return (sample) => {
|
|
66
|
+
return callback(sample);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return callbackOrFalse;
|
|
70
|
+
},
|
|
71
|
+
onVideoTrack: async ({ track }) => {
|
|
72
|
+
const callbackOrFalse = m3uState.hasEmittedVideoTrack(playlistUrl);
|
|
73
|
+
if (callbackOrFalse === false) {
|
|
74
|
+
const callback = await onVideoTrack(track);
|
|
75
|
+
if (!callback) {
|
|
76
|
+
m3uState.setHasEmittedVideoTrack(playlistUrl, null);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
m3uState.setHasEmittedVideoTrack(playlistUrl, callback);
|
|
80
|
+
return (sample) => {
|
|
81
|
+
return callback(sample);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return callbackOrFalse;
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
rejector(e);
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
forwarded.cleanup();
|
|
93
|
+
if (!isLastChunk) {
|
|
94
|
+
childController.pause();
|
|
95
|
+
resolver(makeContinuationFn());
|
|
96
|
+
}
|
|
68
97
|
}
|
|
69
|
-
|
|
98
|
+
resolver(null);
|
|
70
99
|
};
|
|
71
100
|
exports.iteratorOverTsFiles = iteratorOverTsFiles;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LogLevel } from '../../log';
|
|
2
|
+
import type { ParserState } from '../../state/parser-state';
|
|
3
|
+
import type { M3uStructure } from './types';
|
|
4
|
+
export declare const runOverM3u: ({ state, structure, playlistUrl, logLevel, }: {
|
|
5
|
+
state: ParserState;
|
|
6
|
+
structure: M3uStructure;
|
|
7
|
+
playlistUrl: string;
|
|
8
|
+
logLevel: LogLevel;
|
|
9
|
+
}) => Promise<void>;
|