@remotion/media-parser 4.0.248 → 4.0.250
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/boxes/avc/key.d.ts +1 -1
- package/dist/boxes/iso-base-media/continue-mdat-routine.d.ts +14 -0
- package/dist/boxes/iso-base-media/continue-mdat-routine.js +74 -0
- package/dist/boxes/iso-base-media/get-children.d.ts +8 -0
- package/dist/boxes/iso-base-media/get-children.js +23 -0
- package/dist/boxes/iso-base-media/mdat/mdat.d.ts +3 -22
- package/dist/boxes/iso-base-media/mdat/mdat.js +80 -121
- package/dist/boxes/iso-base-media/moov/moov.d.ts +1 -6
- package/dist/boxes/iso-base-media/moov/moov.js +5 -15
- package/dist/boxes/iso-base-media/parse-all-children.d.ts +8 -0
- package/dist/boxes/iso-base-media/parse-all-children.js +20 -0
- package/dist/boxes/iso-base-media/parse-boxes.d.ts +7 -0
- package/dist/boxes/iso-base-media/parse-boxes.js +46 -0
- package/dist/boxes/iso-base-media/parse-mdat-partially.d.ts +9 -0
- package/dist/boxes/iso-base-media/parse-mdat-partially.js +24 -0
- package/dist/boxes/iso-base-media/process-box.d.ts +2 -29
- package/dist/boxes/iso-base-media/process-box.js +56 -367
- package/dist/boxes/iso-base-media/stsd/mebx.d.ts +1 -4
- package/dist/boxes/iso-base-media/stsd/mebx.js +5 -15
- package/dist/boxes/iso-base-media/stsd/samples.d.ts +4 -12
- package/dist/boxes/iso-base-media/stsd/samples.js +24 -70
- package/dist/boxes/iso-base-media/stsd/stsd.d.ts +1 -4
- package/dist/boxes/iso-base-media/stsd/stsd.js +2 -5
- package/dist/boxes/iso-base-media/trak/trak.d.ts +1 -6
- package/dist/boxes/iso-base-media/trak/trak.js +5 -15
- package/dist/boxes/iso-base-media/traversal.d.ts +0 -2
- package/dist/boxes/iso-base-media/traversal.js +1 -12
- package/dist/boxes/mp3/get-duration.d.ts +2 -0
- package/dist/boxes/mp3/get-duration.js +30 -0
- package/dist/boxes/mp3/get-frame-length.d.ts +13 -0
- package/dist/boxes/mp3/get-frame-length.js +33 -0
- package/dist/boxes/mp3/get-metadata-from-mp3.d.ts +3 -0
- package/dist/boxes/mp3/get-metadata-from-mp3.js +8 -0
- package/dist/boxes/mp3/get-tracks-from-mp3.d.ts +4 -0
- package/dist/boxes/mp3/get-tracks-from-mp3.js +25 -0
- package/dist/boxes/mp3/id3-v1.d.ts +2 -0
- package/dist/boxes/mp3/id3-v1.js +12 -0
- package/dist/boxes/mp3/id3-v2.d.ts +0 -0
- package/dist/boxes/mp3/id3-v2.js +1 -0
- package/dist/boxes/mp3/id3.d.ts +6 -0
- package/dist/boxes/mp3/id3.js +80 -0
- package/dist/boxes/mp3/parse-mp3.d.ts +7 -0
- package/dist/boxes/mp3/parse-mp3.js +41 -0
- package/dist/boxes/mp3/parse-mpeg-header.d.ts +6 -0
- package/dist/boxes/mp3/parse-mpeg-header.js +274 -0
- package/dist/boxes/mp3/samples-per-mpeg-file.d.ts +4 -0
- package/dist/boxes/mp3/samples-per-mpeg-file.js +26 -0
- package/dist/boxes/riff/continue-after-riff-result.d.ts +13 -0
- package/dist/boxes/riff/continue-after-riff-result.js +34 -0
- package/dist/boxes/riff/expect-riff-box.d.ts +1 -7
- package/dist/boxes/riff/expect-riff-box.js +47 -24
- package/dist/boxes/riff/get-tracks-from-avi.d.ts +1 -1
- package/dist/boxes/riff/get-tracks-from-avi.js +6 -10
- package/dist/boxes/riff/parse-box.d.ts +1 -7
- package/dist/boxes/riff/parse-box.js +4 -120
- package/dist/boxes/riff/parse-fmt-box.d.ts +3 -2
- package/dist/boxes/riff/parse-fmt-box.js +7 -5
- package/dist/boxes/riff/parse-list-box.js +15 -14
- package/dist/boxes/riff/parse-movi.d.ts +2 -5
- package/dist/boxes/riff/parse-movi.js +34 -56
- package/dist/boxes/riff/parse-riff-body.d.ts +7 -0
- package/dist/boxes/riff/parse-riff-body.js +25 -0
- package/dist/boxes/riff/parse-riff-box.d.ts +1 -2
- package/dist/boxes/riff/parse-riff-box.js +2 -6
- package/dist/boxes/riff/parse-riff-header.d.ts +7 -0
- package/dist/boxes/riff/parse-riff-header.js +23 -0
- package/dist/boxes/riff/parse-riff.d.ts +7 -0
- package/dist/boxes/riff/parse-riff.js +15 -0
- package/dist/boxes/riff/parse-strf.d.ts +4 -4
- package/dist/boxes/riff/parse-strf.js +4 -8
- package/dist/boxes/riff/parse-strh.js +11 -0
- package/dist/boxes/riff/parse-video-section.d.ts +6 -0
- package/dist/boxes/riff/parse-video-section.js +20 -0
- package/dist/boxes/riff/riff-box.d.ts +4 -5
- package/dist/boxes/riff/traversal.d.ts +1 -2
- package/dist/boxes/riff/traversal.js +1 -6
- package/dist/boxes/transport-stream/get-tracks.d.ts +2 -3
- package/dist/boxes/transport-stream/get-tracks.js +4 -3
- package/dist/boxes/transport-stream/parse-packet.d.ts +1 -7
- package/dist/boxes/transport-stream/parse-packet.js +3 -4
- package/dist/boxes/transport-stream/parse-stream-packet.d.ts +1 -5
- package/dist/boxes/transport-stream/parse-stream-packet.js +10 -12
- package/dist/boxes/transport-stream/parse-transport-stream.d.ts +1 -7
- package/dist/boxes/transport-stream/parse-transport-stream.js +19 -49
- package/dist/boxes/transport-stream/process-stream-buffers.d.ts +1 -2
- package/dist/boxes/transport-stream/process-stream-buffers.js +3 -3
- package/dist/boxes/webm/parse-ebml.js +3 -0
- package/dist/boxes/webm/parse-webm-header.d.ts +2 -4
- package/dist/boxes/webm/parse-webm-header.js +41 -25
- package/dist/boxes/webm/segments/parse-children.d.ts +2 -16
- package/dist/boxes/webm/segments/parse-children.js +7 -130
- package/dist/boxes/webm/segments.d.ts +4 -8
- package/dist/boxes/webm/segments.js +41 -123
- package/dist/buffer-iterator.d.ts +6 -3
- package/dist/buffer-iterator.js +27 -16
- package/dist/bun-reader.d.ts +1 -0
- package/dist/bun-reader.js +17 -0
- package/dist/continue-mdat-routine.d.ts +17 -0
- package/dist/continue-mdat-routine.js +92 -0
- package/dist/emit-available-info.js +42 -28
- package/dist/esm/from-node.mjs +8 -9
- package/dist/esm/index.mjs +5133 -5085
- package/dist/file-types/detect-file-type.js +6 -2
- package/dist/get-audio-codec.d.ts +1 -1
- package/dist/get-audio-codec.js +3 -3
- package/dist/get-container.js +5 -1
- package/dist/get-dimensions.d.ts +1 -1
- package/dist/get-dimensions.js +4 -1
- package/dist/get-duration.js +6 -2
- package/dist/get-fields-from-callbacks.js +1 -0
- package/dist/get-fps.js +3 -0
- package/dist/get-is-hdr.d.ts +1 -1
- package/dist/get-is-hdr.js +3 -3
- package/dist/get-keyframes.js +1 -1
- package/dist/get-tracks.d.ts +2 -2
- package/dist/get-tracks.js +23 -15
- package/dist/get-video-codec.d.ts +1 -1
- package/dist/get-video-codec.js +3 -3
- package/dist/has-all-info.js +4 -3
- package/dist/index.d.ts +65 -21
- package/dist/index.js +1 -1
- package/dist/may-skip-video-data/may-skip-video-data.js +6 -2
- package/dist/may-skip-video-data/need-samples-for-fields.js +1 -0
- package/dist/metadata/get-metadata.d.ts +1 -0
- package/dist/metadata/get-metadata.js +16 -1
- package/dist/options.d.ts +12 -5
- package/dist/parse-media.js +88 -68
- package/dist/parse-result.d.ts +17 -19
- package/dist/parse-video.d.ts +3 -17
- package/dist/parse-video.js +52 -40
- package/dist/readers/from-node.js +7 -8
- package/dist/state/can-skip-tracks.d.ts +8 -1
- package/dist/state/can-skip-tracks.js +38 -26
- package/dist/state/emitted-fields.js +1 -0
- package/dist/state/images.d.ts +9 -0
- package/dist/state/images.js +14 -0
- package/dist/state/iso-base-media/cached-sample-positions.d.ts +15 -0
- package/dist/state/iso-base-media/cached-sample-positions.js +42 -0
- package/dist/state/iso-base-media/iso-state.d.ts +8 -0
- package/dist/state/iso-base-media/iso-state.js +15 -0
- package/dist/state/iso-state.d.ts +4 -0
- package/dist/state/iso-state.js +13 -0
- package/dist/state/mp3.d.ts +11 -0
- package/dist/state/mp3.js +13 -0
- package/dist/state/parser-state.d.ts +57 -11
- package/dist/state/parser-state.js +17 -2
- package/dist/state/sample-callbacks.d.ts +5 -1
- package/dist/state/sample-callbacks.js +8 -2
- package/dist/state/slow-duration-fps.d.ts +2 -1
- package/dist/state/slow-duration-fps.js +52 -18
- package/dist/state/transport-stream.d.ts +8 -0
- package/dist/state/transport-stream.js +11 -0
- package/dist/state/video-section.d.ts +16 -0
- package/dist/state/video-section.js +37 -0
- package/dist/state/webm.d.ts +15 -0
- package/dist/state/webm.js +32 -0
- package/dist/throttled-progress.d.ts +14 -0
- package/dist/throttled-progress.js +44 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/test.json +663 -0
package/dist/options.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { LogLevel } from './log';
|
|
|
5
5
|
import type { MetadataEntry } from './metadata/get-metadata';
|
|
6
6
|
import type { Structure } from './parse-result';
|
|
7
7
|
import type { ReaderInterface } from './readers/reader';
|
|
8
|
+
import type { MediaParserEmbeddedImage } from './state/images';
|
|
8
9
|
import type { InternalStats } from './state/parser-state';
|
|
9
10
|
import type { OnAudioTrack, OnVideoTrack } from './webcodec-sample-types';
|
|
10
11
|
export type KnownAudioCodecs = 'aac' | 'mp3' | 'aiff' | 'opus' | 'pcm' | 'vorbis' | 'unknown';
|
|
@@ -31,6 +32,7 @@ export type ParseMediaFields = {
|
|
|
31
32
|
keyframes: boolean;
|
|
32
33
|
slowKeyframes: boolean;
|
|
33
34
|
slowNumberOfFrames: boolean;
|
|
35
|
+
images: boolean;
|
|
34
36
|
};
|
|
35
37
|
export type AllParseMediaFields = {
|
|
36
38
|
dimensions: true;
|
|
@@ -55,6 +57,7 @@ export type AllParseMediaFields = {
|
|
|
55
57
|
mimeType: true;
|
|
56
58
|
keyframes: true;
|
|
57
59
|
slowKeyframes: true;
|
|
60
|
+
images: true;
|
|
58
61
|
};
|
|
59
62
|
export type AllOptions<Fields extends ParseMediaFields> = {
|
|
60
63
|
dimensions: Fields['dimensions'];
|
|
@@ -79,13 +82,14 @@ export type AllOptions<Fields extends ParseMediaFields> = {
|
|
|
79
82
|
keyframes: Fields['keyframes'];
|
|
80
83
|
slowKeyframes: Fields['slowKeyframes'];
|
|
81
84
|
slowNumberOfFrames: Fields['slowNumberOfFrames'];
|
|
85
|
+
images: Fields['images'];
|
|
82
86
|
};
|
|
83
87
|
export type Options<Fields extends ParseMediaFields> = Partial<AllOptions<Fields>>;
|
|
84
88
|
export type TracksField = {
|
|
85
89
|
videoTracks: VideoTrack[];
|
|
86
90
|
audioTracks: AudioTrack[];
|
|
87
91
|
};
|
|
88
|
-
export type ParseMediaContainer = 'mp4' | 'webm' | 'avi' | 'transport-stream';
|
|
92
|
+
export type ParseMediaContainer = 'mp4' | 'webm' | 'avi' | 'transport-stream' | 'mp3';
|
|
89
93
|
export type MediaParserKeyframe = {
|
|
90
94
|
positionInBytes: number;
|
|
91
95
|
sizeInBytes: number;
|
|
@@ -94,7 +98,7 @@ export type MediaParserKeyframe = {
|
|
|
94
98
|
trackId: number;
|
|
95
99
|
};
|
|
96
100
|
export interface ParseMediaCallbacks {
|
|
97
|
-
onDimensions?: (dimensions: Dimensions) => void;
|
|
101
|
+
onDimensions?: (dimensions: Dimensions | null) => void;
|
|
98
102
|
onDurationInSeconds?: (durationInSeconds: number | null) => void;
|
|
99
103
|
onSlowDurationInSeconds?: (durationInSeconds: number) => void;
|
|
100
104
|
onSlowFps?: (fps: number) => void;
|
|
@@ -104,7 +108,7 @@ export interface ParseMediaCallbacks {
|
|
|
104
108
|
onAudioCodec?: (codec: MediaParserAudioCodec | null) => void;
|
|
105
109
|
onTracks?: (tracks: TracksField) => void;
|
|
106
110
|
onRotation?: (rotation: number | null) => void;
|
|
107
|
-
onUnrotatedDimensions?: (dimensions: Dimensions) => void;
|
|
111
|
+
onUnrotatedDimensions?: (dimensions: Dimensions | null) => void;
|
|
108
112
|
onInternalStats?: (internalStats: InternalStats) => void;
|
|
109
113
|
onSize?: (size: number | null) => void;
|
|
110
114
|
onName?: (name: string) => void;
|
|
@@ -116,9 +120,10 @@ export interface ParseMediaCallbacks {
|
|
|
116
120
|
onKeyframes?: (keyframes: MediaParserKeyframe[] | null) => void;
|
|
117
121
|
onSlowKeyframes?: (keyframes: MediaParserKeyframe[]) => void;
|
|
118
122
|
onSlowNumberOfFrames?: (samples: number) => void;
|
|
123
|
+
onImages?: (images: MediaParserEmbeddedImage[]) => void;
|
|
119
124
|
}
|
|
120
125
|
export interface ParseMediaData {
|
|
121
|
-
dimensions: Dimensions;
|
|
126
|
+
dimensions: Dimensions | null;
|
|
122
127
|
durationInSeconds: number | null;
|
|
123
128
|
slowDurationInSeconds: number;
|
|
124
129
|
slowFps: number;
|
|
@@ -128,7 +133,7 @@ export interface ParseMediaData {
|
|
|
128
133
|
audioCodec: MediaParserAudioCodec | null;
|
|
129
134
|
tracks: TracksField;
|
|
130
135
|
rotation: number | null;
|
|
131
|
-
unrotatedDimensions: Dimensions;
|
|
136
|
+
unrotatedDimensions: Dimensions | null;
|
|
132
137
|
isHdr: boolean;
|
|
133
138
|
internalStats: InternalStats;
|
|
134
139
|
size: number | null;
|
|
@@ -140,6 +145,7 @@ export interface ParseMediaData {
|
|
|
140
145
|
keyframes: MediaParserKeyframe[] | null;
|
|
141
146
|
slowKeyframes: MediaParserKeyframe[];
|
|
142
147
|
slowNumberOfFrames: number;
|
|
148
|
+
images: MediaParserEmbeddedImage[];
|
|
143
149
|
}
|
|
144
150
|
export type ParseMediaResult<T extends Partial<ParseMediaFields>> = {
|
|
145
151
|
[K in keyof T]: T[K] extends true ? K extends keyof ParseMediaData ? ParseMediaData[K] : never : never;
|
|
@@ -161,5 +167,6 @@ export type ParseMediaOptions<F extends Options<ParseMediaFields>> = {
|
|
|
161
167
|
signal?: AbortSignal;
|
|
162
168
|
logLevel?: LogLevel;
|
|
163
169
|
onParseProgress?: ParseMediaOnProgress;
|
|
170
|
+
progressIntervalInMs?: number;
|
|
164
171
|
} & ParseMediaDynamicOptions<F>;
|
|
165
172
|
export type ParseMedia = <F extends Options<ParseMediaFields>>(options: ParseMediaOptions<F>) => Promise<ParseMediaResult<F>>;
|
package/dist/parse-media.js
CHANGED
|
@@ -9,8 +9,9 @@ const log_1 = require("./log");
|
|
|
9
9
|
const parse_video_1 = require("./parse-video");
|
|
10
10
|
const from_fetch_1 = require("./readers/from-fetch");
|
|
11
11
|
const parser_state_1 = require("./state/parser-state");
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const throttled_progress_1 = require("./throttled-progress");
|
|
13
|
+
const parseMedia = async function ({ src, fields: _fieldsInReturnValue, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, signal, logLevel = 'info', onParseProgress: onParseProgressDoNotCallDirectly, progressIntervalInMs, ...more }) {
|
|
14
|
+
var _a;
|
|
14
15
|
let parseResult = null;
|
|
15
16
|
const fieldsInReturnValue = _fieldsInReturnValue !== null && _fieldsInReturnValue !== void 0 ? _fieldsInReturnValue : {};
|
|
16
17
|
const fields = (0, get_fields_from_callbacks_1.getFieldsFromCallback)({
|
|
@@ -18,6 +19,10 @@ const parseMedia = async function ({ src, fields: _fieldsInReturnValue, reader:
|
|
|
18
19
|
callbacks: more,
|
|
19
20
|
});
|
|
20
21
|
const { reader, contentLength, name, contentType, supportsContentRange: readerSupportsContentRange, } = await readerInterface.read(src, null, signal);
|
|
22
|
+
const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(new Uint8Array([]), contentLength !== null && contentLength !== void 0 ? contentLength : 1000000000);
|
|
23
|
+
if (contentLength === null) {
|
|
24
|
+
throw new Error('Media was passed with no content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.');
|
|
25
|
+
}
|
|
21
26
|
const supportsContentRange = readerSupportsContentRange &&
|
|
22
27
|
!(typeof process !== 'undefined' &&
|
|
23
28
|
typeof process.env !== 'undefined' &&
|
|
@@ -31,10 +36,18 @@ const parseMedia = async function ({ src, fields: _fieldsInReturnValue, reader:
|
|
|
31
36
|
onAudioTrack: onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : null,
|
|
32
37
|
onVideoTrack: onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : null,
|
|
33
38
|
supportsContentRange,
|
|
39
|
+
contentLength,
|
|
40
|
+
logLevel,
|
|
34
41
|
});
|
|
35
42
|
let currentReader = reader;
|
|
36
43
|
const returnValue = {};
|
|
37
44
|
const moreFields = more;
|
|
45
|
+
const throttledState = (0, throttled_progress_1.throttledStateUpdate)({
|
|
46
|
+
updateFn: onParseProgressDoNotCallDirectly !== null && onParseProgressDoNotCallDirectly !== void 0 ? onParseProgressDoNotCallDirectly : null,
|
|
47
|
+
everyMilliseconds: progressIntervalInMs !== null && progressIntervalInMs !== void 0 ? progressIntervalInMs : 100,
|
|
48
|
+
signal,
|
|
49
|
+
totalBytes: contentLength,
|
|
50
|
+
});
|
|
38
51
|
const triggerInfoEmit = () => {
|
|
39
52
|
const availableInfo = (0, has_all_info_1.getAvailableInfo)({
|
|
40
53
|
fieldsToFetch: fields,
|
|
@@ -52,35 +65,44 @@ const parseMedia = async function ({ src, fields: _fieldsInReturnValue, reader:
|
|
|
52
65
|
mimeType: contentType,
|
|
53
66
|
});
|
|
54
67
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
const checkIfDone = () => {
|
|
69
|
+
if ((0, has_all_info_1.hasAllInfo)({
|
|
70
|
+
fields,
|
|
71
|
+
state,
|
|
72
|
+
})) {
|
|
73
|
+
log_1.Log.verbose(logLevel, 'Got all info, skipping to the end.');
|
|
74
|
+
if (contentLength !== null) {
|
|
75
|
+
state.increaseSkippedBytes(contentLength - iterator.counter.getOffset());
|
|
60
76
|
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (iterator.counter.getOffset() === contentLength) {
|
|
80
|
+
log_1.Log.verbose(logLevel, 'Reached end of file');
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
};
|
|
85
|
+
triggerInfoEmit();
|
|
86
|
+
let iterationWithThisOffset = 0;
|
|
87
|
+
while (!checkIfDone()) {
|
|
88
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
89
|
+
throw new Error('Aborted');
|
|
90
|
+
}
|
|
91
|
+
const offsetBefore = iterator.counter.getOffset();
|
|
92
|
+
const fetchMoreData = async () => {
|
|
61
93
|
const result = await currentReader.reader.read();
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
iterator.addData(result.value);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
if (result.done) {
|
|
69
|
-
throw new Error('Unexpectedly reached EOF');
|
|
70
|
-
}
|
|
71
|
-
iterator = (0, buffer_iterator_1.getArrayBufferIterator)(result.value, contentLength !== null && contentLength !== void 0 ? contentLength : 1000000000);
|
|
72
|
-
}
|
|
73
|
-
if (iterator.bytesRemaining() >= 0) {
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
if (result.done) {
|
|
77
|
-
break;
|
|
94
|
+
if (result.value) {
|
|
95
|
+
iterator.addData(result.value);
|
|
78
96
|
}
|
|
97
|
+
};
|
|
98
|
+
while (iterator.bytesRemaining() < 0) {
|
|
99
|
+
await fetchMoreData();
|
|
79
100
|
}
|
|
80
|
-
|
|
81
|
-
|
|
101
|
+
const hasBigBuffer = iterator.bytesRemaining() > 100000;
|
|
102
|
+
if (iterationWithThisOffset > 0 || !hasBigBuffer) {
|
|
103
|
+
await fetchMoreData();
|
|
82
104
|
}
|
|
83
|
-
|
|
105
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, () => ({
|
|
84
106
|
bytes: iterator.counter.getOffset(),
|
|
85
107
|
percentage: contentLength
|
|
86
108
|
? iterator.counter.getOffset() / contentLength
|
|
@@ -88,60 +110,58 @@ const parseMedia = async function ({ src, fields: _fieldsInReturnValue, reader:
|
|
|
88
110
|
totalBytes: contentLength,
|
|
89
111
|
}));
|
|
90
112
|
triggerInfoEmit();
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
parseResult = await parseResult.continueParsing();
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
parseResult = await (0, parse_video_1.parseVideo)({
|
|
97
|
-
iterator,
|
|
98
|
-
state,
|
|
99
|
-
signal: signal !== null && signal !== void 0 ? signal : null,
|
|
100
|
-
logLevel,
|
|
101
|
-
fields,
|
|
102
|
-
mimeType: contentType,
|
|
103
|
-
contentLength,
|
|
104
|
-
name,
|
|
105
|
-
});
|
|
113
|
+
if (iterationWithThisOffset > 300) {
|
|
114
|
+
throw new Error('Infinite loop detected. The parser is not progressing. This is likely a bug in the parser.');
|
|
106
115
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if ((0, has_all_info_1.hasAllInfo)({
|
|
111
|
-
fields,
|
|
116
|
+
log_1.Log.trace(logLevel, `Continuing parsing of file, currently at position ${iterator.counter.getOffset()}/${contentLength}`);
|
|
117
|
+
parseResult = await (0, parse_video_1.parseVideo)({
|
|
118
|
+
iterator,
|
|
112
119
|
state,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
mimeType: contentType,
|
|
121
|
+
contentLength,
|
|
122
|
+
name,
|
|
123
|
+
});
|
|
124
|
+
if (parseResult.skipTo !== null) {
|
|
125
|
+
state.increaseSkippedBytes(parseResult.skipTo - iterator.counter.getOffset());
|
|
119
126
|
}
|
|
120
|
-
if (parseResult.
|
|
121
|
-
if (!supportsContentRange) {
|
|
122
|
-
throw new Error('Content-Range header is not supported by the reader, but was asked to seek');
|
|
123
|
-
}
|
|
127
|
+
if (parseResult.skipTo !== null) {
|
|
124
128
|
if (parseResult.skipTo === contentLength) {
|
|
125
129
|
log_1.Log.verbose(logLevel, 'Skipped to end of file, not fetching.');
|
|
126
130
|
break;
|
|
127
131
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
const skippingAhead = parseResult.skipTo > iterator.counter.getOffset();
|
|
133
|
+
if (!skippingAhead && !supportsContentRange) {
|
|
134
|
+
throw new Error('Content-Range header is not supported by the reader, but was asked to seek');
|
|
135
|
+
}
|
|
136
|
+
if (skippingAhead &&
|
|
137
|
+
iterator.counter.getOffset() + iterator.bytesRemaining() >=
|
|
138
|
+
parseResult.skipTo) {
|
|
139
|
+
log_1.Log.verbose(logLevel, `Skipping over video data from position ${iterator.counter.getOffset()} -> ${parseResult.skipTo}. Data already fetched`);
|
|
140
|
+
iterator.discard(parseResult.skipTo - iterator.counter.getOffset());
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
log_1.Log.verbose(logLevel, `Skipping over video data from position ${iterator.counter.getOffset()} -> ${parseResult.skipTo}. Re-reading because this portion is not available`);
|
|
144
|
+
currentReader.abort();
|
|
145
|
+
const { reader: newReader } = await readerInterface.read(src, parseResult.skipTo, signal);
|
|
146
|
+
currentReader = newReader;
|
|
147
|
+
iterator.skipTo(parseResult.skipTo, true);
|
|
148
|
+
}
|
|
133
149
|
}
|
|
150
|
+
const didProgress = iterator.counter.getOffset() > offsetBefore;
|
|
151
|
+
if (!didProgress) {
|
|
152
|
+
iterationWithThisOffset++;
|
|
153
|
+
}
|
|
154
|
+
iterator.removeBytesRead();
|
|
134
155
|
}
|
|
135
156
|
log_1.Log.verbose(logLevel, 'Finished parsing file');
|
|
136
|
-
const hasInfo = Object.keys(fields).reduce((acc, key) => {
|
|
137
|
-
if (fields === null || fields === void 0 ? void 0 : fields[key]) {
|
|
138
|
-
acc[key] = true;
|
|
139
|
-
}
|
|
140
|
-
return acc;
|
|
141
|
-
}, {});
|
|
142
157
|
// Force assign
|
|
143
158
|
(0, emit_available_info_1.emitAvailableInfo)({
|
|
144
|
-
hasInfo,
|
|
159
|
+
hasInfo: Object.keys(fields).reduce((acc, key) => {
|
|
160
|
+
if (fields === null || fields === void 0 ? void 0 : fields[key]) {
|
|
161
|
+
acc[key] = true;
|
|
162
|
+
}
|
|
163
|
+
return acc;
|
|
164
|
+
}, {}),
|
|
145
165
|
callbacks: moreFields,
|
|
146
166
|
fieldsInReturnValue,
|
|
147
167
|
parseResult,
|
package/dist/parse-result.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { BaseBox } from './boxes/iso-base-media/base-type';
|
|
2
2
|
import type { EsdsBox } from './boxes/iso-base-media/esds/esds';
|
|
3
3
|
import type { FtypBox } from './boxes/iso-base-media/ftyp';
|
|
4
|
-
import type { MdatBox } from './boxes/iso-base-media/mdat/mdat';
|
|
5
4
|
import type { MdhdBox } from './boxes/iso-base-media/mdhd';
|
|
6
5
|
import type { HdlrBox } from './boxes/iso-base-media/meta/hdlr';
|
|
7
6
|
import type { IlstBox } from './boxes/iso-base-media/meta/ilst';
|
|
@@ -30,6 +29,7 @@ import type { VoidBox } from './boxes/iso-base-media/void-box';
|
|
|
30
29
|
import type { RiffBox } from './boxes/riff/riff-box';
|
|
31
30
|
import type { TransportStreamBox } from './boxes/transport-stream/boxes';
|
|
32
31
|
import type { MatroskaSegment } from './boxes/webm/segments';
|
|
32
|
+
import type { MetadataEntry } from './metadata/get-metadata';
|
|
33
33
|
export interface RegularBox extends BaseBox {
|
|
34
34
|
boxType: string;
|
|
35
35
|
boxSize: number;
|
|
@@ -37,7 +37,16 @@ export interface RegularBox extends BaseBox {
|
|
|
37
37
|
offset: number;
|
|
38
38
|
type: 'regular-box';
|
|
39
39
|
}
|
|
40
|
-
export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox | IlstBox | EsdsBox |
|
|
40
|
+
export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox | IlstBox | EsdsBox | StszBox | StcoBox | StscBox | AvccBox | HvccBox | VoidBox | StssBox | PaspBox | CttsBox | Av1CBox | TrunBox | HdlrBox | ColorParameterBox | TfdtBox | TfhdBox;
|
|
41
|
+
type Mp3Id3Header = {
|
|
42
|
+
type: 'id3-header';
|
|
43
|
+
versionMajor: number;
|
|
44
|
+
versionMinor: number;
|
|
45
|
+
flags: number;
|
|
46
|
+
size: number;
|
|
47
|
+
metatags: MetadataEntry[];
|
|
48
|
+
};
|
|
49
|
+
export type Mp3Box = Mp3Id3Header;
|
|
41
50
|
export type AnySegment = MatroskaSegment | IsoBaseMediaBox | RiffBox | TransportStreamBox;
|
|
42
51
|
export type IsoBaseMediaStructure = {
|
|
43
52
|
type: 'iso-base-media';
|
|
@@ -55,26 +64,15 @@ export type TransportStreamStructure = {
|
|
|
55
64
|
type: 'transport-stream';
|
|
56
65
|
boxes: TransportStreamBox[];
|
|
57
66
|
};
|
|
58
|
-
export type
|
|
67
|
+
export type Mp3Structure = {
|
|
68
|
+
type: 'mp3';
|
|
69
|
+
boxes: Mp3Box[];
|
|
70
|
+
};
|
|
71
|
+
export type Structure = IsoBaseMediaStructure | RiffStructure | MatroskaStructure | TransportStreamStructure | Mp3Structure;
|
|
59
72
|
export type ParseResult = {
|
|
60
|
-
status: 'done';
|
|
61
|
-
} | {
|
|
62
|
-
status: 'incomplete';
|
|
63
73
|
skipTo: number | null;
|
|
64
|
-
continueParsing: () => Promise<ParseResult>;
|
|
65
74
|
};
|
|
66
75
|
export type MatroskaParseResult = {
|
|
67
|
-
status: 'done';
|
|
68
|
-
} | {
|
|
69
|
-
status: 'incomplete';
|
|
70
76
|
skipTo: number | null;
|
|
71
|
-
continueParsing: () => Promise<MatroskaParseResult>;
|
|
72
|
-
};
|
|
73
|
-
export type ExpectSegmentParseResult = {
|
|
74
|
-
status: 'done';
|
|
75
|
-
segment: MatroskaSegment;
|
|
76
|
-
} | {
|
|
77
|
-
status: 'incomplete';
|
|
78
|
-
segment: MatroskaSegment | null;
|
|
79
|
-
continueParsing: () => Promise<ExpectSegmentParseResult>;
|
|
80
77
|
};
|
|
78
|
+
export {};
|
package/dist/parse-video.d.ts
CHANGED
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
import type { BufferIterator } from './buffer-iterator';
|
|
2
|
-
import { type LogLevel } from './log';
|
|
3
|
-
import type { Options, ParseMediaFields } from './options';
|
|
4
2
|
import type { IsoBaseMediaBox, ParseResult } from './parse-result';
|
|
5
3
|
import type { ParserState } from './state/parser-state';
|
|
6
|
-
export type PartialMdatBox = {
|
|
7
|
-
type: 'partial-mdat-box';
|
|
8
|
-
boxSize: number;
|
|
9
|
-
fileOffset: number;
|
|
10
|
-
};
|
|
11
4
|
export type BoxAndNext = {
|
|
12
|
-
|
|
13
|
-
box: IsoBaseMediaBox;
|
|
14
|
-
size: number;
|
|
5
|
+
box: IsoBaseMediaBox | null;
|
|
15
6
|
skipTo: number | null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
} | PartialMdatBox;
|
|
19
|
-
export declare const parseVideo: ({ iterator, state, signal, logLevel, fields, mimeType, contentLength, name, }: {
|
|
7
|
+
};
|
|
8
|
+
export declare const parseVideo: ({ iterator, state, mimeType, contentLength, name, }: {
|
|
20
9
|
iterator: BufferIterator;
|
|
21
10
|
state: ParserState;
|
|
22
|
-
signal: AbortSignal | null;
|
|
23
|
-
logLevel: LogLevel;
|
|
24
|
-
fields: Options<ParseMediaFields>;
|
|
25
11
|
mimeType: string | null;
|
|
26
12
|
contentLength: number | null;
|
|
27
13
|
name: string | null;
|
package/dist/parse-video.js
CHANGED
|
@@ -1,75 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseVideo = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const parse_boxes_1 = require("./boxes/iso-base-media/parse-boxes");
|
|
5
|
+
const parse_mp3_1 = require("./boxes/mp3/parse-mp3");
|
|
6
|
+
const parse_riff_1 = require("./boxes/riff/parse-riff");
|
|
7
7
|
const parse_transport_stream_1 = require("./boxes/transport-stream/parse-transport-stream");
|
|
8
8
|
const parse_webm_header_1 = require("./boxes/webm/parse-webm-header");
|
|
9
9
|
const errors_1 = require("./errors");
|
|
10
10
|
const log_1 = require("./log");
|
|
11
|
-
const
|
|
12
|
-
if (iterator.bytesRemaining() === 0) {
|
|
13
|
-
return Promise.reject(new Error('no bytes'));
|
|
14
|
-
}
|
|
11
|
+
const initVideo = ({ iterator, state, mimeType, name, contentLength, }) => {
|
|
15
12
|
const fileType = iterator.detectFileType();
|
|
16
13
|
if (fileType.type === 'riff') {
|
|
17
|
-
log_1.Log.verbose(logLevel, 'Detected RIFF container');
|
|
14
|
+
log_1.Log.verbose(state.logLevel, 'Detected RIFF container');
|
|
18
15
|
state.structure.setStructure({
|
|
19
16
|
type: 'riff',
|
|
20
17
|
boxes: [],
|
|
21
18
|
});
|
|
22
|
-
return
|
|
19
|
+
return;
|
|
23
20
|
}
|
|
24
21
|
if (fileType.type === 'iso-base-media') {
|
|
25
|
-
log_1.Log.verbose(logLevel, 'Detected ISO Base Media container');
|
|
26
|
-
const initialBoxes = [];
|
|
22
|
+
log_1.Log.verbose(state.logLevel, 'Detected ISO Base Media container');
|
|
27
23
|
state.structure.setStructure({
|
|
28
24
|
type: 'iso-base-media',
|
|
29
|
-
boxes:
|
|
30
|
-
});
|
|
31
|
-
return (0, process_box_1.parseIsoBaseMediaBoxes)({
|
|
32
|
-
iterator,
|
|
33
|
-
maxBytes: Infinity,
|
|
34
|
-
allowIncompleteBoxes: true,
|
|
35
|
-
initialBoxes,
|
|
36
|
-
state,
|
|
37
|
-
continueMdat: false,
|
|
38
|
-
signal,
|
|
39
|
-
logLevel,
|
|
40
|
-
fields,
|
|
25
|
+
boxes: [],
|
|
41
26
|
});
|
|
27
|
+
return;
|
|
42
28
|
}
|
|
43
29
|
if (fileType.type === 'webm') {
|
|
44
|
-
log_1.Log.verbose(logLevel, 'Detected Matroska container');
|
|
30
|
+
log_1.Log.verbose(state.logLevel, 'Detected Matroska container');
|
|
45
31
|
state.structure.setStructure({
|
|
46
32
|
boxes: [],
|
|
47
33
|
type: 'matroska',
|
|
48
34
|
});
|
|
49
|
-
return
|
|
35
|
+
return;
|
|
50
36
|
}
|
|
51
37
|
if (fileType.type === 'transport-stream') {
|
|
52
|
-
log_1.Log.verbose(logLevel, 'Detected MPEG-2 Transport Stream');
|
|
38
|
+
log_1.Log.verbose(state.logLevel, 'Detected MPEG-2 Transport Stream');
|
|
53
39
|
state.structure.setStructure({
|
|
54
40
|
boxes: [],
|
|
55
41
|
type: 'transport-stream',
|
|
56
42
|
});
|
|
57
|
-
return
|
|
58
|
-
iterator,
|
|
59
|
-
state,
|
|
60
|
-
streamBuffers: new Map(),
|
|
61
|
-
fields,
|
|
62
|
-
nextPesHeaderStore: (0, next_pes_header_store_1.makeNextPesHeaderStore)(),
|
|
63
|
-
});
|
|
43
|
+
return;
|
|
64
44
|
}
|
|
65
45
|
if (fileType.type === 'mp3') {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
46
|
+
log_1.Log.verbose(state.logLevel, 'Detected MP3');
|
|
47
|
+
const structure = {
|
|
48
|
+
boxes: [],
|
|
49
|
+
type: 'mp3',
|
|
50
|
+
};
|
|
51
|
+
state.structure.setStructure(structure);
|
|
52
|
+
return;
|
|
73
53
|
}
|
|
74
54
|
if (fileType.type === 'wav') {
|
|
75
55
|
return Promise.reject(new errors_1.IsAnUnsupportedAudioTypeError({
|
|
@@ -128,4 +108,36 @@ const parseVideo = ({ iterator, state, signal, logLevel, fields, mimeType, conte
|
|
|
128
108
|
}
|
|
129
109
|
return Promise.reject(new Error('Unknown video format ' + fileType));
|
|
130
110
|
};
|
|
111
|
+
const parseVideo = async ({ iterator, state, mimeType, contentLength, name, }) => {
|
|
112
|
+
if (iterator.bytesRemaining() === 0) {
|
|
113
|
+
return Promise.reject(new Error('no bytes'));
|
|
114
|
+
}
|
|
115
|
+
const structure = state.structure.getStructureOrNull();
|
|
116
|
+
if (structure === null) {
|
|
117
|
+
await initVideo({ iterator, state, mimeType, name, contentLength });
|
|
118
|
+
return { skipTo: null };
|
|
119
|
+
}
|
|
120
|
+
if (structure.type === 'riff') {
|
|
121
|
+
return (0, parse_riff_1.parseRiff)({ iterator, state });
|
|
122
|
+
}
|
|
123
|
+
if (structure.type === 'mp3') {
|
|
124
|
+
return (0, parse_mp3_1.parseMp3)({ iterator, state });
|
|
125
|
+
}
|
|
126
|
+
if (structure.type === 'iso-base-media') {
|
|
127
|
+
return (0, parse_boxes_1.parseIsoBaseMedia)({
|
|
128
|
+
iterator,
|
|
129
|
+
state,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (structure.type === 'matroska') {
|
|
133
|
+
return (0, parse_webm_header_1.parseWebm)({ iterator, state });
|
|
134
|
+
}
|
|
135
|
+
if (structure.type === 'transport-stream') {
|
|
136
|
+
return (0, parse_transport_stream_1.parseTransportStream)({
|
|
137
|
+
iterator,
|
|
138
|
+
state,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return Promise.reject(new Error('Unknown video format ' + structure));
|
|
142
|
+
};
|
|
131
143
|
exports.parseVideo = parseVideo;
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.nodeReader = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
|
-
const promises_1 = require("node:fs/promises");
|
|
6
5
|
const path_1 = require("path");
|
|
7
6
|
const stream_1 = require("stream");
|
|
8
7
|
exports.nodeReader = {
|
|
9
|
-
read:
|
|
8
|
+
read: (src, range, signal) => {
|
|
10
9
|
if (typeof src !== 'string') {
|
|
11
10
|
throw new Error('src must be a string when using `nodeReader`');
|
|
12
11
|
}
|
|
@@ -23,14 +22,14 @@ exports.nodeReader = {
|
|
|
23
22
|
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', () => {
|
|
24
23
|
controller.abort();
|
|
25
24
|
}, { once: true });
|
|
26
|
-
const stats =
|
|
25
|
+
const stats = (0, fs_1.statSync)(src);
|
|
27
26
|
const reader = stream_1.Readable.toWeb(stream).getReader();
|
|
28
27
|
if (signal) {
|
|
29
28
|
signal.addEventListener('abort', () => {
|
|
30
29
|
reader.cancel().catch(() => { });
|
|
31
30
|
}, { once: true });
|
|
32
31
|
}
|
|
33
|
-
return {
|
|
32
|
+
return Promise.resolve({
|
|
34
33
|
reader: {
|
|
35
34
|
reader,
|
|
36
35
|
abort: () => {
|
|
@@ -41,13 +40,13 @@ exports.nodeReader = {
|
|
|
41
40
|
contentType: null,
|
|
42
41
|
name: src.split(path_1.sep).pop(),
|
|
43
42
|
supportsContentRange: true,
|
|
44
|
-
};
|
|
43
|
+
});
|
|
45
44
|
},
|
|
46
|
-
getLength:
|
|
45
|
+
getLength: (src) => {
|
|
47
46
|
if (typeof src !== 'string') {
|
|
48
47
|
throw new Error('src must be a string when using `nodeReader`');
|
|
49
48
|
}
|
|
50
|
-
const stats =
|
|
51
|
-
return stats.size;
|
|
49
|
+
const stats = (0, fs_1.statSync)(src);
|
|
50
|
+
return Promise.resolve(stats.size);
|
|
52
51
|
},
|
|
53
52
|
};
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { Options, ParseMediaFields } from '../options';
|
|
2
|
-
|
|
2
|
+
import type { Structure } from '../parse-result';
|
|
3
|
+
import type { StructureState } from './structure';
|
|
4
|
+
export declare const needsTracksForField: ({ field, structure, }: {
|
|
5
|
+
field: keyof Options<ParseMediaFields>;
|
|
6
|
+
structure: Structure;
|
|
7
|
+
}) => boolean;
|
|
8
|
+
export declare const makeCanSkipTracksState: ({ hasAudioTrackHandlers, fields, hasVideoTrackHandlers, structure, }: {
|
|
3
9
|
hasAudioTrackHandlers: boolean;
|
|
4
10
|
hasVideoTrackHandlers: boolean;
|
|
5
11
|
fields: Options<ParseMediaFields>;
|
|
12
|
+
structure: StructureState;
|
|
6
13
|
}) => {
|
|
7
14
|
canSkipTracks: () => boolean;
|
|
8
15
|
};
|