@remotion/media-parser 4.0.311 → 4.0.312
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/aac/get-seeking-byte.js +5 -1
- package/dist/containers/flac/get-seeking-byte.d.ts +2 -1
- package/dist/containers/flac/get-seeking-byte.js +1 -1
- package/dist/containers/iso-base-media/find-keyframe-before-time.d.ts +1 -1
- package/dist/containers/iso-base-media/find-keyframe-before-time.js +1 -1
- package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +3 -1
- package/dist/containers/iso-base-media/get-seeking-byte.js +3 -1
- package/dist/containers/m3u/get-seeking-byte.js +2 -0
- package/dist/containers/mp3/get-seeking-byte.js +4 -1
- package/dist/containers/riff/get-seeking-byte.js +3 -0
- package/dist/containers/wav/get-seeking-byte.js +1 -0
- package/dist/containers/wav/parse-list.js +4 -3
- package/dist/containers/webm/seek/get-seeking-byte.js +21 -6
- package/dist/controller/media-parser-controller.d.ts +3 -0
- package/dist/controller/media-parser-controller.js +15 -0
- package/dist/esm/index.mjs +226 -131
- package/dist/esm/server-worker.mjs +17 -0
- package/dist/esm/worker-server-entry.mjs +240 -130
- package/dist/esm/worker-web-entry.mjs +240 -130
- package/dist/esm/worker.mjs +28 -0
- package/dist/get-seeking-byte.js +13 -2
- package/dist/index.cjs +54 -0
- package/dist/index.d.ts +1 -0
- package/dist/internal-parse-media.js +25 -0
- package/dist/parse-media-on-worker-entry.js +17 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webcodec-sample-types.d.ts +2 -2
- package/dist/work-on-seek-request.d.ts +22 -0
- package/dist/work-on-seek-request.js +3 -2
- package/dist/worker/forward-controller-to-worker.js +18 -0
- package/dist/worker/worker-types.d.ts +13 -2
- package/package.json +3 -3
|
@@ -23,7 +23,11 @@ const getSeekingByteForAac = ({ time, seekingHints, }) => {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
if (bestAudioSample) {
|
|
26
|
-
return {
|
|
26
|
+
return {
|
|
27
|
+
type: 'do-seek',
|
|
28
|
+
byte: bestAudioSample.offset,
|
|
29
|
+
timeInSeconds: bestAudioSample.timeInSeconds,
|
|
30
|
+
};
|
|
27
31
|
}
|
|
28
32
|
return { type: 'valid-but-must-wait' };
|
|
29
33
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { AudioSampleOffset } from '../../state/audio-sample-map';
|
|
1
2
|
import type { FlacSeekingHints } from './seeking-hints';
|
|
2
3
|
export declare const getSeekingByteForFlac: ({ time, seekingHints, }: {
|
|
3
4
|
time: number;
|
|
4
5
|
seekingHints: FlacSeekingHints;
|
|
5
|
-
}) =>
|
|
6
|
+
}) => AudioSampleOffset | null;
|
|
@@ -28,6 +28,6 @@ const findKeyframeBeforeTime = ({ samplePositions, time, timescale, mediaSection
|
|
|
28
28
|
log_1.Log.trace(logLevel, 'Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.', videoSample);
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
|
-
return videoSample
|
|
31
|
+
return videoSample;
|
|
32
32
|
};
|
|
33
33
|
exports.findKeyframeBeforeTime = findKeyframeBeforeTime;
|
|
@@ -59,7 +59,9 @@ const getSeekingByteFromFragmentedMp4 = async ({ info, time, logLevel, currentPo
|
|
|
59
59
|
if (kf) {
|
|
60
60
|
return {
|
|
61
61
|
type: 'do-seek',
|
|
62
|
-
byte: kf,
|
|
62
|
+
byte: kf.offset,
|
|
63
|
+
timeInSeconds: Math.min(kf.decodingTimestamp, kf.timestamp) /
|
|
64
|
+
firstTrack.originalTimescale,
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
}
|
|
@@ -58,7 +58,9 @@ const getSeekingByteFromIsoBaseMedia = ({ info, time, logLevel, currentPosition,
|
|
|
58
58
|
if (keyframe) {
|
|
59
59
|
return Promise.resolve({
|
|
60
60
|
type: 'do-seek',
|
|
61
|
-
byte: keyframe,
|
|
61
|
+
byte: keyframe.offset,
|
|
62
|
+
timeInSeconds: Math.min(keyframe.decodingTimestamp, keyframe.timestamp) /
|
|
63
|
+
track.originalTimescale,
|
|
62
64
|
});
|
|
63
65
|
}
|
|
64
66
|
return Promise.resolve({
|
|
@@ -27,6 +27,8 @@ const getSeekingByteForM3u8 = ({ time, currentPosition, m3uState, logLevel, }) =
|
|
|
27
27
|
return {
|
|
28
28
|
type: 'do-seek',
|
|
29
29
|
byte: currentPosition,
|
|
30
|
+
// TODO: This will be imperfect when seeking in playMedia()
|
|
31
|
+
timeInSeconds: time,
|
|
30
32
|
};
|
|
31
33
|
};
|
|
32
34
|
exports.getSeekingByteForM3u8 = getSeekingByteForM3u8;
|
|
@@ -41,9 +41,12 @@ const getSeekingByteForMp3 = ({ time, info, }) => {
|
|
|
41
41
|
type: 'valid-but-must-wait',
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
+
const byte = Math.max(...candidates);
|
|
45
|
+
const timeInSeconds = byte === (bestAudioSample === null || bestAudioSample === void 0 ? void 0 : bestAudioSample.offset) ? bestAudioSample.timeInSeconds : time;
|
|
44
46
|
return {
|
|
45
47
|
type: 'do-seek',
|
|
46
|
-
byte
|
|
48
|
+
byte,
|
|
49
|
+
timeInSeconds,
|
|
47
50
|
};
|
|
48
51
|
};
|
|
49
52
|
exports.getSeekingByteForMp3 = getSeekingByteForMp3;
|
|
@@ -22,6 +22,7 @@ const getSeekingByteForRiff = async ({ info, time, riffState, avcState, }) => {
|
|
|
22
22
|
return {
|
|
23
23
|
type: 'do-seek',
|
|
24
24
|
byte: lastKeyframe.positionInBytes,
|
|
25
|
+
timeInSeconds: Math.min(lastKeyframe.decodingTimeInSeconds, lastKeyframe.presentationTimeInSeconds),
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
28
|
if (idx1Entries.videoTrackIndex === null) {
|
|
@@ -55,6 +56,8 @@ const getSeekingByteForRiff = async ({ info, time, riffState, avcState, }) => {
|
|
|
55
56
|
return {
|
|
56
57
|
type: 'do-seek',
|
|
57
58
|
byte: bestEntry.offset + info.moviOffset - 4,
|
|
59
|
+
timeInSeconds: bestEntry.sampleCounts[idx1Entries.videoTrackIndex] /
|
|
60
|
+
info.samplesPerSecond,
|
|
58
61
|
};
|
|
59
62
|
};
|
|
60
63
|
exports.getSeekingByteForRiff = getSeekingByteForRiff;
|
|
@@ -16,10 +16,11 @@ const parseList = ({ state, }) => {
|
|
|
16
16
|
// Padding
|
|
17
17
|
// https://discord.com/channels/809501355504959528/1308803317480292482/1343979547246333983
|
|
18
18
|
// Indie_Hacker_Podcast (2).wav
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const byte = iterator.getUint8();
|
|
20
|
+
if (byte === 0) {
|
|
21
|
+
continue;
|
|
22
22
|
}
|
|
23
|
+
iterator.counter.decrement(1);
|
|
23
24
|
const key = iterator.getByteString(4, false);
|
|
24
25
|
const size = iterator.getUint32Le();
|
|
25
26
|
const value = iterator.getByteString(size, true);
|
|
@@ -19,7 +19,6 @@ const findBiggestCueBeforeTime = ({ cues, time, track, }) => {
|
|
|
19
19
|
return biggestCueBeforeTime;
|
|
20
20
|
};
|
|
21
21
|
const findKeyframeBeforeTime = ({ keyframes, time, }) => {
|
|
22
|
-
var _a;
|
|
23
22
|
let keyframeBeforeTime;
|
|
24
23
|
for (const keyframe of keyframes) {
|
|
25
24
|
if (keyframe.decodingTimeInSeconds < time &&
|
|
@@ -29,7 +28,7 @@ const findKeyframeBeforeTime = ({ keyframes, time, }) => {
|
|
|
29
28
|
keyframeBeforeTime = keyframe;
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
|
-
return
|
|
31
|
+
return keyframeBeforeTime !== null && keyframeBeforeTime !== void 0 ? keyframeBeforeTime : null;
|
|
33
32
|
};
|
|
34
33
|
const getByteFromCues = ({ cuesResponse, time, info, logLevel, }) => {
|
|
35
34
|
if (!cuesResponse) {
|
|
@@ -46,10 +45,13 @@ const getByteFromCues = ({ cuesResponse, time, info, logLevel, }) => {
|
|
|
46
45
|
if (!biggestCueBeforeTime) {
|
|
47
46
|
return null;
|
|
48
47
|
}
|
|
49
|
-
return
|
|
48
|
+
return {
|
|
49
|
+
byte: biggestCueBeforeTime.clusterPositionInSegment + segmentOffset,
|
|
50
|
+
timeInSeconds: toSeconds(biggestCueBeforeTime.timeInTimescale, info.track),
|
|
51
|
+
};
|
|
50
52
|
};
|
|
51
53
|
const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, mediaSection, }) => {
|
|
52
|
-
var _a, _b, _c;
|
|
54
|
+
var _a, _b, _c, _d, _e;
|
|
53
55
|
if (!info.track) {
|
|
54
56
|
log_1.Log.trace(logLevel, 'No video track found, cannot seek yet');
|
|
55
57
|
return {
|
|
@@ -74,8 +76,8 @@ const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, med
|
|
|
74
76
|
// Optimization possibility for later:
|
|
75
77
|
// Don't seek back, if the last seen time is smaller than the time we want to seek to
|
|
76
78
|
const seekPossibilities = [
|
|
77
|
-
byteFromCues,
|
|
78
|
-
byteFromObservedKeyframe,
|
|
79
|
+
(_d = byteFromCues === null || byteFromCues === void 0 ? void 0 : byteFromCues.byte) !== null && _d !== void 0 ? _d : null,
|
|
80
|
+
(_e = byteFromObservedKeyframe === null || byteFromObservedKeyframe === void 0 ? void 0 : byteFromObservedKeyframe.positionInBytes) !== null && _e !== void 0 ? _e : null,
|
|
79
81
|
byteFromFirstMediaSection,
|
|
80
82
|
].filter((n) => n !== null);
|
|
81
83
|
const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
|
|
@@ -92,9 +94,22 @@ const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, med
|
|
|
92
94
|
start: byteToSeekTo,
|
|
93
95
|
size: 1,
|
|
94
96
|
});
|
|
97
|
+
const timeInSeconds = (() => {
|
|
98
|
+
if (byteToSeekTo === (byteFromObservedKeyframe === null || byteFromObservedKeyframe === void 0 ? void 0 : byteFromObservedKeyframe.positionInBytes)) {
|
|
99
|
+
return Math.min(byteFromObservedKeyframe.decodingTimeInSeconds, byteFromObservedKeyframe.presentationTimeInSeconds);
|
|
100
|
+
}
|
|
101
|
+
if (byteToSeekTo === (byteFromCues === null || byteFromCues === void 0 ? void 0 : byteFromCues.byte)) {
|
|
102
|
+
return byteFromCues.timeInSeconds;
|
|
103
|
+
}
|
|
104
|
+
if (byteToSeekTo === byteFromFirstMediaSection) {
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
throw new Error('Should not happen');
|
|
108
|
+
})();
|
|
95
109
|
return {
|
|
96
110
|
type: 'do-seek',
|
|
97
111
|
byte: byteToSeekTo,
|
|
112
|
+
timeInSeconds,
|
|
98
113
|
};
|
|
99
114
|
};
|
|
100
115
|
exports.getSeekingByteFromMatroska = getSeekingByteFromMatroska;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SeekingHints } from '../seeking-hints';
|
|
2
|
+
import type { SeekResolution } from '../work-on-seek-request';
|
|
2
3
|
import { MediaParserEmitter } from './emitter';
|
|
3
4
|
import type { PauseSignal } from './pause-signal';
|
|
4
5
|
import type { PerformedSeeksSignal } from './performed-seeks-stats';
|
|
@@ -8,6 +9,7 @@ export type MediaParserController = {
|
|
|
8
9
|
pause: PauseSignal['pause'];
|
|
9
10
|
resume: PauseSignal['resume'];
|
|
10
11
|
seek: SeekSignal['seek'];
|
|
12
|
+
simulateSeek: (seekInSeconds: number) => Promise<SeekResolution>;
|
|
11
13
|
addEventListener: MediaParserEmitter['addEventListener'];
|
|
12
14
|
removeEventListener: MediaParserEmitter['removeEventListener'];
|
|
13
15
|
getSeekingHints: () => Promise<SeekingHints | null>;
|
|
@@ -21,6 +23,7 @@ export type MediaParserController = {
|
|
|
21
23
|
markAsReadyToEmitEvents: () => void;
|
|
22
24
|
performedSeeksSignal: PerformedSeeksSignal;
|
|
23
25
|
attachSeekingHintResolution: (callback: () => Promise<SeekingHints | null>) => void;
|
|
26
|
+
attachSimulateSeekResolution: (callback: (seekInSeconds: number) => Promise<SeekResolution>) => void;
|
|
24
27
|
};
|
|
25
28
|
};
|
|
26
29
|
export declare const mediaParserController: () => MediaParserController;
|
|
@@ -23,18 +23,31 @@ const mediaParserController = () => {
|
|
|
23
23
|
await pauseSignal.waitUntilResume();
|
|
24
24
|
};
|
|
25
25
|
let seekingHintResolution = null;
|
|
26
|
+
let simulateSeekResolution = null;
|
|
26
27
|
const getSeekingHints = () => {
|
|
27
28
|
if (!seekingHintResolution) {
|
|
28
29
|
throw new Error('The mediaParserController() was not yet used in a parseMedia() call');
|
|
29
30
|
}
|
|
30
31
|
return seekingHintResolution();
|
|
31
32
|
};
|
|
33
|
+
const simulateSeek = (seekInSeconds) => {
|
|
34
|
+
if (!simulateSeekResolution) {
|
|
35
|
+
throw new Error('The mediaParserController() was not yet used in a parseMedia() call');
|
|
36
|
+
}
|
|
37
|
+
return simulateSeekResolution(seekInSeconds);
|
|
38
|
+
};
|
|
32
39
|
const attachSeekingHintResolution = (callback) => {
|
|
33
40
|
if (seekingHintResolution) {
|
|
34
41
|
throw new Error('The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.');
|
|
35
42
|
}
|
|
36
43
|
seekingHintResolution = callback;
|
|
37
44
|
};
|
|
45
|
+
const attachSimulateSeekResolution = (callback) => {
|
|
46
|
+
if (simulateSeekResolution) {
|
|
47
|
+
throw new Error('The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.');
|
|
48
|
+
}
|
|
49
|
+
simulateSeekResolution = callback;
|
|
50
|
+
};
|
|
38
51
|
return {
|
|
39
52
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
53
|
abort: (reason) => {
|
|
@@ -42,6 +55,7 @@ const mediaParserController = () => {
|
|
|
42
55
|
emitter.dispatchAbort(reason);
|
|
43
56
|
},
|
|
44
57
|
seek: seekSignal.seek,
|
|
58
|
+
simulateSeek,
|
|
45
59
|
pause: pauseSignal.pause,
|
|
46
60
|
resume: pauseSignal.resume,
|
|
47
61
|
addEventListener: emitter.addEventListener,
|
|
@@ -54,6 +68,7 @@ const mediaParserController = () => {
|
|
|
54
68
|
markAsReadyToEmitEvents: emitter.markAsReady,
|
|
55
69
|
performedSeeksSignal,
|
|
56
70
|
attachSeekingHintResolution,
|
|
71
|
+
attachSimulateSeekResolution,
|
|
57
72
|
},
|
|
58
73
|
};
|
|
59
74
|
};
|