@remotion/media-parser 4.0.265 → 4.0.266
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/buffer-iterator.d.ts +1 -0
- package/dist/buffer-iterator.js +17 -0
- package/dist/containers/aac/parse-aac.js +1 -1
- package/dist/containers/avc/create-sps-pps-data.js +15 -1
- package/dist/containers/avc/interpret-sps.js +8 -2
- package/dist/containers/avc/parse-avc.js +23 -24
- package/dist/containers/flac/get-channel-count.d.ts +1 -1
- package/dist/containers/flac/m3u/after-manifest-fetch.d.ts +14 -0
- package/dist/containers/flac/m3u/after-manifest-fetch.js +53 -0
- package/dist/containers/flac/m3u/fetch-m3u8-stream.d.ts +3 -0
- package/dist/containers/flac/m3u/fetch-m3u8-stream.js +15 -0
- package/dist/containers/flac/m3u/get-chunks.d.ts +6 -0
- package/dist/containers/flac/m3u/get-chunks.js +20 -0
- package/dist/containers/flac/m3u/get-duration-from-m3u.d.ts +2 -0
- package/dist/containers/flac/m3u/get-duration-from-m3u.js +9 -0
- package/dist/containers/flac/m3u/get-playlist.d.ts +3 -0
- package/dist/containers/flac/m3u/get-playlist.js +19 -0
- package/dist/containers/flac/m3u/get-streams.d.ts +13 -0
- package/dist/containers/flac/m3u/get-streams.js +41 -0
- package/dist/containers/flac/m3u/parse-directive.d.ts +2 -0
- package/dist/containers/flac/m3u/parse-directive.js +64 -0
- package/dist/containers/flac/m3u/parse-m3u-manifest.d.ts +8 -0
- package/dist/containers/flac/m3u/parse-m3u-manifest.js +18 -0
- package/dist/containers/flac/m3u/parse-m3u.d.ts +4 -0
- package/dist/containers/flac/m3u/parse-m3u.js +35 -0
- package/dist/containers/flac/m3u/parse-m3u8-text.d.ts +2 -0
- package/dist/containers/flac/m3u/parse-m3u8-text.js +23 -0
- package/dist/containers/flac/m3u/parse-stream-inf.d.ts +3 -0
- package/dist/containers/flac/m3u/parse-stream-inf.js +61 -0
- package/dist/containers/flac/m3u/return-packets.d.ts +14 -0
- package/dist/containers/flac/m3u/return-packets.js +63 -0
- package/dist/containers/flac/m3u/select-stream.d.ts +10 -0
- package/dist/containers/flac/m3u/select-stream.js +15 -0
- package/dist/containers/flac/m3u/types.d.ts +48 -0
- package/dist/containers/flac/m3u/types.js +2 -0
- package/dist/containers/flac/parse-streaminfo.js +1 -1
- package/dist/containers/iso-base-media/get-moov-atom.js +3 -2
- package/dist/containers/iso-base-media/process-box.js +9 -2
- package/dist/containers/iso-base-media/trun.js +1 -1
- package/dist/containers/m3u/after-manifest-fetch.d.ts +14 -0
- package/dist/containers/m3u/after-manifest-fetch.js +67 -0
- package/dist/containers/m3u/fetch-m3u8-stream.d.ts +3 -0
- package/dist/containers/m3u/fetch-m3u8-stream.js +18 -0
- package/dist/containers/m3u/get-chunks.d.ts +6 -0
- package/dist/containers/m3u/get-chunks.js +20 -0
- package/dist/containers/m3u/get-duration-from-m3u.d.ts +2 -0
- package/dist/containers/m3u/get-duration-from-m3u.js +9 -0
- package/dist/containers/m3u/get-playlist.d.ts +3 -0
- package/dist/containers/m3u/get-playlist.js +27 -0
- package/dist/containers/m3u/get-streams.d.ts +14 -0
- package/dist/containers/m3u/get-streams.js +60 -0
- package/dist/containers/m3u/parse-directive.d.ts +2 -0
- package/dist/containers/m3u/parse-directive.js +64 -0
- package/dist/containers/m3u/parse-m3u-manifest.d.ts +8 -0
- package/dist/containers/m3u/parse-m3u-manifest.js +18 -0
- package/dist/containers/m3u/parse-m3u.d.ts +4 -0
- package/dist/containers/m3u/parse-m3u.js +35 -0
- package/dist/containers/m3u/parse-m3u8-text.d.ts +2 -0
- package/dist/containers/m3u/parse-m3u8-text.js +23 -0
- package/dist/containers/m3u/parse-stream-inf.d.ts +3 -0
- package/dist/containers/m3u/parse-stream-inf.js +61 -0
- package/dist/containers/m3u/return-packets.d.ts +16 -0
- package/dist/containers/m3u/return-packets.js +71 -0
- package/dist/containers/m3u/select-stream.d.ts +10 -0
- package/dist/containers/m3u/select-stream.js +19 -0
- package/dist/containers/m3u/types.d.ts +48 -0
- package/dist/containers/m3u/types.js +2 -0
- package/dist/containers/mp3/parse-mpeg-header.js +1 -1
- package/dist/containers/riff/expect-riff-box.js +1 -1
- package/dist/containers/transport-stream/boxes.d.ts +4 -1
- package/dist/containers/transport-stream/find-separator.d.ts +1 -2
- package/dist/containers/transport-stream/find-separator.js +7 -13
- package/dist/containers/transport-stream/handle-aac-packet.js +1 -1
- package/dist/containers/transport-stream/handle-avc-packet.js +1 -1
- package/dist/containers/transport-stream/parse-packet.js +7 -1
- package/dist/containers/transport-stream/parse-pat.d.ts +2 -1
- package/dist/containers/transport-stream/parse-pat.js +16 -1
- package/dist/containers/transport-stream/parse-stream-packet.js +86 -74
- package/dist/containers/wav/parse-fmt.js +1 -1
- package/dist/containers/webm/parse-ebml.js +9 -2
- package/dist/does-need-contentlength-contentrange.d.ts +2 -0
- package/dist/does-need-contentlength-contentrange.js +10 -0
- package/dist/download-and-parse-media.js +32 -29
- package/dist/emit-available-info.js +13 -1
- package/dist/emitter.d.ts +4 -0
- package/dist/emitter.js +4 -0
- package/dist/esm/from-fetch.mjs +65 -38
- package/dist/esm/from-node.mjs +2 -8
- package/dist/esm/from-web-file.mjs +2 -7
- package/dist/esm/index.mjs +1029 -289
- package/dist/file-types/detect-file-type.d.ts +5 -1
- package/dist/file-types/detect-file-type.js +5 -1
- package/dist/file-types/index.js +3 -0
- package/dist/forward-controller.d.ts +7 -0
- package/dist/forward-controller.js +25 -0
- package/dist/get-container.js +3 -0
- package/dist/get-duration.js +35 -2
- package/dist/get-fields-from-callbacks.js +1 -0
- package/dist/get-fps.js +7 -0
- package/dist/get-tracks.d.ts +2 -0
- package/dist/get-tracks.js +29 -4
- package/dist/has-all-info.js +4 -0
- package/dist/index.d.ts +46 -9
- package/dist/index.js +3 -1
- package/dist/init-video.js +8 -0
- package/dist/internal-parse-media.js +11 -4
- package/dist/is-audio-structure.js +3 -0
- package/dist/media-parser-controller.js +3 -1
- package/dist/metadata/get-metadata.js +26 -3
- package/dist/options.d.ts +9 -1
- package/dist/parse-media.js +11 -8
- package/dist/parse-result.d.ts +2 -1
- package/dist/readers/fetch/get-body-and-reader.d.ts +8 -0
- package/dist/readers/fetch/get-body-and-reader.js +41 -0
- package/dist/readers/fetch/resolve-url.d.ts +1 -0
- package/dist/readers/fetch/resolve-url.js +15 -0
- package/dist/readers/from-fetch.js +19 -40
- package/dist/readers/from-node.js +1 -7
- package/dist/readers/from-uintarray.d.ts +2 -0
- package/dist/readers/from-uintarray.js +27 -0
- package/dist/readers/from-web-file.js +1 -6
- package/dist/readers/reader.d.ts +1 -2
- package/dist/register-track.d.ts +8 -3
- package/dist/register-track.js +30 -17
- package/dist/run-parse-iteration.js +6 -1
- package/dist/state/can-skip-tracks.js +2 -1
- package/dist/state/emitted-fields.js +1 -0
- package/dist/state/m3u-state.d.ts +29 -0
- package/dist/state/m3u-state.js +48 -0
- package/dist/state/need-samples-for-fields.js +1 -0
- package/dist/state/parser-state.d.ts +36 -1
- package/dist/state/parser-state.js +4 -1
- package/dist/state/structure.d.ts +1 -0
- package/dist/state/structure.js +7 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.iteratorOverTsFiles = void 0;
|
|
4
|
+
const parse_media_1 = require("../../parse-media");
|
|
5
|
+
const get_chunks_1 = require("./get-chunks");
|
|
6
|
+
const get_playlist_1 = require("./get-playlist");
|
|
7
|
+
const iteratorOverTsFiles = async ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, }) => {
|
|
8
|
+
const playlist = (0, get_playlist_1.getPlaylist)(structure);
|
|
9
|
+
const chunks = (0, get_chunks_1.getChunks)(playlist);
|
|
10
|
+
const lastChunkProcessed = m3uState.getLastChunkProcessed();
|
|
11
|
+
const chunkIndex = lastChunkProcessed + 1;
|
|
12
|
+
// TODO: Be able to pause / resume / cancel / seek
|
|
13
|
+
const chunk = chunks[chunkIndex];
|
|
14
|
+
const isLastChunk = chunkIndex === chunks.length - 1;
|
|
15
|
+
const src = new URL(chunk.url, playlistUrl).toString();
|
|
16
|
+
await (0, parse_media_1.parseMedia)({
|
|
17
|
+
src,
|
|
18
|
+
acknowledgeRemotionLicense: true,
|
|
19
|
+
logLevel,
|
|
20
|
+
onTracks: () => {
|
|
21
|
+
if (!m3uState.hasEmittedDoneWithTracks()) {
|
|
22
|
+
m3uState.setHasEmittedDoneWithTracks();
|
|
23
|
+
onDoneWithTracks();
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
onAudioTrack: async ({ track }) => {
|
|
28
|
+
const callbackOrFalse = m3uState.hasEmittedAudioTrack();
|
|
29
|
+
if (callbackOrFalse === false) {
|
|
30
|
+
const callback = await onAudioTrack(track);
|
|
31
|
+
if (!callback) {
|
|
32
|
+
m3uState.setHasEmittedAudioTrack(null);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
m3uState.setHasEmittedAudioTrack(callback);
|
|
36
|
+
return (sample) => {
|
|
37
|
+
return callback(sample);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return callbackOrFalse;
|
|
41
|
+
},
|
|
42
|
+
onVideoTrack: async ({ track }) => {
|
|
43
|
+
const callbackOrFalse = m3uState.hasEmittedVideoTrack();
|
|
44
|
+
if (callbackOrFalse === false) {
|
|
45
|
+
const callback = await onVideoTrack(track);
|
|
46
|
+
if (!callback) {
|
|
47
|
+
m3uState.setHasEmittedVideoTrack(null);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
m3uState.setHasEmittedVideoTrack(callback);
|
|
51
|
+
return (sample) => {
|
|
52
|
+
return callback(sample);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return callbackOrFalse;
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
m3uState.setLastChunkProcessed(chunkIndex);
|
|
59
|
+
if (isLastChunk) {
|
|
60
|
+
m3uState.setAllChunksProcessed();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
exports.iteratorOverTsFiles = iteratorOverTsFiles;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { M3uStream } from './get-streams';
|
|
2
|
+
export type StreamSelectionFnOptions = {
|
|
3
|
+
streams: M3uStream[];
|
|
4
|
+
};
|
|
5
|
+
export type StreamSelectionFn = (options: StreamSelectionFnOptions) => number | Promise<number>;
|
|
6
|
+
export declare const selectStream: ({ streams, fn, }: {
|
|
7
|
+
streams: M3uStream[];
|
|
8
|
+
fn: StreamSelectionFn;
|
|
9
|
+
}) => Promise<M3uStream>;
|
|
10
|
+
export declare const defaultStreamSelectionFn: StreamSelectionFn;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultStreamSelectionFn = exports.selectStream = void 0;
|
|
4
|
+
const selectStream = async ({ streams, fn, }) => {
|
|
5
|
+
if (streams.length < 1) {
|
|
6
|
+
throw new Error('No streams found');
|
|
7
|
+
}
|
|
8
|
+
const selectedStream = await fn({ streams });
|
|
9
|
+
return Promise.resolve(streams[selectedStream]);
|
|
10
|
+
};
|
|
11
|
+
exports.selectStream = selectStream;
|
|
12
|
+
const defaultStreamSelectionFn = ({ streams }) => {
|
|
13
|
+
return Promise.resolve(streams[0].id);
|
|
14
|
+
};
|
|
15
|
+
exports.defaultStreamSelectionFn = defaultStreamSelectionFn;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type M3uHeader = {
|
|
2
|
+
type: 'm3u-header';
|
|
3
|
+
};
|
|
4
|
+
export type M3uVersion = {
|
|
5
|
+
type: 'm3u-version';
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
export type M3uIndependentSegments = {
|
|
9
|
+
type: 'm3u-independent-segments';
|
|
10
|
+
};
|
|
11
|
+
export type M3uTargetDuration = {
|
|
12
|
+
type: 'm3u-target-duration';
|
|
13
|
+
duration: number;
|
|
14
|
+
};
|
|
15
|
+
export type M3uPlaylistType = {
|
|
16
|
+
type: 'm3u-playlist-type';
|
|
17
|
+
playlistType: string;
|
|
18
|
+
};
|
|
19
|
+
export type M3uPlaylist = {
|
|
20
|
+
type: 'm3u-playlist';
|
|
21
|
+
boxes: M3uBox[];
|
|
22
|
+
};
|
|
23
|
+
export type M3uExtInf = {
|
|
24
|
+
type: 'm3u-extinf';
|
|
25
|
+
value: number;
|
|
26
|
+
};
|
|
27
|
+
export type M3uEndList = {
|
|
28
|
+
type: 'm3u-endlist';
|
|
29
|
+
};
|
|
30
|
+
export type M3uStreamInfo = {
|
|
31
|
+
type: 'm3u-stream-info';
|
|
32
|
+
bandwidth: number | null;
|
|
33
|
+
averageBandwidth: number | null;
|
|
34
|
+
codecs: string[] | null;
|
|
35
|
+
resolution: {
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
} | null;
|
|
39
|
+
};
|
|
40
|
+
export type M3uTextValue = {
|
|
41
|
+
type: 'm3u-text-value';
|
|
42
|
+
value: string;
|
|
43
|
+
};
|
|
44
|
+
export type M3uBox = M3uHeader | M3uPlaylist | M3uVersion | M3uIndependentSegments | M3uStreamInfo | M3uTargetDuration | M3uPlaylistType | M3uExtInf | M3uEndList | M3uTextValue;
|
|
45
|
+
export type M3uStructure = {
|
|
46
|
+
type: 'm3u';
|
|
47
|
+
boxes: M3uBox[];
|
|
48
|
+
};
|
|
@@ -31,7 +31,7 @@ const parseStreamInfo = async ({ iterator, state, }) => {
|
|
|
31
31
|
totalSamples,
|
|
32
32
|
};
|
|
33
33
|
state.getFlacStructure().boxes.push(flacStreamInfo);
|
|
34
|
-
await (0, register_track_1.
|
|
34
|
+
await (0, register_track_1.registerAudioTrack)({
|
|
35
35
|
container: 'flac',
|
|
36
36
|
state,
|
|
37
37
|
track: {
|
|
@@ -22,13 +22,13 @@ const getMoovAtom = async ({ endOfMdat, state, }) => {
|
|
|
22
22
|
},
|
|
23
23
|
onAudioTrack: state.onAudioTrack
|
|
24
24
|
? async ({ track, container }) => {
|
|
25
|
-
await (0, register_track_1.
|
|
25
|
+
await (0, register_track_1.registerAudioTrack)({ state, track, container });
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
: null,
|
|
29
29
|
onVideoTrack: state.onVideoTrack
|
|
30
30
|
? async ({ track, container }) => {
|
|
31
|
-
await (0, register_track_1.
|
|
31
|
+
await (0, register_track_1.registerVideoTrack)({ state, track, container });
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
34
|
: null,
|
|
@@ -38,6 +38,7 @@ const getMoovAtom = async ({ endOfMdat, state, }) => {
|
|
|
38
38
|
readerInterface: state.readerInterface,
|
|
39
39
|
src: state.src,
|
|
40
40
|
onDiscardedData: null,
|
|
41
|
+
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
41
42
|
});
|
|
42
43
|
while (true) {
|
|
43
44
|
const result = await reader.reader.read();
|
|
@@ -181,8 +181,15 @@ const processBox = async (state) => {
|
|
|
181
181
|
state,
|
|
182
182
|
});
|
|
183
183
|
const transformedTrack = (0, make_track_1.makeBaseMediaTrack)(box);
|
|
184
|
-
if (transformedTrack) {
|
|
185
|
-
await (0, register_track_1.
|
|
184
|
+
if (transformedTrack && transformedTrack.type === 'video') {
|
|
185
|
+
await (0, register_track_1.registerVideoTrack)({
|
|
186
|
+
state,
|
|
187
|
+
track: transformedTrack,
|
|
188
|
+
container: 'mp4',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (transformedTrack && transformedTrack.type === 'audio') {
|
|
192
|
+
await (0, register_track_1.registerAudioTrack)({
|
|
186
193
|
state,
|
|
187
194
|
track: transformedTrack,
|
|
188
195
|
container: 'mp4',
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseTrun = void 0;
|
|
4
4
|
const parseTrun = ({ iterator, offset, size, }) => {
|
|
5
5
|
const version = iterator.getUint8();
|
|
6
|
-
if (version !== 0) {
|
|
6
|
+
if (version !== 0 && version !== 1) {
|
|
7
7
|
throw new Error(`Unsupported TRUN version ${version}`);
|
|
8
8
|
}
|
|
9
9
|
const flags = iterator.getUint24();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { M3uState } from '../../state/m3u-state';
|
|
2
|
+
import type { ParserState } from '../../state/parser-state';
|
|
3
|
+
import type { SelectM3uStreamFn } from './select-stream';
|
|
4
|
+
import type { M3uStructure } from './types';
|
|
5
|
+
export declare const afterManifestFetch: ({ structure, m3uState, src, selectM3uStreamFn, }: {
|
|
6
|
+
structure: M3uStructure;
|
|
7
|
+
m3uState: M3uState;
|
|
8
|
+
src: string | null;
|
|
9
|
+
selectM3uStreamFn: SelectM3uStreamFn;
|
|
10
|
+
}) => Promise<void>;
|
|
11
|
+
export declare const runOverM3u: ({ state, structure, }: {
|
|
12
|
+
state: ParserState;
|
|
13
|
+
structure: M3uStructure;
|
|
14
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runOverM3u = exports.afterManifestFetch = void 0;
|
|
4
|
+
const register_track_1 = require("../../register-track");
|
|
5
|
+
const fetch_m3u8_stream_1 = require("./fetch-m3u8-stream");
|
|
6
|
+
const get_streams_1 = require("./get-streams");
|
|
7
|
+
const return_packets_1 = require("./return-packets");
|
|
8
|
+
const select_stream_1 = require("./select-stream");
|
|
9
|
+
const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn, }) => {
|
|
10
|
+
const independentSegments = (0, get_streams_1.isIndependentSegments)(structure);
|
|
11
|
+
if (!independentSegments) {
|
|
12
|
+
if (!src) {
|
|
13
|
+
throw new Error('No src');
|
|
14
|
+
}
|
|
15
|
+
m3uState.setSelectedStream({
|
|
16
|
+
type: 'initial-url',
|
|
17
|
+
url: src,
|
|
18
|
+
});
|
|
19
|
+
return m3uState.setReadyToIterateOverM3u();
|
|
20
|
+
}
|
|
21
|
+
const streams = (0, get_streams_1.getM3uStreams)(structure, src);
|
|
22
|
+
if (streams === null) {
|
|
23
|
+
throw new Error('No streams found');
|
|
24
|
+
}
|
|
25
|
+
const selectedStream = await (0, select_stream_1.selectStream)({ streams, fn: selectM3uStreamFn });
|
|
26
|
+
m3uState.setSelectedStream({ type: 'selected-stream', stream: selectedStream });
|
|
27
|
+
if (!selectedStream.resolution) {
|
|
28
|
+
throw new Error('Stream does not have a resolution');
|
|
29
|
+
}
|
|
30
|
+
const boxes = await (0, fetch_m3u8_stream_1.fetchM3u8Stream)(selectedStream);
|
|
31
|
+
structure.boxes.push({ type: 'm3u-playlist', boxes });
|
|
32
|
+
m3uState.setReadyToIterateOverM3u();
|
|
33
|
+
};
|
|
34
|
+
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;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchM3u8Stream = void 0;
|
|
4
|
+
const parse_m3u8_text_1 = require("./parse-m3u8-text");
|
|
5
|
+
const fetchM3u8Stream = async (stream) => {
|
|
6
|
+
const res = await fetch(stream.url);
|
|
7
|
+
if (!res.ok) {
|
|
8
|
+
throw new Error(`Failed to fetch ${stream.url} (HTTP code: ${res.status})`);
|
|
9
|
+
}
|
|
10
|
+
const text = await res.text();
|
|
11
|
+
const lines = text.split('\n');
|
|
12
|
+
const boxes = [];
|
|
13
|
+
for (const line of lines) {
|
|
14
|
+
(0, parse_m3u8_text_1.parseM3u8Text)(line, boxes);
|
|
15
|
+
}
|
|
16
|
+
return boxes;
|
|
17
|
+
};
|
|
18
|
+
exports.fetchM3u8Stream = fetchM3u8Stream;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getChunks = void 0;
|
|
4
|
+
const getChunks = (playlist) => {
|
|
5
|
+
const chunks = [];
|
|
6
|
+
for (let i = 0; i < playlist.boxes.length; i++) {
|
|
7
|
+
const box = playlist.boxes[i];
|
|
8
|
+
if (box.type === 'm3u-extinf') {
|
|
9
|
+
const nextBox = playlist.boxes[i + 1];
|
|
10
|
+
i++;
|
|
11
|
+
if (nextBox.type !== 'm3u-text-value') {
|
|
12
|
+
throw new Error('Expected m3u-text-value');
|
|
13
|
+
}
|
|
14
|
+
chunks.push({ duration: box.value, url: nextBox.value });
|
|
15
|
+
}
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
return chunks;
|
|
19
|
+
};
|
|
20
|
+
exports.getChunks = getChunks;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDurationFromM3u = void 0;
|
|
4
|
+
const get_playlist_1 = require("./get-playlist");
|
|
5
|
+
const getDurationFromM3u = (structure) => {
|
|
6
|
+
const playlist = (0, get_playlist_1.getPlaylist)(structure);
|
|
7
|
+
return (0, get_playlist_1.getDurationFromPlaylist)(playlist);
|
|
8
|
+
};
|
|
9
|
+
exports.getDurationFromM3u = getDurationFromM3u;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDurationFromPlaylist = exports.getPlaylist = void 0;
|
|
4
|
+
const get_streams_1 = require("./get-streams");
|
|
5
|
+
const getPlaylist = (structure) => {
|
|
6
|
+
const isIndependent = (0, get_streams_1.isIndependentSegments)(structure);
|
|
7
|
+
if (!isIndependent) {
|
|
8
|
+
return {
|
|
9
|
+
type: 'm3u-playlist',
|
|
10
|
+
boxes: structure.boxes,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const playlists = structure.boxes.filter((box) => box.type === 'm3u-playlist');
|
|
14
|
+
if (playlists.length !== 1) {
|
|
15
|
+
throw new Error('Expected one playlist');
|
|
16
|
+
}
|
|
17
|
+
return playlists[0];
|
|
18
|
+
};
|
|
19
|
+
exports.getPlaylist = getPlaylist;
|
|
20
|
+
const getDurationFromPlaylist = (playlist) => {
|
|
21
|
+
const duration = playlist.boxes.filter((box) => box.type === 'm3u-extinf');
|
|
22
|
+
if (duration.length === 0) {
|
|
23
|
+
throw new Error('Expected duration in m3u playlist');
|
|
24
|
+
}
|
|
25
|
+
return duration.reduce((acc, d) => acc + d.value, 0);
|
|
26
|
+
};
|
|
27
|
+
exports.getDurationFromPlaylist = getDurationFromPlaylist;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Dimensions } from '../../get-dimensions';
|
|
2
|
+
import type { Structure } from '../../parse-result';
|
|
3
|
+
import type { ParserState } from '../../state/parser-state';
|
|
4
|
+
export type M3uStream = {
|
|
5
|
+
url: string;
|
|
6
|
+
bandwidth: number | null;
|
|
7
|
+
averageBandwidth: number | null;
|
|
8
|
+
resolution: Dimensions | null;
|
|
9
|
+
codecs: string[] | null;
|
|
10
|
+
id: number;
|
|
11
|
+
};
|
|
12
|
+
export declare const isIndependentSegments: (structure: Structure | null) => boolean;
|
|
13
|
+
export declare const getM3uStreams: (structure: Structure | null, originalSrc: string | null) => M3uStream[] | null;
|
|
14
|
+
export declare const m3uHasStreams: (state: ParserState) => boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.m3uHasStreams = exports.getM3uStreams = exports.isIndependentSegments = void 0;
|
|
4
|
+
const isIndependentSegments = (structure) => {
|
|
5
|
+
if (structure === null || structure.type !== 'm3u') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
return structure.boxes.some((box) => box.type === 'm3u-independent-segments' || box.type === 'm3u-stream-info');
|
|
9
|
+
};
|
|
10
|
+
exports.isIndependentSegments = isIndependentSegments;
|
|
11
|
+
const getM3uStreams = (structure, originalSrc) => {
|
|
12
|
+
if (structure === null || structure.type !== 'm3u') {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const boxes = [];
|
|
16
|
+
for (let i = 0; i < structure.boxes.length; i++) {
|
|
17
|
+
const str = structure.boxes[i];
|
|
18
|
+
if (str.type === 'm3u-stream-info') {
|
|
19
|
+
const next = structure.boxes[i + 1];
|
|
20
|
+
if (next.type !== 'm3u-text-value') {
|
|
21
|
+
throw new Error('Expected m3u-text-value');
|
|
22
|
+
}
|
|
23
|
+
boxes.push({
|
|
24
|
+
url: originalSrc && originalSrc.startsWith('http')
|
|
25
|
+
? new URL(next.value, originalSrc).href
|
|
26
|
+
: next.value,
|
|
27
|
+
averageBandwidth: str.averageBandwidth,
|
|
28
|
+
bandwidth: str.bandwidth,
|
|
29
|
+
codecs: str.codecs,
|
|
30
|
+
resolution: str.resolution,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Maybe this is already a playlist
|
|
35
|
+
if (boxes.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const sorted = boxes.slice().sort((a, b) => {
|
|
39
|
+
const aResolution = a.resolution
|
|
40
|
+
? a.resolution.width * a.resolution.height
|
|
41
|
+
: 0;
|
|
42
|
+
const bResolution = b.resolution
|
|
43
|
+
? b.resolution.width * b.resolution.height
|
|
44
|
+
: 0;
|
|
45
|
+
return bResolution - aResolution;
|
|
46
|
+
});
|
|
47
|
+
return sorted.map((box, index) => ({ ...box, id: index }));
|
|
48
|
+
};
|
|
49
|
+
exports.getM3uStreams = getM3uStreams;
|
|
50
|
+
const m3uHasStreams = (state) => {
|
|
51
|
+
const structure = state.getStructureOrNull();
|
|
52
|
+
if (!structure) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (structure.type !== 'm3u') {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return state.m3u.hasFinishedManifest();
|
|
59
|
+
};
|
|
60
|
+
exports.m3uHasStreams = m3uHasStreams;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseM3uDirective = void 0;
|
|
4
|
+
const parse_stream_inf_1 = require("./parse-stream-inf");
|
|
5
|
+
const parseM3uDirective = (str) => {
|
|
6
|
+
const firstColon = str.indexOf(':');
|
|
7
|
+
const directive = firstColon === -1 ? str : str.slice(0, firstColon);
|
|
8
|
+
const value = firstColon === -1 ? null : str.slice(firstColon + 1);
|
|
9
|
+
if (directive === '#EXT-X-VERSION') {
|
|
10
|
+
if (!value) {
|
|
11
|
+
throw new Error('EXT-X-VERSION directive must have a value');
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
type: 'm3u-version',
|
|
15
|
+
version: value,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (directive === '#EXT-X-INDEPENDENT-SEGMENTS') {
|
|
19
|
+
return {
|
|
20
|
+
type: 'm3u-independent-segments',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (directive === '#EXT-X-TARGETDURATION') {
|
|
24
|
+
if (!value) {
|
|
25
|
+
throw new Error('EXT-X-TARGETDURATION directive must have a value');
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
type: 'm3u-target-duration',
|
|
29
|
+
duration: parseFloat(value),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (directive === '#EXTINF') {
|
|
33
|
+
if (!value) {
|
|
34
|
+
throw new Error('EXTINF has no value');
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
type: 'm3u-extinf',
|
|
38
|
+
value: parseFloat(value),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (directive === '#EXT-X-ENDLIST') {
|
|
42
|
+
return {
|
|
43
|
+
type: 'm3u-endlist',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (directive === '#EXT-X-PLAYLIST-TYPE') {
|
|
47
|
+
if (!value) {
|
|
48
|
+
throw new Error('#EXT-X-PLAYLIST-TYPE. directive must have a value');
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
type: 'm3u-playlist-type',
|
|
52
|
+
playlistType: value,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (directive === '#EXT-X-STREAM-INF') {
|
|
56
|
+
if (!value) {
|
|
57
|
+
throw new Error('EXT-X-STREAM-INF directive must have a value');
|
|
58
|
+
}
|
|
59
|
+
const res = (0, parse_stream_inf_1.parseStreamInf)(value);
|
|
60
|
+
return res;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Unknown directive ${directive}. Value: ${value}`);
|
|
63
|
+
};
|
|
64
|
+
exports.parseM3uDirective = parseM3uDirective;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BufferIterator } from '../../buffer-iterator';
|
|
2
|
+
import type { ParseResult } from '../../parse-result';
|
|
3
|
+
import type { M3uStructure } from './types';
|
|
4
|
+
export declare const parseM3uManifest: ({ iterator, structure, contentLength, }: {
|
|
5
|
+
iterator: BufferIterator;
|
|
6
|
+
structure: M3uStructure;
|
|
7
|
+
contentLength: number;
|
|
8
|
+
}) => Promise<ParseResult>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseM3uManifest = void 0;
|
|
4
|
+
const parse_m3u8_text_1 = require("./parse-m3u8-text");
|
|
5
|
+
const parseM3uManifest = ({ iterator, structure, contentLength, }) => {
|
|
6
|
+
const start = iterator.startCheckpoint();
|
|
7
|
+
const line = iterator.readUntilLineEnd();
|
|
8
|
+
if (iterator.counter.getOffset() > contentLength) {
|
|
9
|
+
throw new Error('Unexpected end of file');
|
|
10
|
+
}
|
|
11
|
+
if (line === null) {
|
|
12
|
+
start.returnToCheckpoint();
|
|
13
|
+
return Promise.resolve(null);
|
|
14
|
+
}
|
|
15
|
+
(0, parse_m3u8_text_1.parseM3u8Text)(line, structure.boxes);
|
|
16
|
+
return Promise.resolve(null);
|
|
17
|
+
};
|
|
18
|
+
exports.parseM3uManifest = parseM3uManifest;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseM3u = void 0;
|
|
4
|
+
const after_manifest_fetch_1 = require("./after-manifest-fetch");
|
|
5
|
+
const parse_m3u_manifest_1 = require("./parse-m3u-manifest");
|
|
6
|
+
const parseM3u = async ({ state }) => {
|
|
7
|
+
const structure = state.getM3uStructure();
|
|
8
|
+
if (state.m3u.isReadyToIterateOverM3u()) {
|
|
9
|
+
await (0, after_manifest_fetch_1.runOverM3u)({
|
|
10
|
+
state,
|
|
11
|
+
structure,
|
|
12
|
+
});
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (state.m3u.hasFinishedManifest()) {
|
|
16
|
+
await (0, after_manifest_fetch_1.afterManifestFetch)({
|
|
17
|
+
structure,
|
|
18
|
+
m3uState: state.m3u,
|
|
19
|
+
src: typeof state.src === 'string' ? state.src : null,
|
|
20
|
+
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
21
|
+
});
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const box = await (0, parse_m3u_manifest_1.parseM3uManifest)({
|
|
25
|
+
iterator: state.iterator,
|
|
26
|
+
structure,
|
|
27
|
+
contentLength: state.contentLength,
|
|
28
|
+
});
|
|
29
|
+
const isDoneNow = state.iterator.counter.getOffset() === state.contentLength;
|
|
30
|
+
if (isDoneNow) {
|
|
31
|
+
state.m3u.setHasFinishedManifest();
|
|
32
|
+
}
|
|
33
|
+
return box;
|
|
34
|
+
};
|
|
35
|
+
exports.parseM3u = parseM3u;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseM3u8Text = void 0;
|
|
4
|
+
const parse_directive_1 = require("./parse-directive");
|
|
5
|
+
const parseM3u8Text = (line, boxes) => {
|
|
6
|
+
if (line === '#EXTM3U') {
|
|
7
|
+
boxes.push({
|
|
8
|
+
type: 'm3u-header',
|
|
9
|
+
});
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (line.startsWith('#')) {
|
|
13
|
+
boxes.push((0, parse_directive_1.parseM3uDirective)(line));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (line.trim()) {
|
|
17
|
+
boxes.push({
|
|
18
|
+
type: 'm3u-text-value',
|
|
19
|
+
value: line,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
exports.parseM3u8Text = parseM3u8Text;
|