@remotion/media 4.0.451 → 4.0.452
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/audio/audio-for-preview.d.ts +0 -1
- package/dist/audio/audio-preview-iterator.d.ts +13 -39
- package/dist/audio/get-scheduled-time.d.ts +3 -3
- package/dist/audio/props.d.ts +0 -1
- package/dist/audio/sort-by-priority.d.ts +1 -0
- package/dist/audio-iterator-manager.d.ts +41 -47
- package/dist/calculate-playbacktime.d.ts +5 -0
- package/dist/debug-overlay/preview-overlay.d.ts +30 -45
- package/dist/esm/index.mjs +742 -852
- package/dist/index.d.ts +0 -1
- package/dist/make-iterator-with-priming.d.ts +9 -2
- package/dist/media-player.d.ts +14 -16
- package/dist/prewarm-iterator-for-looping.d.ts +1 -10
- package/dist/shared-audio-context-for-media-player.d.ts +2 -0
- package/dist/use-common-effects.d.ts +1 -8
- package/dist/video/props.d.ts +0 -1
- package/dist/video/video-for-preview.d.ts +0 -1
- package/dist/video/video.d.ts +0 -1
- package/dist/video-iterator-manager.d.ts +2 -2
- package/package.json +3 -3
- package/dist/audio/decode-pool.d.ts +0 -7
- package/dist/audio-decode-scheduler.d.ts +0 -14
- package/dist/draw-with-object-fit.d.ts +0 -14
package/dist/esm/index.mjs
CHANGED
|
@@ -37,12 +37,12 @@ var __callDispose = (stack, error, hasError) => {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
// src/audio/audio.tsx
|
|
40
|
-
import { Internals as
|
|
40
|
+
import { Internals as Internals17, Sequence, useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
|
|
41
41
|
|
|
42
42
|
// src/audio/audio-for-preview.tsx
|
|
43
43
|
import { useContext as useContext3, useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState2 } from "react";
|
|
44
44
|
import {
|
|
45
|
-
Internals as
|
|
45
|
+
Internals as Internals8,
|
|
46
46
|
Audio as RemotionAudio,
|
|
47
47
|
useBufferState,
|
|
48
48
|
useCurrentFrame as useCurrentFrame2,
|
|
@@ -102,219 +102,123 @@ var calculateEndTime = ({
|
|
|
102
102
|
|
|
103
103
|
// src/media-player.ts
|
|
104
104
|
import { ALL_FORMATS, Input, UrlSource } from "mediabunny";
|
|
105
|
-
import { Internals as
|
|
105
|
+
import { Internals as Internals4 } from "remotion";
|
|
106
106
|
|
|
107
107
|
// src/audio-iterator-manager.ts
|
|
108
108
|
import { AudioBufferSink, InputDisposedError } from "mediabunny";
|
|
109
|
-
import { Internals as Internals4 } from "remotion";
|
|
110
|
-
|
|
111
|
-
// src/audio/audio-preview-iterator.ts
|
|
112
|
-
import { Internals as Internals3 } from "remotion";
|
|
113
|
-
|
|
114
|
-
// src/helpers/round-to-4-digits.ts
|
|
115
|
-
var roundTo4Digits = (timestamp) => {
|
|
116
|
-
return Math.round(timestamp * 1000) / 1000;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// src/set-global-time-anchor.ts
|
|
120
109
|
import { Internals as Internals2 } from "remotion";
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
110
|
+
|
|
111
|
+
// src/make-iterator-with-priming.ts
|
|
112
|
+
var AUDIO_PRIMING_SECONDS = 0.5;
|
|
113
|
+
async function* makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp) {
|
|
114
|
+
const primingStart = Math.max(0, timeToSeek - AUDIO_PRIMING_SECONDS);
|
|
115
|
+
const iterator = audioSink.buffers(primingStart, maximumTimestamp);
|
|
116
|
+
for await (const buffer of iterator) {
|
|
117
|
+
if (buffer.timestamp + buffer.duration <= timeToSeek) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
yield {
|
|
121
|
+
buffer,
|
|
122
|
+
timestamp: buffer.timestamp
|
|
123
|
+
};
|
|
134
124
|
}
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
}
|
|
126
|
+
async function* makeLoopingIterator({
|
|
127
|
+
audioSink,
|
|
128
|
+
segmentStartInSeconds,
|
|
129
|
+
segmentEndInSeconds,
|
|
130
|
+
playbackRate,
|
|
131
|
+
sequenceDurationInSeconds
|
|
132
|
+
}) {
|
|
133
|
+
const duration = segmentEndInSeconds - segmentStartInSeconds;
|
|
134
|
+
let iteration = 0;
|
|
135
|
+
let broken = false;
|
|
136
|
+
while (true) {
|
|
137
|
+
for await (const item of makeIteratorWithPrimingInner(audioSink, segmentStartInSeconds, segmentEndInSeconds)) {
|
|
138
|
+
const timestamp = item.timestamp + iteration * duration;
|
|
139
|
+
const endTimestamp = duration * iteration + (item.timestamp - segmentStartInSeconds + item.buffer.duration);
|
|
140
|
+
if (endTimestamp > sequenceDurationInSeconds * playbackRate) {
|
|
141
|
+
broken = true;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
yield {
|
|
145
|
+
buffer: item.buffer,
|
|
146
|
+
timestamp
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (broken) {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
iteration++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
var makeIteratorWithPriming = ({
|
|
156
|
+
audioSink,
|
|
157
|
+
timeToSeek,
|
|
158
|
+
maximumTimestamp,
|
|
159
|
+
loop,
|
|
160
|
+
playbackRate,
|
|
161
|
+
sequenceDurationInSeconds
|
|
162
|
+
}) => {
|
|
163
|
+
if (loop) {
|
|
164
|
+
return makeLoopingIterator({
|
|
165
|
+
audioSink,
|
|
166
|
+
segmentStartInSeconds: timeToSeek,
|
|
167
|
+
segmentEndInSeconds: maximumTimestamp,
|
|
168
|
+
playbackRate,
|
|
169
|
+
sequenceDurationInSeconds
|
|
170
|
+
});
|
|
137
171
|
}
|
|
138
|
-
|
|
172
|
+
return makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp);
|
|
139
173
|
};
|
|
140
174
|
|
|
141
175
|
// src/audio/audio-preview-iterator.ts
|
|
176
|
+
var ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
|
|
142
177
|
var makeAudioIterator = ({
|
|
143
178
|
startFromSecond,
|
|
144
179
|
maximumTimestamp,
|
|
145
|
-
|
|
146
|
-
|
|
180
|
+
audioSink,
|
|
181
|
+
loop,
|
|
182
|
+
playbackRate,
|
|
183
|
+
sequenceDurationInSeconds,
|
|
184
|
+
unscheduleAudioNode
|
|
147
185
|
}) => {
|
|
148
186
|
let destroyed = false;
|
|
149
|
-
const iterator =
|
|
187
|
+
const iterator = makeIteratorWithPriming({
|
|
188
|
+
audioSink,
|
|
189
|
+
timeToSeek: startFromSecond,
|
|
190
|
+
maximumTimestamp,
|
|
191
|
+
loop,
|
|
192
|
+
playbackRate,
|
|
193
|
+
sequenceDurationInSeconds
|
|
194
|
+
});
|
|
150
195
|
const queuedAudioNodes = [];
|
|
151
|
-
const audioChunksForAfterResuming = [];
|
|
152
196
|
let mostRecentTimestamp = -Infinity;
|
|
153
|
-
|
|
154
|
-
const cleanupAudioQueue = (audioContext) => {
|
|
197
|
+
const cleanupAudioQueue = () => {
|
|
155
198
|
for (const node of queuedAudioNodes) {
|
|
156
|
-
|
|
157
|
-
const isAlreadyPlaying = node.scheduledTime - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT < audioContext.audioContext.currentTime;
|
|
158
|
-
const wasScheduledForThisAnchor = node.scheduledAtAnchor === audioContext.audioSyncAnchor.value;
|
|
159
|
-
if (isAlreadyPlaying && wasScheduledForThisAnchor) {
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
if (debugAudioScheduling) {
|
|
163
|
-
const currentlyHearing = audioContext.audioContext.getOutputTimestamp().contextTime;
|
|
164
|
-
const nodeEndTime = node.scheduledTime + node.buffer.duration / node.playbackRate;
|
|
165
|
-
Internals3.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, `Stopping node ${node.timestamp.toFixed(3)}, currently hearing = ${currentlyHearing.toFixed(3)} currentTime = ${audioContext.audioContext.currentTime.toFixed(3)} nodeEndTime = ${nodeEndTime.toFixed(3)} scheduledTime = ${node.scheduledTime.toFixed(3)}`);
|
|
166
|
-
}
|
|
167
|
-
node.node.stop();
|
|
168
|
-
} catch {}
|
|
169
|
-
}
|
|
170
|
-
queuedAudioNodes.length = 0;
|
|
171
|
-
};
|
|
172
|
-
const getNextOrNullIfNotAvailable = async () => {
|
|
173
|
-
let next = pendingNext;
|
|
174
|
-
if (!next) {
|
|
175
|
-
next = iterator.next();
|
|
176
|
-
}
|
|
177
|
-
pendingNext = null;
|
|
178
|
-
const result = await Promise.race([
|
|
179
|
-
next,
|
|
180
|
-
new Promise((resolve) => {
|
|
181
|
-
Promise.resolve().then(() => resolve());
|
|
182
|
-
})
|
|
183
|
-
]);
|
|
184
|
-
if (!result) {
|
|
185
|
-
pendingNext = next;
|
|
186
|
-
return {
|
|
187
|
-
type: "need-to-wait-for-it",
|
|
188
|
-
waitPromise: async () => {
|
|
189
|
-
const res = await next;
|
|
190
|
-
return res.value;
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
if (result.value) {
|
|
195
|
-
mostRecentTimestamp = Math.max(mostRecentTimestamp, result.value.timestamp + result.value.duration);
|
|
196
|
-
pendingNext = iterator.next();
|
|
197
|
-
return {
|
|
198
|
-
type: "got-buffer",
|
|
199
|
-
buffer: result.value
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
type: "got-end",
|
|
204
|
-
mostRecentTimestamp
|
|
205
|
-
};
|
|
206
|
-
};
|
|
207
|
-
const tryToSatisfySeek = async (time, onBufferScheduled) => {
|
|
208
|
-
if (time < startFromSecond) {
|
|
209
|
-
return {
|
|
210
|
-
type: "not-satisfied",
|
|
211
|
-
reason: `time requested is before the start of the iterator`
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
while (true) {
|
|
215
|
-
const buffer = await getNextOrNullIfNotAvailable();
|
|
216
|
-
if (buffer.type === "need-to-wait-for-it") {
|
|
217
|
-
return {
|
|
218
|
-
type: "not-satisfied",
|
|
219
|
-
reason: "iterator did not have buffer ready"
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
if (buffer.type === "got-end") {
|
|
223
|
-
if (time >= mostRecentTimestamp) {
|
|
224
|
-
return {
|
|
225
|
-
type: "ended"
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
type: "not-satisfied",
|
|
230
|
-
reason: `iterator ended before the requested time`
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
if (buffer.type === "got-buffer") {
|
|
234
|
-
const bufferTimestamp = roundTo4Digits(buffer.buffer.timestamp);
|
|
235
|
-
const bufferEndTimestamp = roundTo4Digits(buffer.buffer.timestamp + buffer.buffer.duration);
|
|
236
|
-
const timestamp = roundTo4Digits(time);
|
|
237
|
-
if (timestamp < bufferTimestamp) {
|
|
238
|
-
return {
|
|
239
|
-
type: "not-satisfied",
|
|
240
|
-
reason: `iterator is too far, most recently returned ${bufferTimestamp}-${bufferEndTimestamp}, requested ${timestamp}`
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
if (bufferTimestamp <= timestamp && bufferEndTimestamp >= timestamp) {
|
|
244
|
-
onBufferScheduled(buffer.buffer);
|
|
245
|
-
return {
|
|
246
|
-
type: "satisfied"
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
onBufferScheduled(buffer.buffer);
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
throw new Error("Unreachable");
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
const bufferAsFarAsPossible = async (onBufferScheduled, maxTimestamp) => {
|
|
256
|
-
while (true) {
|
|
257
|
-
if (mostRecentTimestamp >= maxTimestamp) {
|
|
258
|
-
return { type: "max-reached" };
|
|
259
|
-
}
|
|
260
|
-
const buffer = await getNextOrNullIfNotAvailable();
|
|
261
|
-
if (buffer.type === "need-to-wait-for-it") {
|
|
262
|
-
return { type: "waiting" };
|
|
263
|
-
}
|
|
264
|
-
if (buffer.type === "got-end") {
|
|
265
|
-
return { type: "ended" };
|
|
266
|
-
}
|
|
267
|
-
if (buffer.type === "got-buffer") {
|
|
268
|
-
onBufferScheduled(buffer.buffer);
|
|
269
|
-
continue;
|
|
270
|
-
}
|
|
271
|
-
throw new Error("Unreachable");
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
const removeAndReturnAllQueuedAudioNodes = () => {
|
|
275
|
-
const nodes = queuedAudioNodes.slice();
|
|
276
|
-
for (const node of nodes) {
|
|
199
|
+
unscheduleAudioNode(node.node);
|
|
277
200
|
try {
|
|
278
201
|
node.node.stop();
|
|
279
202
|
} catch {}
|
|
280
203
|
}
|
|
281
204
|
queuedAudioNodes.length = 0;
|
|
282
|
-
return nodes;
|
|
283
205
|
};
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
timestamp
|
|
288
|
-
});
|
|
289
|
-
};
|
|
290
|
-
const moveQueuedChunksToPauseQueue = () => {
|
|
291
|
-
const toQueue = removeAndReturnAllQueuedAudioNodes();
|
|
292
|
-
for (const chunk of toQueue) {
|
|
293
|
-
addChunkForAfterResuming(chunk.buffer, chunk.timestamp);
|
|
206
|
+
const getNextFn = async () => {
|
|
207
|
+
const next = await iterator.next();
|
|
208
|
+
if (next.value) {
|
|
209
|
+
mostRecentTimestamp = Math.max(mostRecentTimestamp, next.value.timestamp + next.value.buffer.duration);
|
|
294
210
|
}
|
|
295
|
-
|
|
296
|
-
Internals3.Log.trace({ logLevel: "trace", tag: "audio-scheduling" }, `Moved ${toQueue.length} ${toQueue.length === 1 ? "chunk" : "chunks"} to pause queue (${toQueue[0].timestamp.toFixed(3)}-${toQueue[toQueue.length - 1].timestamp + toQueue[toQueue.length - 1].buffer.duration.toFixed(3)})`);
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
const getNumberOfChunksAfterResuming = () => {
|
|
300
|
-
return audioChunksForAfterResuming.length;
|
|
211
|
+
return next;
|
|
301
212
|
};
|
|
302
213
|
return {
|
|
303
|
-
destroy: (
|
|
304
|
-
cleanupAudioQueue(
|
|
214
|
+
destroy: () => {
|
|
215
|
+
cleanupAudioQueue();
|
|
305
216
|
destroyed = true;
|
|
306
217
|
iterator.return().catch(() => {
|
|
307
218
|
return;
|
|
308
219
|
});
|
|
309
|
-
audioChunksForAfterResuming.length = 0;
|
|
310
|
-
},
|
|
311
|
-
getNext: async () => {
|
|
312
|
-
const next = await iterator.next();
|
|
313
|
-
if (next.value) {
|
|
314
|
-
mostRecentTimestamp = Math.max(mostRecentTimestamp, next.value.timestamp + next.value.duration);
|
|
315
|
-
}
|
|
316
|
-
return next;
|
|
317
220
|
},
|
|
221
|
+
getNextFn,
|
|
318
222
|
isDestroyed: () => {
|
|
319
223
|
return destroyed;
|
|
320
224
|
},
|
|
@@ -323,7 +227,6 @@ var makeAudioIterator = ({
|
|
|
323
227
|
timestamp,
|
|
324
228
|
buffer,
|
|
325
229
|
scheduledTime,
|
|
326
|
-
playbackRate,
|
|
327
230
|
scheduledAtAnchor
|
|
328
231
|
}) => {
|
|
329
232
|
queuedAudioNodes.push({
|
|
@@ -335,16 +238,8 @@ var makeAudioIterator = ({
|
|
|
335
238
|
scheduledAtAnchor
|
|
336
239
|
});
|
|
337
240
|
},
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if (index !== -1) {
|
|
341
|
-
queuedAudioNodes.splice(index, 1);
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
getAndClearAudioChunksForAfterResuming: () => {
|
|
345
|
-
const chunks = audioChunksForAfterResuming.slice();
|
|
346
|
-
audioChunksForAfterResuming.length = 0;
|
|
347
|
-
return chunks;
|
|
241
|
+
guessNextTimestamp: () => {
|
|
242
|
+
return !Number.isFinite(mostRecentTimestamp) ? startFromSecond : mostRecentTimestamp;
|
|
348
243
|
},
|
|
349
244
|
getQueuedPeriod: () => {
|
|
350
245
|
let until = -Infinity;
|
|
@@ -353,10 +248,6 @@ var makeAudioIterator = ({
|
|
|
353
248
|
until = Math.max(until, node.timestamp + node.buffer.duration);
|
|
354
249
|
from = Math.min(from, node.timestamp);
|
|
355
250
|
}
|
|
356
|
-
for (const chunk of audioChunksForAfterResuming) {
|
|
357
|
-
until = Math.max(until, chunk.timestamp + chunk.buffer.duration);
|
|
358
|
-
from = Math.min(from, chunk.timestamp);
|
|
359
|
-
}
|
|
360
251
|
if (!Number.isFinite(from) || !Number.isFinite(until)) {
|
|
361
252
|
return null;
|
|
362
253
|
}
|
|
@@ -364,12 +255,7 @@ var makeAudioIterator = ({
|
|
|
364
255
|
from,
|
|
365
256
|
until
|
|
366
257
|
};
|
|
367
|
-
}
|
|
368
|
-
tryToSatisfySeek,
|
|
369
|
-
bufferAsFarAsPossible,
|
|
370
|
-
addChunkForAfterResuming,
|
|
371
|
-
moveQueuedChunksToPauseQueue,
|
|
372
|
-
getNumberOfChunksAfterResuming
|
|
258
|
+
}
|
|
373
259
|
};
|
|
374
260
|
};
|
|
375
261
|
var isAlreadyQueued = (time, queuedPeriod) => {
|
|
@@ -379,224 +265,183 @@ var isAlreadyQueued = (time, queuedPeriod) => {
|
|
|
379
265
|
return time >= queuedPeriod.from && time < queuedPeriod.until;
|
|
380
266
|
};
|
|
381
267
|
|
|
382
|
-
// src/
|
|
383
|
-
var
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
let innerDone = false;
|
|
389
|
-
let returned = false;
|
|
390
|
-
let fetching = false;
|
|
391
|
-
let waiter = null;
|
|
392
|
-
const prefetch = () => {
|
|
393
|
-
if (fetching || returned || innerDone) {
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
const lastBuffered = buffer.length > 0 ? buffer[buffer.length - 1] : null;
|
|
397
|
-
const bufferedEndTime = lastBuffered ? lastBuffered.timestamp + lastBuffered.duration : consumerEndTime;
|
|
398
|
-
if (bufferedEndTime >= consumerEndTime + PREDECODE_AHEAD_SECONDS) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
fetching = true;
|
|
402
|
-
inner.next().then((result) => {
|
|
403
|
-
fetching = false;
|
|
404
|
-
if (returned) {
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
if (result.done) {
|
|
408
|
-
innerDone = true;
|
|
409
|
-
if (waiter) {
|
|
410
|
-
const w = waiter;
|
|
411
|
-
waiter = null;
|
|
412
|
-
w({ value: undefined, done: true });
|
|
413
|
-
}
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
if (waiter) {
|
|
417
|
-
const w = waiter;
|
|
418
|
-
waiter = null;
|
|
419
|
-
const buf = result.value;
|
|
420
|
-
consumerEndTime = buf.timestamp + buf.duration;
|
|
421
|
-
w({ value: buf, done: false });
|
|
422
|
-
prefetch();
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
buffer.push(result.value);
|
|
426
|
-
prefetch();
|
|
427
|
-
}, () => {
|
|
428
|
-
fetching = false;
|
|
429
|
-
innerDone = true;
|
|
430
|
-
if (waiter) {
|
|
431
|
-
const w = waiter;
|
|
432
|
-
waiter = null;
|
|
433
|
-
w({ value: undefined, done: true });
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
};
|
|
437
|
-
prefetch();
|
|
438
|
-
const _return = () => {
|
|
439
|
-
returned = true;
|
|
440
|
-
buffer.length = 0;
|
|
441
|
-
if (waiter) {
|
|
442
|
-
const w = waiter;
|
|
443
|
-
waiter = null;
|
|
444
|
-
w({ value: undefined, done: true });
|
|
445
|
-
}
|
|
446
|
-
inner.return(undefined);
|
|
447
|
-
return Promise.resolve({ value: undefined, done: true });
|
|
448
|
-
};
|
|
449
|
-
const iterator = {
|
|
450
|
-
next() {
|
|
451
|
-
if (buffer.length > 0) {
|
|
452
|
-
const buf = buffer.shift();
|
|
453
|
-
consumerEndTime = buf.timestamp + buf.duration;
|
|
454
|
-
prefetch();
|
|
455
|
-
return Promise.resolve({ value: buf, done: false });
|
|
456
|
-
}
|
|
457
|
-
if (innerDone) {
|
|
458
|
-
return Promise.resolve({
|
|
459
|
-
value: undefined,
|
|
460
|
-
done: true
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
return new Promise((resolve) => {
|
|
464
|
-
waiter = resolve;
|
|
465
|
-
prefetch();
|
|
466
|
-
});
|
|
467
|
-
},
|
|
468
|
-
return: _return,
|
|
469
|
-
throw(e) {
|
|
470
|
-
returned = true;
|
|
471
|
-
buffer.length = 0;
|
|
472
|
-
return inner.throw(e);
|
|
473
|
-
},
|
|
474
|
-
[Symbol.asyncIterator]() {
|
|
475
|
-
return iterator;
|
|
476
|
-
}
|
|
477
|
-
};
|
|
478
|
-
return iterator;
|
|
479
|
-
}
|
|
480
|
-
async function* makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp) {
|
|
481
|
-
const primingStart = Math.max(0, timeToSeek - AUDIO_PRIMING_SECONDS);
|
|
482
|
-
const iterator = audioSink.buffers(primingStart, maximumTimestamp);
|
|
483
|
-
for await (const buffer of iterator) {
|
|
484
|
-
if (buffer.timestamp + buffer.duration <= timeToSeek) {
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
yield buffer;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
var makeIteratorWithPriming = ({
|
|
491
|
-
audioSink,
|
|
492
|
-
timeToSeek,
|
|
493
|
-
maximumTimestamp
|
|
268
|
+
// src/audio/get-scheduled-time.ts
|
|
269
|
+
var getScheduledTime = ({
|
|
270
|
+
mediaTimestamp,
|
|
271
|
+
targetTime,
|
|
272
|
+
currentTime,
|
|
273
|
+
sequenceStartTime
|
|
494
274
|
}) => {
|
|
495
|
-
|
|
275
|
+
const needsTrimStart = mediaTimestamp < sequenceStartTime;
|
|
276
|
+
const offsetBecauseOfTrim = needsTrimStart ? sequenceStartTime - mediaTimestamp : 0;
|
|
277
|
+
const offsetBecauseOfTooLate = targetTime < 0 ? -targetTime : 0;
|
|
278
|
+
const offset = offsetBecauseOfTrim + offsetBecauseOfTooLate;
|
|
279
|
+
const scheduledTime = targetTime + currentTime + offset;
|
|
280
|
+
return scheduledTime;
|
|
496
281
|
};
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
if (prewarmedIterator) {
|
|
509
|
-
prewarmedVideoIterators.delete(timeToSeek);
|
|
510
|
-
return prewarmedIterator;
|
|
511
|
-
}
|
|
512
|
-
const iterator = videoSink.canvases(timeToSeek);
|
|
513
|
-
return iterator;
|
|
514
|
-
};
|
|
515
|
-
const destroy = () => {
|
|
516
|
-
for (const iterator of prewarmedVideoIterators.values()) {
|
|
517
|
-
iterator.return();
|
|
518
|
-
}
|
|
519
|
-
prewarmedVideoIterators.clear();
|
|
520
|
-
};
|
|
521
|
-
return {
|
|
522
|
-
prewarmIteratorForLooping,
|
|
523
|
-
makeIteratorOrUsePrewarmed,
|
|
524
|
-
destroy
|
|
525
|
-
};
|
|
282
|
+
var getDurationOfNode = ({
|
|
283
|
+
bufferDuration,
|
|
284
|
+
loopSegmentMediaEndTimestamp,
|
|
285
|
+
offset,
|
|
286
|
+
originalUnloopedMediaTimestamp
|
|
287
|
+
}) => {
|
|
288
|
+
const originalUnloopedMediaEndTime = originalUnloopedMediaTimestamp + bufferDuration;
|
|
289
|
+
const needsTrimEnd = originalUnloopedMediaEndTime > loopSegmentMediaEndTimestamp;
|
|
290
|
+
const durationMinusOffset = bufferDuration - offset;
|
|
291
|
+
const duration = needsTrimEnd ? durationMinusOffset - Math.max(0, originalUnloopedMediaEndTime - loopSegmentMediaEndTimestamp) : durationMinusOffset;
|
|
292
|
+
return duration;
|
|
526
293
|
};
|
|
527
|
-
var
|
|
528
|
-
|
|
294
|
+
var getOffset = ({
|
|
295
|
+
mediaTimestamp,
|
|
296
|
+
targetTime,
|
|
297
|
+
sequenceStartTime
|
|
298
|
+
}) => {
|
|
299
|
+
const needsTrimStart = mediaTimestamp < sequenceStartTime;
|
|
300
|
+
const offsetBecauseOfTrim = needsTrimStart ? sequenceStartTime - mediaTimestamp : 0;
|
|
301
|
+
const offsetBecauseOfTooLate = targetTime < 0 ? -targetTime : 0;
|
|
302
|
+
const offset = offsetBecauseOfTrim + offsetBecauseOfTooLate;
|
|
303
|
+
return offset;
|
|
529
304
|
};
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
305
|
+
|
|
306
|
+
// src/audio/sort-by-priority.ts
|
|
307
|
+
class StaleWaiterError extends Error {
|
|
308
|
+
constructor() {
|
|
309
|
+
super("Waiter became stale before it got its turn");
|
|
310
|
+
this.name = "StaleWaiterError";
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
var CONCURRENCY = 1;
|
|
314
|
+
var waiters = [];
|
|
315
|
+
var running = 0;
|
|
316
|
+
var processNext = () => {
|
|
317
|
+
if (running >= CONCURRENCY) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const staleWaiters = [];
|
|
321
|
+
for (let i = waiters.length - 1;i >= 0; i--) {
|
|
322
|
+
if (waiters[i].getPriority() === null) {
|
|
323
|
+
const [stale] = waiters.splice(i, 1);
|
|
324
|
+
staleWaiters.push(stale);
|
|
538
325
|
}
|
|
539
|
-
}
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
326
|
+
}
|
|
327
|
+
for (const stale of staleWaiters) {
|
|
328
|
+
stale.onError(new StaleWaiterError);
|
|
329
|
+
}
|
|
330
|
+
if (waiters.length === 0) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
let bestIndex = 0;
|
|
334
|
+
let bestPriority = waiters[0].getPriority();
|
|
335
|
+
if (bestPriority === null) {
|
|
336
|
+
throw new Error("Stale waiter should have been removed");
|
|
337
|
+
}
|
|
338
|
+
for (let i = 1;i < waiters.length; i++) {
|
|
339
|
+
const priority = waiters[i].getPriority();
|
|
340
|
+
if (priority === null) {
|
|
341
|
+
throw new Error("Stale waiter should have been removed");
|
|
545
342
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
maximumTimestamp
|
|
550
|
-
});
|
|
551
|
-
return iterator;
|
|
552
|
-
};
|
|
553
|
-
const destroy = () => {
|
|
554
|
-
for (const iterator of prewarmedAudioIterators.values()) {
|
|
555
|
-
iterator.return();
|
|
343
|
+
if (priority < bestPriority) {
|
|
344
|
+
bestPriority = priority;
|
|
345
|
+
bestIndex = i;
|
|
556
346
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
347
|
+
}
|
|
348
|
+
if (bestPriority > 2) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const [next] = waiters.splice(bestIndex, 1);
|
|
352
|
+
running++;
|
|
353
|
+
next.fn().then((value) => {
|
|
354
|
+
running--;
|
|
355
|
+
next.onDone(value, processNext);
|
|
356
|
+
}, (err) => {
|
|
357
|
+
running--;
|
|
358
|
+
next.onError(err);
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
var waitForTurn = ({
|
|
362
|
+
getPriority,
|
|
363
|
+
fn,
|
|
364
|
+
onDone,
|
|
365
|
+
onError
|
|
366
|
+
}) => {
|
|
367
|
+
waiters.push({
|
|
368
|
+
getPriority,
|
|
369
|
+
fn,
|
|
370
|
+
onDone,
|
|
371
|
+
onError
|
|
372
|
+
});
|
|
373
|
+
processNext();
|
|
564
374
|
};
|
|
565
375
|
|
|
566
376
|
// src/audio-iterator-manager.ts
|
|
567
|
-
var MAX_BUFFER_AHEAD_SECONDS = 2;
|
|
568
377
|
var audioIteratorManager = ({
|
|
569
378
|
audioTrack,
|
|
570
379
|
delayPlaybackHandleIfNotPremounting,
|
|
571
380
|
sharedAudioContext,
|
|
572
|
-
|
|
573
|
-
|
|
381
|
+
getSequenceEndTimestamp,
|
|
382
|
+
getSequenceDurationInSeconds,
|
|
383
|
+
getMediaEndTimestamp,
|
|
574
384
|
getStartTime,
|
|
575
385
|
initialMuted,
|
|
576
|
-
drawDebugOverlay
|
|
386
|
+
drawDebugOverlay,
|
|
387
|
+
initialPlaybackRate,
|
|
388
|
+
initialTrimBefore,
|
|
389
|
+
initialTrimAfter,
|
|
390
|
+
initialSequenceOffset,
|
|
391
|
+
initialSequenceDurationInFrames,
|
|
392
|
+
initialLoop,
|
|
393
|
+
initialFps
|
|
577
394
|
}) => {
|
|
578
395
|
let muted = initialMuted;
|
|
579
396
|
let currentVolume = 1;
|
|
397
|
+
let currentSeek = {
|
|
398
|
+
time: -1,
|
|
399
|
+
playbackRate: initialPlaybackRate,
|
|
400
|
+
trimBefore: initialTrimBefore,
|
|
401
|
+
trimAfter: initialTrimAfter,
|
|
402
|
+
sequenceOffset: initialSequenceOffset,
|
|
403
|
+
sequenceDurationInFrames: initialSequenceDurationInFrames,
|
|
404
|
+
loop: initialLoop,
|
|
405
|
+
fps: initialFps
|
|
406
|
+
};
|
|
580
407
|
const gainNode = sharedAudioContext.audioContext.createGain();
|
|
581
|
-
gainNode.connect(sharedAudioContext.
|
|
408
|
+
gainNode.connect(sharedAudioContext.gainNode);
|
|
582
409
|
const audioSink = new AudioBufferSink(audioTrack);
|
|
583
|
-
const prewarmedAudioIteratorCache = makePrewarmedAudioIteratorCache(audioSink);
|
|
584
410
|
let audioBufferIterator = null;
|
|
585
411
|
let audioIteratorsCreated = 0;
|
|
412
|
+
let totalAudioScheduledInSeconds = 0;
|
|
586
413
|
let currentDelayHandle = null;
|
|
414
|
+
const pendingScheduleWaiters = [];
|
|
415
|
+
const notifyNodeScheduled = () => {
|
|
416
|
+
for (let i = pendingScheduleWaiters.length - 1;i >= 0; i--) {
|
|
417
|
+
const waiter = pendingScheduleWaiters[i];
|
|
418
|
+
waiter.remaining--;
|
|
419
|
+
if (waiter.remaining <= 0) {
|
|
420
|
+
waiter.resolve();
|
|
421
|
+
pendingScheduleWaiters.splice(i, 1);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
const waitForNScheduledNodes = (n) => {
|
|
426
|
+
if (n <= 0) {
|
|
427
|
+
return Promise.resolve();
|
|
428
|
+
}
|
|
429
|
+
return new Promise((resolve) => {
|
|
430
|
+
pendingScheduleWaiters.push({ remaining: n, resolve });
|
|
431
|
+
});
|
|
432
|
+
};
|
|
587
433
|
const scheduleAudioChunk = ({
|
|
588
434
|
buffer,
|
|
589
435
|
mediaTimestamp,
|
|
436
|
+
originalUnloopedMediaTimestamp,
|
|
590
437
|
playbackRate,
|
|
591
438
|
scheduleAudioNode,
|
|
592
|
-
|
|
439
|
+
logLevel,
|
|
440
|
+
currentTime
|
|
593
441
|
}) => {
|
|
594
442
|
if (!audioBufferIterator) {
|
|
595
443
|
throw new Error("Audio buffer iterator not found");
|
|
596
444
|
}
|
|
597
|
-
if (sharedAudioContext.audioContext.state !== "running") {
|
|
598
|
-
throw new Error("Tried to schedule node while audio context is not running");
|
|
599
|
-
}
|
|
600
445
|
if (muted) {
|
|
601
446
|
return;
|
|
602
447
|
}
|
|
@@ -604,252 +449,247 @@ var audioIteratorManager = ({
|
|
|
604
449
|
node.buffer = buffer;
|
|
605
450
|
node.playbackRate.value = playbackRate;
|
|
606
451
|
node.connect(gainNode);
|
|
607
|
-
const started = scheduleAudioNode(node, mediaTimestamp);
|
|
452
|
+
const started = scheduleAudioNode(node, mediaTimestamp, originalUnloopedMediaTimestamp, currentTime);
|
|
608
453
|
if (started.type === "not-started") {
|
|
609
|
-
|
|
610
|
-
Internals4.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, "not started, disconnected: %s %s", mediaTimestamp.toFixed(3), buffer.duration.toFixed(3));
|
|
611
|
-
}
|
|
454
|
+
Internals2.Log.verbose({ logLevel, tag: "audio-scheduling" }, "not started, disconnected: %s %s", mediaTimestamp.toFixed(3), buffer.duration.toFixed(3));
|
|
612
455
|
node.disconnect();
|
|
613
456
|
return;
|
|
614
457
|
}
|
|
615
|
-
|
|
616
|
-
iterator.addQueuedAudioNode({
|
|
458
|
+
audioBufferIterator.addQueuedAudioNode({
|
|
617
459
|
node,
|
|
618
460
|
timestamp: mediaTimestamp,
|
|
619
461
|
buffer,
|
|
620
462
|
scheduledTime: started.scheduledTime,
|
|
621
|
-
playbackRate,
|
|
622
463
|
scheduledAtAnchor: sharedAudioContext.audioSyncAnchor.value
|
|
623
464
|
});
|
|
624
|
-
node.onended = () => {
|
|
625
|
-
setTimeout(() => {
|
|
626
|
-
iterator.removeQueuedAudioNode(node);
|
|
627
|
-
}, 30);
|
|
628
|
-
};
|
|
629
|
-
};
|
|
630
|
-
const resumeScheduledAudioChunks = ({
|
|
631
|
-
playbackRate,
|
|
632
|
-
scheduleAudioNode,
|
|
633
|
-
debugAudioScheduling
|
|
634
|
-
}) => {
|
|
635
|
-
if (muted) {
|
|
636
|
-
return;
|
|
637
|
-
}
|
|
638
|
-
if (!audioBufferIterator) {
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
for (const chunk of audioBufferIterator.getAndClearAudioChunksForAfterResuming()) {
|
|
642
|
-
scheduleAudioChunk({
|
|
643
|
-
buffer: chunk.buffer,
|
|
644
|
-
mediaTimestamp: chunk.timestamp,
|
|
645
|
-
playbackRate,
|
|
646
|
-
scheduleAudioNode,
|
|
647
|
-
debugAudioScheduling
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
465
|
};
|
|
651
466
|
const onAudioChunk = ({
|
|
652
|
-
getIsPlaying,
|
|
653
467
|
buffer,
|
|
654
468
|
playbackRate,
|
|
655
469
|
scheduleAudioNode,
|
|
656
|
-
|
|
470
|
+
logLevel,
|
|
471
|
+
currentTime
|
|
657
472
|
}) => {
|
|
658
473
|
if (muted) {
|
|
659
474
|
return;
|
|
660
475
|
}
|
|
661
476
|
const startTime = getStartTime();
|
|
662
|
-
const
|
|
663
|
-
if (buffer.timestamp + buffer.duration <= startTime) {
|
|
664
|
-
return;
|
|
665
|
-
}
|
|
666
|
-
if (buffer.timestamp >=
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
if (getIsPlaying() && sharedAudioContext.audioContext.state === "running" && (sharedAudioContext.audioContext.getOutputTimestamp().contextTime ?? 0) > 0) {
|
|
670
|
-
resumeScheduledAudioChunks({
|
|
671
|
-
playbackRate,
|
|
672
|
-
scheduleAudioNode,
|
|
673
|
-
debugAudioScheduling
|
|
674
|
-
});
|
|
675
|
-
scheduleAudioChunk({
|
|
676
|
-
buffer: buffer.buffer,
|
|
677
|
-
mediaTimestamp: buffer.timestamp,
|
|
678
|
-
playbackRate,
|
|
679
|
-
scheduleAudioNode,
|
|
680
|
-
debugAudioScheduling
|
|
681
|
-
});
|
|
682
|
-
} else {
|
|
683
|
-
if (!audioBufferIterator) {
|
|
684
|
-
throw new Error("Audio buffer iterator not found");
|
|
685
|
-
}
|
|
686
|
-
if (debugAudioScheduling) {
|
|
687
|
-
Internals4.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, "not ready, added to queue: %s %s", buffer.timestamp.toFixed(3), buffer.duration.toFixed(3));
|
|
688
|
-
}
|
|
689
|
-
audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp);
|
|
477
|
+
const sequenceEndTime = getSequenceEndTimestamp();
|
|
478
|
+
if (buffer.timestamp + buffer.buffer.duration <= startTime) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (buffer.timestamp >= sequenceEndTime) {
|
|
482
|
+
return;
|
|
690
483
|
}
|
|
484
|
+
const scheduledStart = Math.max(buffer.timestamp, startTime);
|
|
485
|
+
const scheduledEnd = Math.min(buffer.timestamp + buffer.buffer.duration, sequenceEndTime);
|
|
486
|
+
totalAudioScheduledInSeconds += Math.max(0, scheduledEnd - scheduledStart);
|
|
487
|
+
scheduleAudioChunk({
|
|
488
|
+
buffer: buffer.buffer.buffer,
|
|
489
|
+
mediaTimestamp: buffer.timestamp,
|
|
490
|
+
playbackRate,
|
|
491
|
+
scheduleAudioNode,
|
|
492
|
+
logLevel,
|
|
493
|
+
originalUnloopedMediaTimestamp: buffer.buffer.timestamp,
|
|
494
|
+
currentTime
|
|
495
|
+
});
|
|
691
496
|
drawDebugOverlay();
|
|
692
497
|
};
|
|
693
|
-
const
|
|
498
|
+
const proceedScheduling = ({
|
|
499
|
+
iterator,
|
|
694
500
|
nonce,
|
|
501
|
+
getTargetTime,
|
|
695
502
|
playbackRate,
|
|
696
|
-
startFromSecond,
|
|
697
|
-
getIsPlaying,
|
|
698
503
|
scheduleAudioNode,
|
|
699
|
-
|
|
504
|
+
onScheduled,
|
|
505
|
+
onDestroyed,
|
|
506
|
+
onDone,
|
|
507
|
+
logLevel,
|
|
508
|
+
currentTime,
|
|
509
|
+
getAudioContextCurrentTimeMockedInTest
|
|
700
510
|
}) => {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
audioBufferIterator?.destroy(sharedAudioContext);
|
|
707
|
-
const delayHandle = __using(__stack, delayPlaybackHandleIfNotPremounting(), 0);
|
|
708
|
-
currentDelayHandle = delayHandle;
|
|
709
|
-
const iterator = makeAudioIterator({
|
|
710
|
-
startFromSecond,
|
|
711
|
-
maximumTimestamp: getEndTime(),
|
|
712
|
-
cache: prewarmedAudioIteratorCache,
|
|
713
|
-
debugAudioScheduling
|
|
714
|
-
});
|
|
715
|
-
audioIteratorsCreated++;
|
|
716
|
-
audioBufferIterator = iterator;
|
|
717
|
-
try {
|
|
718
|
-
for (let i = 0;i < 6; i++) {
|
|
719
|
-
const result = await iterator.getNext();
|
|
720
|
-
if (iterator.isDestroyed()) {
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
if (nonce.isStale()) {
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
if (!result.value) {
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
onAudioChunk({
|
|
730
|
-
getIsPlaying,
|
|
731
|
-
buffer: result.value,
|
|
732
|
-
playbackRate,
|
|
733
|
-
scheduleAudioNode,
|
|
734
|
-
debugAudioScheduling
|
|
735
|
-
});
|
|
511
|
+
waitForTurn({
|
|
512
|
+
getPriority: () => {
|
|
513
|
+
if (iterator.isDestroyed()) {
|
|
514
|
+
return null;
|
|
736
515
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
|
|
516
|
+
const guessedNextTimestamp = iterator.guessNextTimestamp();
|
|
517
|
+
const targetTime = getTargetTime(guessedNextTimestamp, currentTime);
|
|
518
|
+
if (targetTime === null) {
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
const scheduledTime = getScheduledTime({
|
|
522
|
+
mediaTimestamp: guessedNextTimestamp,
|
|
523
|
+
targetTime,
|
|
524
|
+
currentTime,
|
|
525
|
+
sequenceStartTime: getStartTime()
|
|
526
|
+
});
|
|
527
|
+
return scheduledTime - getAudioContextCurrentTimeMockedInTest();
|
|
528
|
+
},
|
|
529
|
+
fn: () => iterator.getNextFn(),
|
|
530
|
+
onDone: (result, next) => {
|
|
531
|
+
if (iterator.isDestroyed()) {
|
|
532
|
+
next();
|
|
533
|
+
onDestroyed();
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
if (!result.value) {
|
|
537
|
+
next();
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
onScheduled(result.value.timestamp);
|
|
541
|
+
notifyNodeScheduled();
|
|
542
|
+
onAudioChunk({
|
|
543
|
+
buffer: result.value,
|
|
544
|
+
playbackRate,
|
|
545
|
+
scheduleAudioNode,
|
|
546
|
+
logLevel,
|
|
547
|
+
currentTime
|
|
548
|
+
});
|
|
549
|
+
proceedScheduling({
|
|
550
|
+
iterator,
|
|
551
|
+
nonce,
|
|
552
|
+
getTargetTime,
|
|
553
|
+
playbackRate,
|
|
554
|
+
scheduleAudioNode,
|
|
555
|
+
onScheduled,
|
|
556
|
+
onDestroyed,
|
|
557
|
+
onDone,
|
|
558
|
+
logLevel,
|
|
559
|
+
currentTime,
|
|
560
|
+
getAudioContextCurrentTimeMockedInTest
|
|
561
|
+
});
|
|
562
|
+
next();
|
|
563
|
+
},
|
|
564
|
+
onError: (e) => {
|
|
749
565
|
if (e instanceof InputDisposedError) {
|
|
750
566
|
return;
|
|
751
567
|
}
|
|
568
|
+
if (e instanceof StaleWaiterError) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
752
571
|
throw e;
|
|
753
572
|
}
|
|
754
|
-
}
|
|
755
|
-
var _err = _catch, _hasErr = 1;
|
|
756
|
-
} finally {
|
|
757
|
-
__callDispose(__stack, _err, _hasErr);
|
|
758
|
-
}
|
|
573
|
+
});
|
|
759
574
|
};
|
|
760
|
-
const
|
|
761
|
-
|
|
575
|
+
const startAudioIterator = ({
|
|
576
|
+
nonce,
|
|
577
|
+
playbackRate,
|
|
578
|
+
startFromSecond,
|
|
579
|
+
scheduleAudioNode,
|
|
580
|
+
getTargetTime,
|
|
581
|
+
logLevel,
|
|
582
|
+
loop,
|
|
583
|
+
unscheduleAudioNode,
|
|
584
|
+
getAudioContextCurrentTimeMockedInTest
|
|
585
|
+
}) => {
|
|
586
|
+
if (muted) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const maximumTimestamp = getMediaEndTimestamp();
|
|
590
|
+
if (startFromSecond >= maximumTimestamp) {
|
|
762
591
|
return;
|
|
763
592
|
}
|
|
764
|
-
audioBufferIterator
|
|
593
|
+
audioBufferIterator?.destroy();
|
|
594
|
+
const delayHandle = delayPlaybackHandleIfNotPremounting();
|
|
595
|
+
currentDelayHandle = delayHandle;
|
|
596
|
+
const iterator = makeAudioIterator({
|
|
597
|
+
startFromSecond,
|
|
598
|
+
maximumTimestamp,
|
|
599
|
+
audioSink,
|
|
600
|
+
logLevel,
|
|
601
|
+
loop,
|
|
602
|
+
playbackRate,
|
|
603
|
+
sequenceDurationInSeconds: getSequenceDurationInSeconds(),
|
|
604
|
+
unscheduleAudioNode
|
|
605
|
+
});
|
|
606
|
+
audioIteratorsCreated++;
|
|
607
|
+
audioBufferIterator = iterator;
|
|
608
|
+
proceedScheduling({
|
|
609
|
+
iterator,
|
|
610
|
+
nonce,
|
|
611
|
+
getTargetTime,
|
|
612
|
+
playbackRate,
|
|
613
|
+
scheduleAudioNode,
|
|
614
|
+
onScheduled: () => {
|
|
615
|
+
delayHandle.unblock();
|
|
616
|
+
},
|
|
617
|
+
onDestroyed: () => {
|
|
618
|
+
delayHandle.unblock();
|
|
619
|
+
},
|
|
620
|
+
onDone: () => {
|
|
621
|
+
delayHandle.unblock();
|
|
622
|
+
},
|
|
623
|
+
logLevel,
|
|
624
|
+
currentTime: sharedAudioContext.audioContext.currentTime,
|
|
625
|
+
getAudioContextCurrentTimeMockedInTest
|
|
626
|
+
});
|
|
765
627
|
};
|
|
766
|
-
const seek =
|
|
628
|
+
const seek = ({
|
|
767
629
|
newTime,
|
|
768
630
|
nonce,
|
|
769
631
|
playbackRate,
|
|
770
|
-
getIsPlaying,
|
|
771
632
|
scheduleAudioNode,
|
|
772
|
-
|
|
633
|
+
getTargetTime,
|
|
634
|
+
logLevel,
|
|
635
|
+
loop,
|
|
636
|
+
trimBefore,
|
|
637
|
+
trimAfter,
|
|
638
|
+
sequenceOffset,
|
|
639
|
+
sequenceDurationInFrames,
|
|
640
|
+
fps,
|
|
641
|
+
getAudioContextCurrentTimeMockedInTest
|
|
773
642
|
}) => {
|
|
774
|
-
if (
|
|
643
|
+
if (currentSeek.time === newTime && currentSeek.playbackRate === playbackRate && currentSeek.trimBefore === trimBefore && currentSeek.trimAfter === trimAfter && currentSeek.sequenceOffset === sequenceOffset && currentSeek.sequenceDurationInFrames === sequenceDurationInFrames && currentSeek.loop === loop && currentSeek.fps === fps) {
|
|
775
644
|
return;
|
|
776
645
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
playbackRate,
|
|
789
|
-
startFromSecond: newTime,
|
|
790
|
-
getIsPlaying,
|
|
791
|
-
scheduleAudioNode,
|
|
792
|
-
debugAudioScheduling
|
|
793
|
-
});
|
|
646
|
+
currentSeek = {
|
|
647
|
+
time: newTime,
|
|
648
|
+
playbackRate,
|
|
649
|
+
trimBefore,
|
|
650
|
+
trimAfter,
|
|
651
|
+
sequenceOffset,
|
|
652
|
+
sequenceDurationInFrames,
|
|
653
|
+
loop,
|
|
654
|
+
fps
|
|
655
|
+
};
|
|
656
|
+
if (muted) {
|
|
794
657
|
return;
|
|
795
658
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
onAudioChunk({
|
|
806
|
-
getIsPlaying,
|
|
807
|
-
buffer,
|
|
808
|
-
playbackRate,
|
|
809
|
-
scheduleAudioNode,
|
|
810
|
-
debugAudioScheduling
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
});
|
|
814
|
-
if (nonce.isStale()) {
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
if (audioSatisfyResult.type === "ended") {
|
|
659
|
+
if (audioBufferIterator && !audioBufferIterator.isDestroyed()) {
|
|
660
|
+
const queuedPeriod = audioBufferIterator.getQueuedPeriod();
|
|
661
|
+
const queuedPeriodMinusLatency = queuedPeriod ? {
|
|
662
|
+
from: queuedPeriod.from - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT - sharedAudioContext.audioContext.baseLatency - sharedAudioContext.audioContext.outputLatency,
|
|
663
|
+
until: queuedPeriod.until
|
|
664
|
+
} : null;
|
|
665
|
+
const currentTimeIsAlreadyQueued = isAlreadyQueued(newTime, queuedPeriodMinusLatency);
|
|
666
|
+
if (currentTimeIsAlreadyQueued) {
|
|
667
|
+
processNext();
|
|
818
668
|
return;
|
|
819
669
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
playbackRate,
|
|
824
|
-
startFromSecond: newTime,
|
|
825
|
-
getIsPlaying,
|
|
826
|
-
scheduleAudioNode,
|
|
827
|
-
debugAudioScheduling
|
|
828
|
-
});
|
|
670
|
+
const currentIteratorTimestamp = audioBufferIterator.guessNextTimestamp();
|
|
671
|
+
if (currentIteratorTimestamp < newTime && Math.abs(currentIteratorTimestamp - newTime) < 1) {
|
|
672
|
+
processNext();
|
|
829
673
|
return;
|
|
830
674
|
}
|
|
831
|
-
if (audioSatisfyResult.type === "satisfied") {}
|
|
832
675
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
}
|
|
676
|
+
startAudioIterator({
|
|
677
|
+
nonce,
|
|
678
|
+
playbackRate,
|
|
679
|
+
startFromSecond: newTime,
|
|
680
|
+
scheduleAudioNode,
|
|
681
|
+
getTargetTime,
|
|
682
|
+
logLevel,
|
|
683
|
+
loop,
|
|
684
|
+
unscheduleAudioNode: sharedAudioContext.unscheduleAudioNode,
|
|
685
|
+
getAudioContextCurrentTimeMockedInTest
|
|
686
|
+
});
|
|
844
687
|
};
|
|
845
688
|
return {
|
|
846
689
|
startAudioIterator,
|
|
847
|
-
resumeScheduledAudioChunks,
|
|
848
|
-
pausePlayback,
|
|
849
690
|
getAudioBufferIterator: () => audioBufferIterator,
|
|
850
691
|
destroyIterator: () => {
|
|
851
|
-
|
|
852
|
-
audioBufferIterator?.destroy(sharedAudioContext);
|
|
692
|
+
audioBufferIterator?.destroy();
|
|
853
693
|
audioBufferIterator = null;
|
|
854
694
|
if (currentDelayHandle) {
|
|
855
695
|
currentDelayHandle.unblock();
|
|
@@ -858,6 +698,7 @@ var audioIteratorManager = ({
|
|
|
858
698
|
},
|
|
859
699
|
seek,
|
|
860
700
|
getAudioIteratorsCreated: () => audioIteratorsCreated,
|
|
701
|
+
getTotalAudioScheduledInSeconds: () => totalAudioScheduledInSeconds,
|
|
861
702
|
setMuted: (newMuted) => {
|
|
862
703
|
muted = newMuted;
|
|
863
704
|
gainNode.gain.value = muted ? 0 : currentVolume;
|
|
@@ -866,7 +707,8 @@ var audioIteratorManager = ({
|
|
|
866
707
|
currentVolume = Math.max(0, volume);
|
|
867
708
|
gainNode.gain.value = muted ? 0 : currentVolume;
|
|
868
709
|
},
|
|
869
|
-
scheduleAudioChunk
|
|
710
|
+
scheduleAudioChunk,
|
|
711
|
+
waitForNScheduledNodes
|
|
870
712
|
};
|
|
871
713
|
};
|
|
872
714
|
|
|
@@ -886,6 +728,7 @@ var drawPreviewOverlay = ({
|
|
|
886
728
|
"Debug overlay",
|
|
887
729
|
`Video iterators created: ${videoIteratorManager?.getVideoIteratorsCreated()}`,
|
|
888
730
|
`Audio iterators created: ${audioIteratorManager2?.getAudioIteratorsCreated()}`,
|
|
731
|
+
`Audio scheduled: ${(audioIteratorManager2?.getTotalAudioScheduledInSeconds() ?? 0).toFixed(3)}s`,
|
|
889
732
|
`Frames rendered: ${videoIteratorManager?.getFramesRendered()}`,
|
|
890
733
|
`Audio context state: ${audioContextState}`,
|
|
891
734
|
audioTime ? `Audio time: ${((audioTime - anchorValue) * playbackRate).toFixed(3)}s` : null
|
|
@@ -943,7 +786,42 @@ var makeNonceManager = () => {
|
|
|
943
786
|
|
|
944
787
|
// src/video-iterator-manager.ts
|
|
945
788
|
import { CanvasSink } from "mediabunny";
|
|
946
|
-
import { Internals as
|
|
789
|
+
import { Internals as Internals3 } from "remotion";
|
|
790
|
+
|
|
791
|
+
// src/prewarm-iterator-for-looping.ts
|
|
792
|
+
var makePrewarmedVideoIteratorCache = (videoSink) => {
|
|
793
|
+
const prewarmedVideoIterators = new Map;
|
|
794
|
+
const prewarmIteratorForLooping = ({ timeToSeek }) => {
|
|
795
|
+
if (!prewarmedVideoIterators.has(timeToSeek)) {
|
|
796
|
+
prewarmedVideoIterators.set(timeToSeek, videoSink.canvases(timeToSeek));
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
const makeIteratorOrUsePrewarmed = (timeToSeek) => {
|
|
800
|
+
const prewarmedIterator = prewarmedVideoIterators.get(timeToSeek);
|
|
801
|
+
if (prewarmedIterator) {
|
|
802
|
+
prewarmedVideoIterators.delete(timeToSeek);
|
|
803
|
+
return prewarmedIterator;
|
|
804
|
+
}
|
|
805
|
+
const iterator = videoSink.canvases(timeToSeek);
|
|
806
|
+
return iterator;
|
|
807
|
+
};
|
|
808
|
+
const destroy = () => {
|
|
809
|
+
for (const iterator of prewarmedVideoIterators.values()) {
|
|
810
|
+
iterator.return();
|
|
811
|
+
}
|
|
812
|
+
prewarmedVideoIterators.clear();
|
|
813
|
+
};
|
|
814
|
+
return {
|
|
815
|
+
prewarmIteratorForLooping,
|
|
816
|
+
makeIteratorOrUsePrewarmed,
|
|
817
|
+
destroy
|
|
818
|
+
};
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// src/helpers/round-to-4-digits.ts
|
|
822
|
+
var roundTo4Digits = (timestamp) => {
|
|
823
|
+
return Math.round(timestamp * 1000) / 1000;
|
|
824
|
+
};
|
|
947
825
|
|
|
948
826
|
// src/video/video-preview-iterator.ts
|
|
949
827
|
var createVideoIterator = async (timeToSeek, cache) => {
|
|
@@ -1084,7 +962,7 @@ var videoIteratorManager = ({
|
|
|
1084
962
|
logLevel,
|
|
1085
963
|
getOnVideoFrameCallback,
|
|
1086
964
|
videoTrack,
|
|
1087
|
-
|
|
965
|
+
getLoopSegmentMediaEndTimestamp,
|
|
1088
966
|
getStartTime,
|
|
1089
967
|
getIsLooping
|
|
1090
968
|
}) => {
|
|
@@ -1115,7 +993,7 @@ var videoIteratorManager = ({
|
|
|
1115
993
|
if (callback) {
|
|
1116
994
|
callback(frame.canvas);
|
|
1117
995
|
}
|
|
1118
|
-
|
|
996
|
+
Internals3.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
|
|
1119
997
|
};
|
|
1120
998
|
const startVideoIterator = async (timeToSeek, nonce) => {
|
|
1121
999
|
let __stack = [];
|
|
@@ -1150,7 +1028,7 @@ var videoIteratorManager = ({
|
|
|
1150
1028
|
return;
|
|
1151
1029
|
}
|
|
1152
1030
|
if (getIsLooping()) {
|
|
1153
|
-
if (
|
|
1031
|
+
if (getLoopSegmentMediaEndTimestamp() - newTime < 1) {
|
|
1154
1032
|
prewarmedVideoIteratorCache.prewarmIteratorForLooping({
|
|
1155
1033
|
timeToSeek: getStartTime()
|
|
1156
1034
|
});
|
|
@@ -1200,16 +1078,15 @@ class MediaPlayer {
|
|
|
1200
1078
|
sharedAudioContext;
|
|
1201
1079
|
audioIteratorManager = null;
|
|
1202
1080
|
videoIteratorManager = null;
|
|
1203
|
-
sequenceOffset;
|
|
1204
1081
|
playing = false;
|
|
1205
1082
|
loop = false;
|
|
1206
1083
|
fps;
|
|
1207
1084
|
trimBefore;
|
|
1208
1085
|
trimAfter;
|
|
1209
|
-
|
|
1086
|
+
sequenceDurationInFrames;
|
|
1087
|
+
sequenceOffset;
|
|
1210
1088
|
totalDuration;
|
|
1211
1089
|
debugOverlay = false;
|
|
1212
|
-
debugAudioScheduling = false;
|
|
1213
1090
|
nonceManager;
|
|
1214
1091
|
onVideoFrameCallback = null;
|
|
1215
1092
|
initializationPromise = null;
|
|
@@ -1230,7 +1107,6 @@ class MediaPlayer {
|
|
|
1230
1107
|
audioStreamIndex,
|
|
1231
1108
|
fps,
|
|
1232
1109
|
debugOverlay,
|
|
1233
|
-
debugAudioScheduling,
|
|
1234
1110
|
bufferState,
|
|
1235
1111
|
isPremounting,
|
|
1236
1112
|
isPostmounting,
|
|
@@ -1252,11 +1128,10 @@ class MediaPlayer {
|
|
|
1252
1128
|
this.audioStreamIndex = audioStreamIndex ?? 0;
|
|
1253
1129
|
this.fps = fps;
|
|
1254
1130
|
this.debugOverlay = debugOverlay;
|
|
1255
|
-
this.debugAudioScheduling = debugAudioScheduling;
|
|
1256
1131
|
this.bufferState = bufferState;
|
|
1257
1132
|
this.isPremounting = isPremounting;
|
|
1258
1133
|
this.isPostmounting = isPostmounting;
|
|
1259
|
-
this.
|
|
1134
|
+
this.sequenceDurationInFrames = durationInFrames;
|
|
1260
1135
|
this.nonceManager = makeNonceManager();
|
|
1261
1136
|
this.onVideoFrameCallback = onVideoFrameCallback;
|
|
1262
1137
|
this.playing = playing;
|
|
@@ -1293,8 +1168,14 @@ class MediaPlayer {
|
|
|
1293
1168
|
getStartTime() {
|
|
1294
1169
|
return (this.trimBefore ?? 0) / this.fps;
|
|
1295
1170
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1171
|
+
getSequenceEndTimestamp() {
|
|
1172
|
+
return this.sequenceDurationInFrames / this.fps * this.playbackRate + this.getStartTime();
|
|
1173
|
+
}
|
|
1174
|
+
getSequenceDurationInSeconds() {
|
|
1175
|
+
return this.sequenceDurationInFrames / this.fps;
|
|
1176
|
+
}
|
|
1177
|
+
getMediaEndTimestamp() {
|
|
1178
|
+
return calculateEndTime({
|
|
1298
1179
|
mediaDurationInSeconds: this.totalDuration,
|
|
1299
1180
|
ifNoMediaDuration: "fail",
|
|
1300
1181
|
src: this.src,
|
|
@@ -1302,11 +1183,9 @@ class MediaPlayer {
|
|
|
1302
1183
|
trimBefore: this.trimBefore,
|
|
1303
1184
|
fps: this.fps
|
|
1304
1185
|
});
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
const sequenceEndMediaTime = this.durationInFrames / this.fps * this.playbackRate + (this.trimBefore ?? 0) / this.fps;
|
|
1309
|
-
return Math.min(mediaEndTime, sequenceEndMediaTime);
|
|
1186
|
+
}
|
|
1187
|
+
getLoopSegmentMediaEndTimestamp() {
|
|
1188
|
+
return Math.min(this.getMediaEndTimestamp(), this.getSequenceEndTimestamp());
|
|
1310
1189
|
}
|
|
1311
1190
|
async _initialize(startTimeUnresolved, initialMuted) {
|
|
1312
1191
|
let __stack = [];
|
|
@@ -1326,7 +1205,7 @@ class MediaPlayer {
|
|
|
1326
1205
|
if (isNetworkError(err)) {
|
|
1327
1206
|
throw error;
|
|
1328
1207
|
}
|
|
1329
|
-
|
|
1208
|
+
Internals4.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
|
|
1330
1209
|
return { type: "unknown-container-format" };
|
|
1331
1210
|
}
|
|
1332
1211
|
const [durationInSeconds, videoTrack, audioTracks] = await Promise.all([
|
|
@@ -1358,7 +1237,7 @@ class MediaPlayer {
|
|
|
1358
1237
|
getOnVideoFrameCallback: () => this.onVideoFrameCallback,
|
|
1359
1238
|
logLevel: this.logLevel,
|
|
1360
1239
|
drawDebugOverlay: this.drawDebugOverlay,
|
|
1361
|
-
|
|
1240
|
+
getLoopSegmentMediaEndTimestamp: () => this.getLoopSegmentMediaEndTimestamp(),
|
|
1362
1241
|
getStartTime: () => this.getStartTime(),
|
|
1363
1242
|
getIsLooping: () => this.loop
|
|
1364
1243
|
});
|
|
@@ -1379,11 +1258,19 @@ class MediaPlayer {
|
|
|
1379
1258
|
audioTrack,
|
|
1380
1259
|
delayPlaybackHandleIfNotPremounting: this.delayPlaybackHandleIfNotPremounting,
|
|
1381
1260
|
sharedAudioContext: this.sharedAudioContext,
|
|
1382
|
-
|
|
1383
|
-
|
|
1261
|
+
getMediaEndTimestamp: () => this.getMediaEndTimestamp(),
|
|
1262
|
+
getSequenceEndTimestamp: () => this.getSequenceEndTimestamp(),
|
|
1384
1263
|
getStartTime: () => this.getStartTime(),
|
|
1385
1264
|
initialMuted,
|
|
1386
|
-
drawDebugOverlay: this.drawDebugOverlay
|
|
1265
|
+
drawDebugOverlay: this.drawDebugOverlay,
|
|
1266
|
+
initialPlaybackRate: this.playbackRate * this.globalPlaybackRate,
|
|
1267
|
+
getSequenceDurationInSeconds: () => this.getSequenceDurationInSeconds(),
|
|
1268
|
+
initialTrimBefore: this.trimBefore,
|
|
1269
|
+
initialTrimAfter: this.trimAfter,
|
|
1270
|
+
initialSequenceOffset: this.sequenceOffset,
|
|
1271
|
+
initialSequenceDurationInFrames: this.sequenceDurationInFrames,
|
|
1272
|
+
initialLoop: this.loop,
|
|
1273
|
+
initialFps: this.fps
|
|
1387
1274
|
});
|
|
1388
1275
|
}
|
|
1389
1276
|
const nonce = this.nonceManager.createAsyncOperation();
|
|
@@ -1393,9 +1280,12 @@ class MediaPlayer {
|
|
|
1393
1280
|
nonce,
|
|
1394
1281
|
playbackRate: this.playbackRate * this.globalPlaybackRate,
|
|
1395
1282
|
startFromSecond: startTime,
|
|
1396
|
-
getIsPlaying: () => this.playing,
|
|
1397
1283
|
scheduleAudioNode: this.scheduleAudioNode,
|
|
1398
|
-
|
|
1284
|
+
getTargetTime: this.getTargetTime,
|
|
1285
|
+
logLevel: this.logLevel,
|
|
1286
|
+
loop: this.loop,
|
|
1287
|
+
unscheduleAudioNode: this.sharedAudioContext.unscheduleAudioNode,
|
|
1288
|
+
getAudioContextCurrentTimeMockedInTest: () => this.sharedAudioContext.audioContext.currentTime
|
|
1399
1289
|
}) : Promise.resolve(),
|
|
1400
1290
|
this.videoIteratorManager ? this.videoIteratorManager.startVideoIterator(startTime, nonce) : Promise.resolve()
|
|
1401
1291
|
]);
|
|
@@ -1403,16 +1293,16 @@ class MediaPlayer {
|
|
|
1403
1293
|
if (this.isDisposalError()) {
|
|
1404
1294
|
return { type: "disposed" };
|
|
1405
1295
|
}
|
|
1406
|
-
|
|
1296
|
+
Internals4.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
|
|
1407
1297
|
}
|
|
1408
1298
|
return { type: "success", durationInSeconds };
|
|
1409
1299
|
} catch (error) {
|
|
1410
1300
|
const err = error;
|
|
1411
1301
|
if (isNetworkError(err)) {
|
|
1412
|
-
|
|
1302
|
+
Internals4.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
|
|
1413
1303
|
return { type: "network-error" };
|
|
1414
1304
|
}
|
|
1415
|
-
|
|
1305
|
+
Internals4.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
|
|
1416
1306
|
throw error;
|
|
1417
1307
|
}
|
|
1418
1308
|
} catch (_catch) {
|
|
@@ -1438,21 +1328,27 @@ class MediaPlayer {
|
|
|
1438
1328
|
if (nonce.isStale()) {
|
|
1439
1329
|
return;
|
|
1440
1330
|
}
|
|
1441
|
-
const shouldSeekAudio = this.audioIteratorManager && this.getAudioPlaybackTime(this.sharedAudioContext?.audioContext.currentTime ?? 0) !== newTime;
|
|
1442
1331
|
try {
|
|
1443
1332
|
await Promise.all([
|
|
1444
1333
|
this.videoIteratorManager?.seek({
|
|
1445
1334
|
newTime,
|
|
1446
1335
|
nonce
|
|
1447
1336
|
}),
|
|
1448
|
-
|
|
1337
|
+
this.audioIteratorManager?.seek({
|
|
1449
1338
|
newTime,
|
|
1450
1339
|
nonce,
|
|
1451
1340
|
playbackRate: this.playbackRate * this.globalPlaybackRate,
|
|
1452
|
-
|
|
1341
|
+
getTargetTime: this.getTargetTime,
|
|
1342
|
+
logLevel: this.logLevel,
|
|
1343
|
+
loop: this.loop,
|
|
1344
|
+
trimBefore: this.trimBefore,
|
|
1345
|
+
trimAfter: this.trimAfter,
|
|
1346
|
+
sequenceOffset: this.sequenceOffset,
|
|
1347
|
+
sequenceDurationInFrames: this.sequenceDurationInFrames,
|
|
1348
|
+
fps: this.fps,
|
|
1453
1349
|
scheduleAudioNode: this.scheduleAudioNode,
|
|
1454
|
-
|
|
1455
|
-
})
|
|
1350
|
+
getAudioContextCurrentTimeMockedInTest: () => this.sharedAudioContext.audioContext.currentTime
|
|
1351
|
+
})
|
|
1456
1352
|
]);
|
|
1457
1353
|
} catch (error) {
|
|
1458
1354
|
if (this.isDisposalError()) {
|
|
@@ -1461,17 +1357,7 @@ class MediaPlayer {
|
|
|
1461
1357
|
throw error;
|
|
1462
1358
|
}
|
|
1463
1359
|
}
|
|
1464
|
-
playAudio() {
|
|
1465
|
-
if (this.audioIteratorManager && this.sharedAudioContext?.audioContext.state === "running" && (this.sharedAudioContext?.audioContext?.getOutputTimestamp().contextTime ?? 0) > 0) {
|
|
1466
|
-
this.audioIteratorManager.resumeScheduledAudioChunks({
|
|
1467
|
-
playbackRate: this.playbackRate * this.globalPlaybackRate,
|
|
1468
|
-
scheduleAudioNode: this.scheduleAudioNode,
|
|
1469
|
-
debugAudioScheduling: this.debugAudioScheduling
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
1360
|
play() {
|
|
1474
|
-
this.playAudio();
|
|
1475
1361
|
if (this.playing) {
|
|
1476
1362
|
return;
|
|
1477
1363
|
}
|
|
@@ -1498,7 +1384,6 @@ class MediaPlayer {
|
|
|
1498
1384
|
return;
|
|
1499
1385
|
}
|
|
1500
1386
|
this.playing = false;
|
|
1501
|
-
this.audioIteratorManager?.pausePlayback();
|
|
1502
1387
|
this.drawDebugOverlay();
|
|
1503
1388
|
}
|
|
1504
1389
|
setMuted(muted) {
|
|
@@ -1523,73 +1408,46 @@ class MediaPlayer {
|
|
|
1523
1408
|
src: this.src
|
|
1524
1409
|
});
|
|
1525
1410
|
}
|
|
1526
|
-
async updateAfterTrimChange(unloopedTimeInSeconds) {
|
|
1527
|
-
if (!this.audioIteratorManager && !this.videoIteratorManager) {
|
|
1528
|
-
return;
|
|
1529
|
-
}
|
|
1530
|
-
const newMediaTime = this.getTrimmedTime(unloopedTimeInSeconds);
|
|
1531
|
-
this.audioIteratorManager?.destroyIterator();
|
|
1532
|
-
if (newMediaTime !== null) {
|
|
1533
|
-
if (!this.playing && this.videoIteratorManager) {
|
|
1534
|
-
await this.seekToWithQueue(newMediaTime);
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
1411
|
async setTrimBefore(trimBefore, unloopedTimeInSeconds) {
|
|
1539
1412
|
if (this.trimBefore !== trimBefore) {
|
|
1540
1413
|
this.trimBefore = trimBefore;
|
|
1541
|
-
|
|
1414
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1415
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1542
1416
|
}
|
|
1543
1417
|
}
|
|
1544
1418
|
async setTrimAfter(trimAfter, unloopedTimeInSeconds) {
|
|
1545
1419
|
if (this.trimAfter !== trimAfter) {
|
|
1546
1420
|
this.trimAfter = trimAfter;
|
|
1547
|
-
|
|
1421
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1422
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1548
1423
|
}
|
|
1549
1424
|
}
|
|
1550
1425
|
setDebugOverlay(debugOverlay) {
|
|
1551
1426
|
this.debugOverlay = debugOverlay;
|
|
1552
1427
|
}
|
|
1553
|
-
setDebugAudioScheduling(debugAudioScheduling) {
|
|
1554
|
-
this.debugAudioScheduling = debugAudioScheduling;
|
|
1555
|
-
}
|
|
1556
|
-
rescheduleAudioChunks() {
|
|
1557
|
-
if (!this.audioIteratorManager) {
|
|
1558
|
-
return;
|
|
1559
|
-
}
|
|
1560
|
-
if (!this.sharedAudioContext) {
|
|
1561
|
-
return;
|
|
1562
|
-
}
|
|
1563
|
-
const iterator = this.audioIteratorManager.getAudioBufferIterator();
|
|
1564
|
-
if (!iterator) {
|
|
1565
|
-
return;
|
|
1566
|
-
}
|
|
1567
|
-
iterator.moveQueuedChunksToPauseQueue();
|
|
1568
|
-
if (this.playing && this.sharedAudioContext.audioContext.state === "running" && (this.sharedAudioContext.audioContext?.getOutputTimestamp().contextTime ?? 0) > 0) {
|
|
1569
|
-
this.audioIteratorManager.resumeScheduledAudioChunks({
|
|
1570
|
-
playbackRate: this.playbackRate * this.globalPlaybackRate,
|
|
1571
|
-
scheduleAudioNode: this.scheduleAudioNode,
|
|
1572
|
-
debugAudioScheduling: this.debugAudioScheduling
|
|
1573
|
-
});
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
1428
|
async setPlaybackRate(rate, unloopedTimeInSeconds) {
|
|
1577
1429
|
const previousRate = this.playbackRate;
|
|
1578
1430
|
if (previousRate !== rate) {
|
|
1579
1431
|
this.playbackRate = rate;
|
|
1580
|
-
this.
|
|
1432
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1581
1433
|
await this.seekTo(unloopedTimeInSeconds);
|
|
1582
1434
|
}
|
|
1583
1435
|
}
|
|
1584
|
-
setGlobalPlaybackRate(rate) {
|
|
1436
|
+
async setGlobalPlaybackRate(rate, unloopedTimeInSeconds) {
|
|
1585
1437
|
const previousRate = this.globalPlaybackRate;
|
|
1586
1438
|
if (previousRate !== rate) {
|
|
1587
1439
|
this.globalPlaybackRate = rate;
|
|
1588
|
-
this.
|
|
1440
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1441
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1589
1442
|
}
|
|
1590
1443
|
}
|
|
1591
|
-
setFps(fps) {
|
|
1592
|
-
|
|
1444
|
+
async setFps(fps, unloopedTimeInSeconds) {
|
|
1445
|
+
const previousFps = this.fps;
|
|
1446
|
+
if (previousFps !== fps) {
|
|
1447
|
+
this.fps = fps;
|
|
1448
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1449
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1450
|
+
}
|
|
1593
1451
|
}
|
|
1594
1452
|
setIsPremounting(isPremounting) {
|
|
1595
1453
|
this.isPremounting = isPremounting;
|
|
@@ -1597,14 +1455,28 @@ class MediaPlayer {
|
|
|
1597
1455
|
setIsPostmounting(isPostmounting) {
|
|
1598
1456
|
this.isPostmounting = isPostmounting;
|
|
1599
1457
|
}
|
|
1600
|
-
setLoop(loop) {
|
|
1601
|
-
|
|
1458
|
+
async setLoop(loop, unloopedTimeInSeconds) {
|
|
1459
|
+
const previousLoop = this.loop;
|
|
1460
|
+
if (previousLoop !== loop) {
|
|
1461
|
+
this.loop = loop;
|
|
1462
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1463
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1464
|
+
}
|
|
1602
1465
|
}
|
|
1603
|
-
setSequenceOffset(offset) {
|
|
1604
|
-
this.sequenceOffset
|
|
1466
|
+
async setSequenceOffset(offset, unloopedTimeInSeconds) {
|
|
1467
|
+
const previousOffset = this.sequenceOffset;
|
|
1468
|
+
if (previousOffset !== offset) {
|
|
1469
|
+
this.sequenceOffset = offset;
|
|
1470
|
+
this.audioIteratorManager?.destroyIterator();
|
|
1471
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1472
|
+
}
|
|
1605
1473
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1474
|
+
async setSequenceDurationInFrames(sequenceDurationInFrames, unloopedTimeInSeconds) {
|
|
1475
|
+
const previousDuration = this.sequenceDurationInFrames;
|
|
1476
|
+
if (previousDuration !== sequenceDurationInFrames) {
|
|
1477
|
+
this.sequenceDurationInFrames = sequenceDurationInFrames;
|
|
1478
|
+
await this.seekTo(unloopedTimeInSeconds);
|
|
1479
|
+
}
|
|
1608
1480
|
}
|
|
1609
1481
|
async dispose() {
|
|
1610
1482
|
if (this.initializationPromise) {
|
|
@@ -1617,41 +1489,59 @@ class MediaPlayer {
|
|
|
1617
1489
|
this.audioIteratorManager?.destroyIterator();
|
|
1618
1490
|
this.input.dispose();
|
|
1619
1491
|
}
|
|
1620
|
-
|
|
1492
|
+
getTargetTime = (mediaTimestamp, currentTime) => {
|
|
1621
1493
|
if (!this.sharedAudioContext) {
|
|
1622
1494
|
throw new Error("Shared audio context not found");
|
|
1623
1495
|
}
|
|
1624
|
-
const { audioContext } = this.sharedAudioContext;
|
|
1625
|
-
const { currentTime } = audioContext;
|
|
1626
1496
|
const globalTime = (currentTime - this.sharedAudioContext.audioSyncAnchor.value) * this.globalPlaybackRate;
|
|
1627
1497
|
const timeInSeconds = globalTime - this.sequenceOffset;
|
|
1628
1498
|
const localTime = this.getTrimmedTime(timeInSeconds);
|
|
1629
1499
|
if (localTime === null) {
|
|
1630
|
-
return
|
|
1500
|
+
return null;
|
|
1631
1501
|
}
|
|
1632
1502
|
const targetTime = (mediaTimestamp - localTime) / (this.playbackRate * this.globalPlaybackRate);
|
|
1503
|
+
return targetTime;
|
|
1504
|
+
};
|
|
1505
|
+
scheduleAudioNode = (node, mediaTimestamp, originalUnloopedMediaTimestamp, currentTime) => {
|
|
1506
|
+
if (!this.sharedAudioContext) {
|
|
1507
|
+
throw new Error("Shared audio context not found");
|
|
1508
|
+
}
|
|
1509
|
+
const targetTime = this.getTargetTime(mediaTimestamp, currentTime);
|
|
1510
|
+
if (targetTime === null) {
|
|
1511
|
+
return {
|
|
1512
|
+
type: "not-started",
|
|
1513
|
+
reason: "no target for" + mediaTimestamp.toFixed(3) + "," + currentTime.toFixed(3)
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
const sequenceStartTime = this.getStartTime();
|
|
1517
|
+
const loopSegmentMediaEndTimestamp = this.getLoopSegmentMediaEndTimestamp();
|
|
1518
|
+
const offset = getOffset({
|
|
1519
|
+
mediaTimestamp,
|
|
1520
|
+
targetTime,
|
|
1521
|
+
sequenceStartTime
|
|
1522
|
+
});
|
|
1523
|
+
const duration = getDurationOfNode({
|
|
1524
|
+
bufferDuration: node.buffer?.duration ?? 0,
|
|
1525
|
+
loopSegmentMediaEndTimestamp,
|
|
1526
|
+
offset,
|
|
1527
|
+
originalUnloopedMediaTimestamp
|
|
1528
|
+
});
|
|
1529
|
+
const scheduledTime = getScheduledTime({
|
|
1530
|
+
mediaTimestamp,
|
|
1531
|
+
targetTime,
|
|
1532
|
+
currentTime,
|
|
1533
|
+
sequenceStartTime
|
|
1534
|
+
});
|
|
1633
1535
|
return this.sharedAudioContext.scheduleAudioNode({
|
|
1634
1536
|
node,
|
|
1635
1537
|
mediaTimestamp,
|
|
1636
|
-
targetTime,
|
|
1637
1538
|
currentTime,
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1539
|
+
scheduledTime,
|
|
1540
|
+
duration,
|
|
1541
|
+
offset,
|
|
1542
|
+
originalUnloopedMediaTimestamp
|
|
1641
1543
|
});
|
|
1642
1544
|
};
|
|
1643
|
-
getAudioPlaybackTime(currentTime) {
|
|
1644
|
-
if (!this.sharedAudioContext) {
|
|
1645
|
-
throw new Error("Shared audio context not found");
|
|
1646
|
-
}
|
|
1647
|
-
const globalTime = (currentTime - this.sharedAudioContext.audioSyncAnchor.value) * this.globalPlaybackRate;
|
|
1648
|
-
const localTime = globalTime - this.sequenceOffset;
|
|
1649
|
-
const trimmedTime = this.getTrimmedTime(localTime);
|
|
1650
|
-
if (trimmedTime !== null) {
|
|
1651
|
-
return trimmedTime;
|
|
1652
|
-
}
|
|
1653
|
-
return localTime * this.playbackRate + (this.trimBefore ?? 0) / this.fps;
|
|
1654
|
-
}
|
|
1655
1545
|
setVideoFrameCallback(callback) {
|
|
1656
1546
|
this.onVideoFrameCallback = callback;
|
|
1657
1547
|
}
|
|
@@ -1671,6 +1561,12 @@ class MediaPlayer {
|
|
|
1671
1561
|
});
|
|
1672
1562
|
}
|
|
1673
1563
|
};
|
|
1564
|
+
audioSyncAnchorChanged = () => {
|
|
1565
|
+
if (!this.audioIteratorManager) {
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
this.audioIteratorManager.destroyIterator();
|
|
1569
|
+
};
|
|
1674
1570
|
}
|
|
1675
1571
|
|
|
1676
1572
|
// src/on-error.ts
|
|
@@ -1696,7 +1592,7 @@ var callOnErrorAndResolve = ({
|
|
|
1696
1592
|
|
|
1697
1593
|
// src/show-in-timeline.ts
|
|
1698
1594
|
import { useMemo } from "react";
|
|
1699
|
-
import { Internals as
|
|
1595
|
+
import { Internals as Internals5, useVideoConfig } from "remotion";
|
|
1700
1596
|
var useLoopDisplay = ({
|
|
1701
1597
|
loop,
|
|
1702
1598
|
mediaDurationInSeconds,
|
|
@@ -1709,7 +1605,7 @@ var useLoopDisplay = ({
|
|
|
1709
1605
|
if (!loop || !mediaDurationInSeconds) {
|
|
1710
1606
|
return;
|
|
1711
1607
|
}
|
|
1712
|
-
const durationInFrames =
|
|
1608
|
+
const durationInFrames = Internals5.calculateMediaDuration({
|
|
1713
1609
|
mediaDurationInFrames: mediaDurationInSeconds * fps,
|
|
1714
1610
|
playbackRate,
|
|
1715
1611
|
trimAfter,
|
|
@@ -1735,7 +1631,7 @@ var useLoopDisplay = ({
|
|
|
1735
1631
|
|
|
1736
1632
|
// src/use-common-effects.ts
|
|
1737
1633
|
import { useContext, useLayoutEffect } from "react";
|
|
1738
|
-
import { Internals as
|
|
1634
|
+
import { Internals as Internals6 } from "remotion";
|
|
1739
1635
|
var useCommonEffects = ({
|
|
1740
1636
|
mediaPlayerRef,
|
|
1741
1637
|
mediaPlayerReady,
|
|
@@ -1752,39 +1648,14 @@ var useCommonEffects = ({
|
|
|
1752
1648
|
fps,
|
|
1753
1649
|
sequenceOffset,
|
|
1754
1650
|
loop,
|
|
1755
|
-
debugAudioScheduling,
|
|
1756
1651
|
durationInFrames,
|
|
1757
1652
|
isPremounting,
|
|
1758
1653
|
isPostmounting,
|
|
1759
1654
|
currentTime,
|
|
1760
1655
|
logLevel,
|
|
1761
|
-
sharedAudioContext,
|
|
1762
1656
|
label
|
|
1763
1657
|
}) => {
|
|
1764
|
-
const
|
|
1765
|
-
const { playing: playingWhilePremounting } = useContext(Internals8.PremountContext);
|
|
1766
|
-
useLayoutEffect(() => {
|
|
1767
|
-
if (sharedAudioContext?.audioContext && sharedAudioContext.audioSyncAnchor) {
|
|
1768
|
-
setGlobalTimeAnchor({
|
|
1769
|
-
audioContext: sharedAudioContext.audioContext,
|
|
1770
|
-
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
1771
|
-
absoluteTimeInSeconds: absoluteTime / fps,
|
|
1772
|
-
globalPlaybackRate,
|
|
1773
|
-
debugAudioScheduling,
|
|
1774
|
-
logLevel
|
|
1775
|
-
});
|
|
1776
|
-
}
|
|
1777
|
-
}, [
|
|
1778
|
-
absoluteTime,
|
|
1779
|
-
globalPlaybackRate,
|
|
1780
|
-
sharedAudioContext,
|
|
1781
|
-
fps,
|
|
1782
|
-
debugAudioScheduling,
|
|
1783
|
-
logLevel
|
|
1784
|
-
]);
|
|
1785
|
-
if (playingWhilePremounting) {
|
|
1786
|
-
mediaPlayerRef.current?.playAudio();
|
|
1787
|
-
}
|
|
1658
|
+
const sharedAudioContext = useContext(Internals6.SharedAudioContext);
|
|
1788
1659
|
useLayoutEffect(() => {
|
|
1789
1660
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1790
1661
|
if (!mediaPlayer)
|
|
@@ -1802,6 +1673,18 @@ var useCommonEffects = ({
|
|
|
1802
1673
|
frame,
|
|
1803
1674
|
mediaPlayerRef
|
|
1804
1675
|
]);
|
|
1676
|
+
useLayoutEffect(() => {
|
|
1677
|
+
if (!sharedAudioContext)
|
|
1678
|
+
return;
|
|
1679
|
+
const { remove } = sharedAudioContext.audioSyncAnchorEmitter.subscribe((event) => {
|
|
1680
|
+
if (event === "changed") {
|
|
1681
|
+
mediaPlayerRef.current?.audioSyncAnchorChanged();
|
|
1682
|
+
}
|
|
1683
|
+
});
|
|
1684
|
+
return () => {
|
|
1685
|
+
remove();
|
|
1686
|
+
};
|
|
1687
|
+
}, [sharedAudioContext, mediaPlayerRef]);
|
|
1805
1688
|
useLayoutEffect(() => {
|
|
1806
1689
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1807
1690
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
@@ -1841,22 +1724,22 @@ var useCommonEffects = ({
|
|
|
1841
1724
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
1842
1725
|
return;
|
|
1843
1726
|
}
|
|
1844
|
-
mediaPlayer.setGlobalPlaybackRate(globalPlaybackRate);
|
|
1845
|
-
}, [globalPlaybackRate, mediaPlayerReady, mediaPlayerRef]);
|
|
1727
|
+
mediaPlayer.setGlobalPlaybackRate(globalPlaybackRate, currentTimeRef.current);
|
|
1728
|
+
}, [globalPlaybackRate, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
|
|
1846
1729
|
useLayoutEffect(() => {
|
|
1847
1730
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1848
1731
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
1849
1732
|
return;
|
|
1850
1733
|
}
|
|
1851
|
-
mediaPlayer.setLoop(loop);
|
|
1852
|
-
}, [loop, mediaPlayerReady, mediaPlayerRef]);
|
|
1734
|
+
mediaPlayer.setLoop(loop, currentTimeRef.current);
|
|
1735
|
+
}, [loop, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
|
|
1853
1736
|
useLayoutEffect(() => {
|
|
1854
1737
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1855
1738
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
1856
1739
|
return;
|
|
1857
1740
|
}
|
|
1858
|
-
mediaPlayer.
|
|
1859
|
-
}, [durationInFrames, mediaPlayerReady, mediaPlayerRef]);
|
|
1741
|
+
mediaPlayer.setSequenceDurationInFrames(durationInFrames, currentTimeRef.current);
|
|
1742
|
+
}, [durationInFrames, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
|
|
1860
1743
|
useLayoutEffect(() => {
|
|
1861
1744
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1862
1745
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
@@ -1876,34 +1759,27 @@ var useCommonEffects = ({
|
|
|
1876
1759
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
1877
1760
|
return;
|
|
1878
1761
|
}
|
|
1879
|
-
mediaPlayer.setFps(fps);
|
|
1880
|
-
}, [fps, mediaPlayerReady, mediaPlayerRef]);
|
|
1881
|
-
useLayoutEffect(() => {
|
|
1882
|
-
const mediaPlayer = mediaPlayerRef.current;
|
|
1883
|
-
if (!mediaPlayer || !mediaPlayerReady) {
|
|
1884
|
-
return;
|
|
1885
|
-
}
|
|
1886
|
-
mediaPlayer.setSequenceOffset(sequenceOffset);
|
|
1887
|
-
}, [sequenceOffset, mediaPlayerReady, mediaPlayerRef]);
|
|
1762
|
+
mediaPlayer.setFps(fps, currentTimeRef.current);
|
|
1763
|
+
}, [fps, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
|
|
1888
1764
|
useLayoutEffect(() => {
|
|
1889
1765
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1890
1766
|
if (!mediaPlayer || !mediaPlayerReady) {
|
|
1891
1767
|
return;
|
|
1892
1768
|
}
|
|
1893
|
-
mediaPlayer.
|
|
1894
|
-
}, [
|
|
1769
|
+
mediaPlayer.setSequenceOffset(sequenceOffset, currentTimeRef.current);
|
|
1770
|
+
}, [sequenceOffset, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
|
|
1895
1771
|
useLayoutEffect(() => {
|
|
1896
1772
|
const mediaPlayer = mediaPlayerRef.current;
|
|
1897
1773
|
if (!mediaPlayer || !mediaPlayerReady)
|
|
1898
1774
|
return;
|
|
1899
1775
|
mediaPlayer.seekTo(currentTime).catch(() => {});
|
|
1900
|
-
|
|
1776
|
+
Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[${label}] Updating target time to ${currentTime.toFixed(3)}s`);
|
|
1901
1777
|
}, [currentTime, logLevel, mediaPlayerReady, label, mediaPlayerRef]);
|
|
1902
1778
|
};
|
|
1903
1779
|
|
|
1904
1780
|
// src/use-media-in-timeline.ts
|
|
1905
1781
|
import { useContext as useContext2, useState, useEffect } from "react";
|
|
1906
|
-
import { Internals as
|
|
1782
|
+
import { Internals as Internals7, useCurrentFrame } from "remotion";
|
|
1907
1783
|
var useMediaInTimeline = ({
|
|
1908
1784
|
volume,
|
|
1909
1785
|
mediaVolume,
|
|
@@ -1920,9 +1796,9 @@ var useMediaInTimeline = ({
|
|
|
1920
1796
|
trimAfter,
|
|
1921
1797
|
controls
|
|
1922
1798
|
}) => {
|
|
1923
|
-
const parentSequence = useContext2(
|
|
1924
|
-
const startsAt =
|
|
1925
|
-
const { registerSequence, unregisterSequence } = useContext2(
|
|
1799
|
+
const parentSequence = useContext2(Internals7.SequenceContext);
|
|
1800
|
+
const startsAt = Internals7.useMediaStartsAt();
|
|
1801
|
+
const { registerSequence, unregisterSequence } = useContext2(Internals7.SequenceManager);
|
|
1926
1802
|
const [sequenceId] = useState(() => String(Math.random()));
|
|
1927
1803
|
const [mediaId] = useState(() => String(Math.random()));
|
|
1928
1804
|
const frame = useCurrentFrame();
|
|
@@ -1934,7 +1810,7 @@ var useMediaInTimeline = ({
|
|
|
1934
1810
|
rootId,
|
|
1935
1811
|
isStudio,
|
|
1936
1812
|
finalDisplayName
|
|
1937
|
-
} =
|
|
1813
|
+
} = Internals7.useBasicMediaInTimeline({
|
|
1938
1814
|
volume,
|
|
1939
1815
|
mediaVolume,
|
|
1940
1816
|
mediaType,
|
|
@@ -2044,7 +1920,7 @@ var {
|
|
|
2044
1920
|
warnAboutTooHighVolume,
|
|
2045
1921
|
usePreload,
|
|
2046
1922
|
SequenceContext
|
|
2047
|
-
} =
|
|
1923
|
+
} = Internals8;
|
|
2048
1924
|
var AudioForPreviewAssertedShowing = ({
|
|
2049
1925
|
src,
|
|
2050
1926
|
playbackRate,
|
|
@@ -2062,7 +1938,6 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2062
1938
|
toneFrequency,
|
|
2063
1939
|
audioStreamIndex,
|
|
2064
1940
|
fallbackHtml5AudioProps,
|
|
2065
|
-
debugAudioScheduling,
|
|
2066
1941
|
onError,
|
|
2067
1942
|
credentials,
|
|
2068
1943
|
controls
|
|
@@ -2075,7 +1950,7 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2075
1950
|
const [mediaPlayerReady, setMediaPlayerReady] = useState2(false);
|
|
2076
1951
|
const [shouldFallbackToNativeAudio, setShouldFallbackToNativeAudio] = useState2(false);
|
|
2077
1952
|
const [playing] = Timeline.usePlayingState();
|
|
2078
|
-
const timelineContext =
|
|
1953
|
+
const timelineContext = Internals8.useTimelineContext();
|
|
2079
1954
|
const globalPlaybackRate = timelineContext.playbackRate;
|
|
2080
1955
|
const sharedAudioContext = useContext3(SharedAudioContext);
|
|
2081
1956
|
const buffer = useBufferState();
|
|
@@ -2126,12 +2001,12 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2126
2001
|
trimBefore,
|
|
2127
2002
|
controls
|
|
2128
2003
|
});
|
|
2129
|
-
const bufferingContext = useContext3(
|
|
2004
|
+
const bufferingContext = useContext3(Internals8.BufferingContextReact);
|
|
2130
2005
|
if (!bufferingContext) {
|
|
2131
2006
|
throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
|
|
2132
2007
|
}
|
|
2133
2008
|
const effectiveMuted = muted || mediaMuted || userPreferredVolume <= 0;
|
|
2134
|
-
const isPlayerBuffering =
|
|
2009
|
+
const isPlayerBuffering = Internals8.useIsPlayerBuffering(bufferingContext);
|
|
2135
2010
|
const initialPlaying = useRef(playing && !isPlayerBuffering);
|
|
2136
2011
|
const initialIsPremounting = useRef(isPremounting);
|
|
2137
2012
|
const initialIsPostmounting = useRef(isPostmounting);
|
|
@@ -2156,13 +2031,11 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2156
2031
|
fps: videoConfig.fps,
|
|
2157
2032
|
sequenceOffset,
|
|
2158
2033
|
loop,
|
|
2159
|
-
debugAudioScheduling,
|
|
2160
2034
|
durationInFrames: videoConfig.durationInFrames,
|
|
2161
2035
|
isPremounting,
|
|
2162
2036
|
isPostmounting,
|
|
2163
2037
|
currentTime,
|
|
2164
2038
|
logLevel,
|
|
2165
|
-
sharedAudioContext,
|
|
2166
2039
|
label: "AudioForPreview"
|
|
2167
2040
|
});
|
|
2168
2041
|
useEffect2(() => {
|
|
@@ -2170,12 +2043,27 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2170
2043
|
return;
|
|
2171
2044
|
if (!sharedAudioContext.audioContext)
|
|
2172
2045
|
return;
|
|
2173
|
-
const {
|
|
2046
|
+
const {
|
|
2047
|
+
audioContext,
|
|
2048
|
+
gainNode,
|
|
2049
|
+
audioSyncAnchor,
|
|
2050
|
+
scheduleAudioNode,
|
|
2051
|
+
unscheduleAudioNode
|
|
2052
|
+
} = sharedAudioContext;
|
|
2053
|
+
if (!gainNode) {
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2174
2056
|
try {
|
|
2175
2057
|
const player = new MediaPlayer({
|
|
2176
2058
|
src: preloadedSrc,
|
|
2177
2059
|
logLevel,
|
|
2178
|
-
sharedAudioContext: {
|
|
2060
|
+
sharedAudioContext: {
|
|
2061
|
+
audioContext,
|
|
2062
|
+
gainNode,
|
|
2063
|
+
audioSyncAnchor,
|
|
2064
|
+
scheduleAudioNode,
|
|
2065
|
+
unscheduleAudioNode
|
|
2066
|
+
},
|
|
2179
2067
|
loop,
|
|
2180
2068
|
trimAfter: initialTrimAfterRef.current,
|
|
2181
2069
|
trimBefore: initialTrimBeforeRef.current,
|
|
@@ -2184,7 +2072,6 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2184
2072
|
playbackRate: initialPlaybackRate.current,
|
|
2185
2073
|
audioStreamIndex: audioStreamIndex ?? 0,
|
|
2186
2074
|
debugOverlay: false,
|
|
2187
|
-
debugAudioScheduling,
|
|
2188
2075
|
bufferState: buffer,
|
|
2189
2076
|
isPostmounting: initialIsPostmounting.current,
|
|
2190
2077
|
isPremounting: initialIsPremounting.current,
|
|
@@ -2211,7 +2098,7 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2211
2098
|
if (action === "fail") {
|
|
2212
2099
|
throw errorToUse;
|
|
2213
2100
|
} else {
|
|
2214
|
-
|
|
2101
|
+
Internals8.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
|
|
2215
2102
|
setShouldFallbackToNativeAudio(true);
|
|
2216
2103
|
}
|
|
2217
2104
|
};
|
|
@@ -2234,7 +2121,7 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2234
2121
|
if (result.type === "success") {
|
|
2235
2122
|
setMediaPlayerReady(true);
|
|
2236
2123
|
setMediaDurationInSeconds(result.durationInSeconds);
|
|
2237
|
-
|
|
2124
|
+
Internals8.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
|
|
2238
2125
|
}
|
|
2239
2126
|
}).catch((error) => {
|
|
2240
2127
|
const [action, errorToUse] = callOnErrorAndResolve({
|
|
@@ -2247,7 +2134,7 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2247
2134
|
if (action === "fail") {
|
|
2248
2135
|
throw errorToUse;
|
|
2249
2136
|
} else {
|
|
2250
|
-
|
|
2137
|
+
Internals8.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
|
|
2251
2138
|
setShouldFallbackToNativeAudio(true);
|
|
2252
2139
|
}
|
|
2253
2140
|
});
|
|
@@ -2262,12 +2149,12 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2262
2149
|
if (action === "fail") {
|
|
2263
2150
|
throw errorToUse;
|
|
2264
2151
|
}
|
|
2265
|
-
|
|
2152
|
+
Internals8.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
|
|
2266
2153
|
setShouldFallbackToNativeAudio(true);
|
|
2267
2154
|
}
|
|
2268
2155
|
return () => {
|
|
2269
2156
|
if (mediaPlayerRef.current) {
|
|
2270
|
-
|
|
2157
|
+
Internals8.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
|
|
2271
2158
|
mediaPlayerRef.current.dispose();
|
|
2272
2159
|
mediaPlayerRef.current = null;
|
|
2273
2160
|
}
|
|
@@ -2282,7 +2169,6 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
2282
2169
|
videoConfig.fps,
|
|
2283
2170
|
audioStreamIndex,
|
|
2284
2171
|
disallowFallbackToHtml5Audio,
|
|
2285
|
-
debugAudioScheduling,
|
|
2286
2172
|
buffer,
|
|
2287
2173
|
onError,
|
|
2288
2174
|
credentials
|
|
@@ -2326,13 +2212,12 @@ var AudioForPreview = ({
|
|
|
2326
2212
|
toneFrequency,
|
|
2327
2213
|
audioStreamIndex,
|
|
2328
2214
|
fallbackHtml5AudioProps,
|
|
2329
|
-
debugAudioScheduling,
|
|
2330
2215
|
onError,
|
|
2331
2216
|
credentials,
|
|
2332
2217
|
controls
|
|
2333
2218
|
}) => {
|
|
2334
2219
|
const preloadedSrc = usePreload(src);
|
|
2335
|
-
const defaultLogLevel =
|
|
2220
|
+
const defaultLogLevel = Internals8.useLogLevel();
|
|
2336
2221
|
const frame = useCurrentFrame2();
|
|
2337
2222
|
const videoConfig = useVideoConfig2();
|
|
2338
2223
|
const currentTime = frame / videoConfig.fps;
|
|
@@ -2376,7 +2261,6 @@ var AudioForPreview = ({
|
|
|
2376
2261
|
stack,
|
|
2377
2262
|
disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false,
|
|
2378
2263
|
toneFrequency,
|
|
2379
|
-
debugAudioScheduling: debugAudioScheduling ?? false,
|
|
2380
2264
|
onError,
|
|
2381
2265
|
credentials,
|
|
2382
2266
|
fallbackHtml5AudioProps,
|
|
@@ -2389,7 +2273,7 @@ import { useContext as useContext4, useLayoutEffect as useLayoutEffect2, useMemo
|
|
|
2389
2273
|
import {
|
|
2390
2274
|
cancelRender as cancelRender2,
|
|
2391
2275
|
Html5Audio,
|
|
2392
|
-
Internals as
|
|
2276
|
+
Internals as Internals16,
|
|
2393
2277
|
random,
|
|
2394
2278
|
useCurrentFrame as useCurrentFrame3,
|
|
2395
2279
|
useDelayRender,
|
|
@@ -2398,13 +2282,13 @@ import {
|
|
|
2398
2282
|
|
|
2399
2283
|
// src/caches.ts
|
|
2400
2284
|
import React2 from "react";
|
|
2401
|
-
import { cancelRender, Internals as
|
|
2285
|
+
import { cancelRender, Internals as Internals13 } from "remotion";
|
|
2402
2286
|
|
|
2403
2287
|
// src/audio-extraction/audio-manager.ts
|
|
2404
|
-
import { Internals as
|
|
2288
|
+
import { Internals as Internals10 } from "remotion";
|
|
2405
2289
|
|
|
2406
2290
|
// src/audio-extraction/audio-iterator.ts
|
|
2407
|
-
import { Internals as
|
|
2291
|
+
import { Internals as Internals9 } from "remotion";
|
|
2408
2292
|
|
|
2409
2293
|
// src/audio-extraction/audio-cache.ts
|
|
2410
2294
|
var makeAudioCache = () => {
|
|
@@ -2483,7 +2367,7 @@ var warnAboutMatroskaOnce = (src, logLevel) => {
|
|
|
2483
2367
|
return;
|
|
2484
2368
|
}
|
|
2485
2369
|
warned[src] = true;
|
|
2486
|
-
|
|
2370
|
+
Internals9.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
|
|
2487
2371
|
};
|
|
2488
2372
|
var makeAudioIterator2 = ({
|
|
2489
2373
|
audioSampleSink,
|
|
@@ -2551,7 +2435,7 @@ var makeAudioIterator2 = ({
|
|
|
2551
2435
|
if (openTimestamps.length > 0) {
|
|
2552
2436
|
const first = openTimestamps[0];
|
|
2553
2437
|
const last = openTimestamps[openTimestamps.length - 1];
|
|
2554
|
-
|
|
2438
|
+
Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
|
|
2555
2439
|
}
|
|
2556
2440
|
};
|
|
2557
2441
|
const getCacheStats = () => {
|
|
@@ -2648,7 +2532,7 @@ var makeAudioManager = () => {
|
|
|
2648
2532
|
if (seenKeys.has(key)) {
|
|
2649
2533
|
iterator.prepareForDeletion();
|
|
2650
2534
|
iterators.splice(iterators.indexOf(iterator), 1);
|
|
2651
|
-
|
|
2535
|
+
Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
|
|
2652
2536
|
}
|
|
2653
2537
|
seenKeys.add(key);
|
|
2654
2538
|
}
|
|
@@ -2669,7 +2553,7 @@ var makeAudioManager = () => {
|
|
|
2669
2553
|
attempts++;
|
|
2670
2554
|
}
|
|
2671
2555
|
if ((await getTotalCacheStats()).totalSize > maxCacheSize && attempts >= maxAttempts) {
|
|
2672
|
-
|
|
2556
|
+
Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
|
|
2673
2557
|
}
|
|
2674
2558
|
for (const iterator of iterators) {
|
|
2675
2559
|
if (iterator.src === src && await iterator.waitForCompletion() && iterator.canSatisfyRequestedTime(timeInSeconds)) {
|
|
@@ -2738,7 +2622,7 @@ var makeAudioManager = () => {
|
|
|
2738
2622
|
};
|
|
2739
2623
|
|
|
2740
2624
|
// src/video-extraction/keyframe-manager.ts
|
|
2741
|
-
import { Internals as
|
|
2625
|
+
import { Internals as Internals12 } from "remotion";
|
|
2742
2626
|
|
|
2743
2627
|
// src/render-timestamp-range.ts
|
|
2744
2628
|
var renderTimestampRange = (timestamps) => {
|
|
@@ -2752,7 +2636,7 @@ var renderTimestampRange = (timestamps) => {
|
|
|
2752
2636
|
};
|
|
2753
2637
|
|
|
2754
2638
|
// src/video-extraction/keyframe-bank.ts
|
|
2755
|
-
import { Internals as
|
|
2639
|
+
import { Internals as Internals11 } from "remotion";
|
|
2756
2640
|
|
|
2757
2641
|
// src/video-extraction/get-allocation-size.ts
|
|
2758
2642
|
var getAllocationSize = (sample) => {
|
|
@@ -2815,7 +2699,7 @@ var makeKeyframeBank = async ({
|
|
|
2815
2699
|
}
|
|
2816
2700
|
}
|
|
2817
2701
|
if (deletedTimestamps.length > 0) {
|
|
2818
|
-
|
|
2702
|
+
Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
|
|
2819
2703
|
}
|
|
2820
2704
|
};
|
|
2821
2705
|
const hasDecodedEnoughForTimestamp = (timestamp) => {
|
|
@@ -2838,7 +2722,7 @@ var makeKeyframeBank = async ({
|
|
|
2838
2722
|
frameTimestamps.push(frame.timestamp);
|
|
2839
2723
|
allocationSize += getAllocationSize(frame);
|
|
2840
2724
|
lastUsed = Date.now();
|
|
2841
|
-
|
|
2725
|
+
Internals11.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
|
|
2842
2726
|
};
|
|
2843
2727
|
const ensureEnoughFramesForTimestamp = async (timestampInSeconds, logLevel, fps) => {
|
|
2844
2728
|
while (!hasDecodedEnoughForTimestamp(timestampInSeconds)) {
|
|
@@ -2893,7 +2777,7 @@ var makeKeyframeBank = async ({
|
|
|
2893
2777
|
throw new Error("No first frame found");
|
|
2894
2778
|
}
|
|
2895
2779
|
const startTimestampInSeconds = firstFrame.value.timestamp;
|
|
2896
|
-
|
|
2780
|
+
Internals11.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
|
|
2897
2781
|
addFrame(firstFrame.value, parentLogLevel);
|
|
2898
2782
|
const getRangeOfTimestamps = () => {
|
|
2899
2783
|
if (frameTimestamps.length === 0) {
|
|
@@ -2911,7 +2795,7 @@ var makeKeyframeBank = async ({
|
|
|
2911
2795
|
const prepareForDeletion = (logLevel, reason) => {
|
|
2912
2796
|
const range = getRangeOfTimestamps();
|
|
2913
2797
|
if (range) {
|
|
2914
|
-
|
|
2798
|
+
Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
|
|
2915
2799
|
}
|
|
2916
2800
|
let framesDeleted = 0;
|
|
2917
2801
|
for (const frameTimestamp of frameTimestamps.slice()) {
|
|
@@ -2984,10 +2868,10 @@ var makeKeyframeManager = () => {
|
|
|
2984
2868
|
if (size === 0) {
|
|
2985
2869
|
continue;
|
|
2986
2870
|
}
|
|
2987
|
-
|
|
2871
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
|
|
2988
2872
|
}
|
|
2989
2873
|
}
|
|
2990
|
-
|
|
2874
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
|
|
2991
2875
|
};
|
|
2992
2876
|
const getCacheStats = () => {
|
|
2993
2877
|
let count = 0;
|
|
@@ -3041,7 +2925,7 @@ var makeKeyframeManager = () => {
|
|
|
3041
2925
|
const { framesDeleted } = mostInThePastBank.prepareForDeletion(logLevel, "deleted oldest keyframe bank to stay under max cache size");
|
|
3042
2926
|
sources[mostInThePastSrc].splice(mostInThePastIndex, 1);
|
|
3043
2927
|
if (range) {
|
|
3044
|
-
|
|
2928
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
|
|
3045
2929
|
}
|
|
3046
2930
|
}
|
|
3047
2931
|
return { finish: false };
|
|
@@ -3055,12 +2939,12 @@ var makeKeyframeManager = () => {
|
|
|
3055
2939
|
if (finish) {
|
|
3056
2940
|
break;
|
|
3057
2941
|
}
|
|
3058
|
-
|
|
2942
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
|
|
3059
2943
|
cacheStats = getTotalCacheStats();
|
|
3060
2944
|
attempts++;
|
|
3061
2945
|
}
|
|
3062
2946
|
if (cacheStats.totalSize > maxCacheSize && attempts >= maxAttempts) {
|
|
3063
|
-
|
|
2947
|
+
Internals12.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
|
|
3064
2948
|
}
|
|
3065
2949
|
};
|
|
3066
2950
|
const clearKeyframeBanksBeforeTime = ({
|
|
@@ -3081,7 +2965,7 @@ var makeKeyframeManager = () => {
|
|
|
3081
2965
|
}
|
|
3082
2966
|
if (range.lastTimestamp < threshold) {
|
|
3083
2967
|
bank.prepareForDeletion(logLevel, "cleared before threshold " + threshold);
|
|
3084
|
-
|
|
2968
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
|
|
3085
2969
|
const bankIndex = banks.indexOf(bank);
|
|
3086
2970
|
delete sources[src][bankIndex];
|
|
3087
2971
|
} else {
|
|
@@ -3103,7 +2987,7 @@ var makeKeyframeManager = () => {
|
|
|
3103
2987
|
const existingBanks = sources[src] ?? [];
|
|
3104
2988
|
const existingBank = existingBanks?.find((bank) => bank.canSatisfyTimestamp(timestamp));
|
|
3105
2989
|
if (!existingBank) {
|
|
3106
|
-
|
|
2990
|
+
Internals12.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
|
|
3107
2991
|
const newKeyframeBank = await makeKeyframeBank({
|
|
3108
2992
|
videoSampleSink,
|
|
3109
2993
|
logLevel,
|
|
@@ -3114,10 +2998,10 @@ var makeKeyframeManager = () => {
|
|
|
3114
2998
|
return newKeyframeBank;
|
|
3115
2999
|
}
|
|
3116
3000
|
if (existingBank.canSatisfyTimestamp(timestamp)) {
|
|
3117
|
-
|
|
3001
|
+
Internals12.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
|
|
3118
3002
|
return existingBank;
|
|
3119
3003
|
}
|
|
3120
|
-
|
|
3004
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
|
|
3121
3005
|
existingBank.prepareForDeletion(logLevel, "already existed but evicted");
|
|
3122
3006
|
sources[src] = sources[src].filter((bank) => bank !== existingBank);
|
|
3123
3007
|
const replacementKeybank = await makeKeyframeBank({
|
|
@@ -3208,20 +3092,20 @@ var getUncachedMaxCacheSize = (logLevel) => {
|
|
|
3208
3092
|
if (window.remotion_mediaCacheSizeInBytes > 20000 * 1024 * 1024) {
|
|
3209
3093
|
cancelRender(new Error(`The maximum value for the "mediaCacheSizeInBytes" prop is 20GB (${20000 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
|
|
3210
3094
|
}
|
|
3211
|
-
|
|
3095
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
|
|
3212
3096
|
return window.remotion_mediaCacheSizeInBytes;
|
|
3213
3097
|
}
|
|
3214
3098
|
if (typeof window !== "undefined" && window.remotion_initialMemoryAvailable !== undefined && window.remotion_initialMemoryAvailable !== null) {
|
|
3215
3099
|
const value = window.remotion_initialMemoryAvailable / 2;
|
|
3216
3100
|
if (value < 500 * 1024 * 1024) {
|
|
3217
|
-
|
|
3101
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
|
|
3218
3102
|
return 500 * 1024 * 1024;
|
|
3219
3103
|
}
|
|
3220
3104
|
if (value > 20000 * 1024 * 1024) {
|
|
3221
|
-
|
|
3105
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
|
|
3222
3106
|
return 20000 * 1024 * 1024;
|
|
3223
3107
|
}
|
|
3224
|
-
|
|
3108
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
|
|
3225
3109
|
return value;
|
|
3226
3110
|
}
|
|
3227
3111
|
return 1000 * 1000 * 1000;
|
|
@@ -3235,7 +3119,7 @@ var getMaxVideoCacheSize = (logLevel) => {
|
|
|
3235
3119
|
return cachedMaxCacheSize;
|
|
3236
3120
|
};
|
|
3237
3121
|
var useMaxMediaCacheSize = (logLevel) => {
|
|
3238
|
-
const context = React2.useContext(
|
|
3122
|
+
const context = React2.useContext(Internals13.MaxMediaCacheSizeContext);
|
|
3239
3123
|
if (context === null) {
|
|
3240
3124
|
return getMaxVideoCacheSize(logLevel);
|
|
3241
3125
|
}
|
|
@@ -3489,7 +3373,7 @@ var combineAudioDataAndClosePrevious = (audioDataArray) => {
|
|
|
3489
3373
|
};
|
|
3490
3374
|
|
|
3491
3375
|
// src/get-sink.ts
|
|
3492
|
-
import { Internals as
|
|
3376
|
+
import { Internals as Internals14 } from "remotion";
|
|
3493
3377
|
|
|
3494
3378
|
// src/video-extraction/get-frames-since-keyframe.ts
|
|
3495
3379
|
import {
|
|
@@ -3644,7 +3528,7 @@ var getSink = (src, logLevel, credentials) => {
|
|
|
3644
3528
|
const cacheKey = credentials ? `${src}::${credentials}` : src;
|
|
3645
3529
|
let promise = sinkPromises[cacheKey];
|
|
3646
3530
|
if (!promise) {
|
|
3647
|
-
|
|
3531
|
+
Internals14.Log.verbose({
|
|
3648
3532
|
logLevel,
|
|
3649
3533
|
tag: "@remotion/media"
|
|
3650
3534
|
}, `Sink for ${src} was not found, creating new sink`);
|
|
@@ -3785,7 +3669,7 @@ var extractAudio = (params) => {
|
|
|
3785
3669
|
};
|
|
3786
3670
|
|
|
3787
3671
|
// src/video-extraction/extract-frame.ts
|
|
3788
|
-
import { Internals as
|
|
3672
|
+
import { Internals as Internals15 } from "remotion";
|
|
3789
3673
|
var extractFrameInternal = async ({
|
|
3790
3674
|
src,
|
|
3791
3675
|
timeInSeconds: unloopedTimeInSeconds,
|
|
@@ -3867,7 +3751,7 @@ var extractFrameInternal = async ({
|
|
|
3867
3751
|
durationInSeconds: await sink.getDuration()
|
|
3868
3752
|
};
|
|
3869
3753
|
} catch (err) {
|
|
3870
|
-
|
|
3754
|
+
Internals15.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
|
|
3871
3755
|
return { type: "cannot-decode", durationInSeconds: mediaDurationInSeconds };
|
|
3872
3756
|
}
|
|
3873
3757
|
};
|
|
@@ -4271,13 +4155,13 @@ var AudioForRendering = ({
|
|
|
4271
4155
|
onError,
|
|
4272
4156
|
credentials
|
|
4273
4157
|
}) => {
|
|
4274
|
-
const defaultLogLevel =
|
|
4158
|
+
const defaultLogLevel = Internals16.useLogLevel();
|
|
4275
4159
|
const logLevel = overriddenLogLevel ?? defaultLogLevel;
|
|
4276
4160
|
const frame = useCurrentFrame3();
|
|
4277
|
-
const absoluteFrame =
|
|
4278
|
-
const videoConfig =
|
|
4279
|
-
const { registerRenderAsset, unregisterRenderAsset } = useContext4(
|
|
4280
|
-
const startsAt =
|
|
4161
|
+
const absoluteFrame = Internals16.useTimelinePosition();
|
|
4162
|
+
const videoConfig = Internals16.useUnsafeVideoConfig();
|
|
4163
|
+
const { registerRenderAsset, unregisterRenderAsset } = useContext4(Internals16.RenderAssetManager);
|
|
4164
|
+
const startsAt = Internals16.useMediaStartsAt();
|
|
4281
4165
|
const environment = useRemotionEnvironment();
|
|
4282
4166
|
if (!videoConfig) {
|
|
4283
4167
|
throw new Error("No video config found");
|
|
@@ -4288,7 +4172,7 @@ var AudioForRendering = ({
|
|
|
4288
4172
|
const { fps } = videoConfig;
|
|
4289
4173
|
const { delayRender, continueRender } = useDelayRender();
|
|
4290
4174
|
const [replaceWithHtml5Audio, setReplaceWithHtml5Audio] = useState3(false);
|
|
4291
|
-
const sequenceContext = useContext4(
|
|
4175
|
+
const sequenceContext = useContext4(Internals16.SequenceContext);
|
|
4292
4176
|
const id = useMemo3(() => `media-audio-${random(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
|
|
4293
4177
|
src,
|
|
4294
4178
|
sequenceContext?.cumulatedFrom,
|
|
@@ -4296,7 +4180,7 @@ var AudioForRendering = ({
|
|
|
4296
4180
|
sequenceContext?.durationInFrames
|
|
4297
4181
|
]);
|
|
4298
4182
|
const maxCacheSize = useMaxMediaCacheSize(logLevel);
|
|
4299
|
-
const audioEnabled =
|
|
4183
|
+
const audioEnabled = Internals16.useAudioEnabled();
|
|
4300
4184
|
useLayoutEffect2(() => {
|
|
4301
4185
|
const timestamp = frame / fps;
|
|
4302
4186
|
const durationInSeconds = 1 / fps;
|
|
@@ -4347,7 +4231,7 @@ var AudioForRendering = ({
|
|
|
4347
4231
|
if (action === "fail") {
|
|
4348
4232
|
cancelRender2(errorToUse);
|
|
4349
4233
|
}
|
|
4350
|
-
|
|
4234
|
+
Internals16.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
|
|
4351
4235
|
setReplaceWithHtml5Audio(true);
|
|
4352
4236
|
};
|
|
4353
4237
|
if (result.type === "unknown-container-format") {
|
|
@@ -4374,12 +4258,12 @@ var AudioForRendering = ({
|
|
|
4374
4258
|
frame,
|
|
4375
4259
|
startsAt
|
|
4376
4260
|
});
|
|
4377
|
-
const volume =
|
|
4261
|
+
const volume = Internals16.evaluateVolume({
|
|
4378
4262
|
volume: volumeProp,
|
|
4379
4263
|
frame: volumePropsFrame,
|
|
4380
4264
|
mediaVolume: 1
|
|
4381
4265
|
});
|
|
4382
|
-
|
|
4266
|
+
Internals16.warnAboutTooHighVolume(volume);
|
|
4383
4267
|
if (audio && volume > 0) {
|
|
4384
4268
|
applyVolume(audio.data, volume);
|
|
4385
4269
|
registerRenderAsset({
|
|
@@ -4456,7 +4340,7 @@ var AudioForRendering = ({
|
|
|
4456
4340
|
|
|
4457
4341
|
// src/audio/audio.tsx
|
|
4458
4342
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
4459
|
-
var { validateMediaProps } =
|
|
4343
|
+
var { validateMediaProps } = Internals17;
|
|
4460
4344
|
var audioSchema = {
|
|
4461
4345
|
volume: {
|
|
4462
4346
|
type: "number",
|
|
@@ -4505,11 +4389,11 @@ var AudioInner = (props) => {
|
|
|
4505
4389
|
})
|
|
4506
4390
|
});
|
|
4507
4391
|
};
|
|
4508
|
-
var Audio =
|
|
4509
|
-
|
|
4392
|
+
var Audio = Internals17.wrapInSchema(AudioInner, audioSchema);
|
|
4393
|
+
Internals17.addSequenceStackTraces(Audio);
|
|
4510
4394
|
|
|
4511
4395
|
// src/video/video.tsx
|
|
4512
|
-
import { Internals as
|
|
4396
|
+
import { Internals as Internals21, Sequence as Sequence2, useRemotionEnvironment as useRemotionEnvironment4 } from "remotion";
|
|
4513
4397
|
|
|
4514
4398
|
// src/video/video-for-preview.tsx
|
|
4515
4399
|
import {
|
|
@@ -4522,7 +4406,7 @@ import {
|
|
|
4522
4406
|
} from "react";
|
|
4523
4407
|
import {
|
|
4524
4408
|
Html5Video,
|
|
4525
|
-
Internals as
|
|
4409
|
+
Internals as Internals19,
|
|
4526
4410
|
useBufferState as useBufferState2,
|
|
4527
4411
|
useCurrentFrame as useCurrentFrame4,
|
|
4528
4412
|
useVideoConfig as useVideoConfig3
|
|
@@ -4552,7 +4436,7 @@ var getCachedVideoFrame = (src) => {
|
|
|
4552
4436
|
};
|
|
4553
4437
|
|
|
4554
4438
|
// src/video/warn-object-fit-css.ts
|
|
4555
|
-
import { Internals as
|
|
4439
|
+
import { Internals as Internals18 } from "remotion";
|
|
4556
4440
|
var OBJECT_FIT_CLASS_PATTERN = /\bobject-(contain|cover|fill|none|scale-down)\b/;
|
|
4557
4441
|
var warnedStyle = false;
|
|
4558
4442
|
var warnedClassName = false;
|
|
@@ -4563,11 +4447,11 @@ var warnAboutObjectFitInStyleOrClassName = ({
|
|
|
4563
4447
|
}) => {
|
|
4564
4448
|
if (!warnedStyle && style?.objectFit) {
|
|
4565
4449
|
warnedStyle = true;
|
|
4566
|
-
|
|
4450
|
+
Internals18.Log.warn({ logLevel, tag: "@remotion/media" }, "Use the `objectFit` prop instead of the `style` prop.");
|
|
4567
4451
|
}
|
|
4568
4452
|
if (!warnedClassName && className && OBJECT_FIT_CLASS_PATTERN.test(className)) {
|
|
4569
4453
|
warnedClassName = true;
|
|
4570
|
-
|
|
4454
|
+
Internals18.Log.warn({ logLevel, tag: "@remotion/media" }, "Use the `objectFit` prop instead of `object-*` CSS class names.");
|
|
4571
4455
|
}
|
|
4572
4456
|
};
|
|
4573
4457
|
|
|
@@ -4585,7 +4469,7 @@ var {
|
|
|
4585
4469
|
usePreload: usePreload2,
|
|
4586
4470
|
SequenceContext: SequenceContext2,
|
|
4587
4471
|
SequenceVisibilityToggleContext
|
|
4588
|
-
} =
|
|
4472
|
+
} = Internals19;
|
|
4589
4473
|
var VideoForPreviewAssertedShowing = ({
|
|
4590
4474
|
src: unpreloadedSrc,
|
|
4591
4475
|
style,
|
|
@@ -4606,7 +4490,6 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4606
4490
|
fallbackOffthreadVideoProps,
|
|
4607
4491
|
audioStreamIndex,
|
|
4608
4492
|
debugOverlay,
|
|
4609
|
-
debugAudioScheduling,
|
|
4610
4493
|
headless,
|
|
4611
4494
|
onError,
|
|
4612
4495
|
credentials,
|
|
@@ -4625,7 +4508,7 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4625
4508
|
const [mediaPlayerReady, setMediaPlayerReady] = useState4(false);
|
|
4626
4509
|
const [shouldFallbackToNativeVideo, setShouldFallbackToNativeVideo] = useState4(false);
|
|
4627
4510
|
const [playing] = Timeline2.usePlayingState();
|
|
4628
|
-
const timelineContext =
|
|
4511
|
+
const timelineContext = Internals19.useTimelineContext();
|
|
4629
4512
|
const globalPlaybackRate = timelineContext.playbackRate;
|
|
4630
4513
|
const sharedAudioContext = useContext5(SharedAudioContext2);
|
|
4631
4514
|
const buffer = useBufferState2();
|
|
@@ -4675,19 +4558,19 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4675
4558
|
const currentTimeRef = useRef2(currentTime);
|
|
4676
4559
|
currentTimeRef.current = currentTime;
|
|
4677
4560
|
const preloadedSrc = usePreload2(src);
|
|
4678
|
-
const buffering = useContext5(
|
|
4561
|
+
const buffering = useContext5(Internals19.BufferingContextReact);
|
|
4679
4562
|
if (!buffering) {
|
|
4680
4563
|
throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
|
|
4681
4564
|
}
|
|
4682
4565
|
const effectiveMuted = isSequenceHidden || muted || mediaMuted || userPreferredVolume <= 0;
|
|
4683
|
-
const isPlayerBuffering =
|
|
4566
|
+
const isPlayerBuffering = Internals19.useIsPlayerBuffering(buffering);
|
|
4684
4567
|
const initialPlaying = useRef2(playing && !isPlayerBuffering);
|
|
4685
4568
|
const initialIsPremounting = useRef2(isPremounting);
|
|
4686
4569
|
const initialIsPostmounting = useRef2(isPostmounting);
|
|
4687
4570
|
const initialGlobalPlaybackRate = useRef2(globalPlaybackRate);
|
|
4688
4571
|
const initialPlaybackRate = useRef2(playbackRate);
|
|
4689
4572
|
const initialMuted = useRef2(effectiveMuted);
|
|
4690
|
-
const
|
|
4573
|
+
const initialSequenceDuration = useRef2(videoConfig.durationInFrames);
|
|
4691
4574
|
const initialSequenceOffset = useRef2(sequenceOffset);
|
|
4692
4575
|
const hasDrawnRealFrameRef = useRef2(false);
|
|
4693
4576
|
const isPremountingRef = useRef2(isPremounting);
|
|
@@ -4732,13 +4615,28 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4732
4615
|
return;
|
|
4733
4616
|
if (!sharedAudioContext.audioContext)
|
|
4734
4617
|
return;
|
|
4735
|
-
const {
|
|
4618
|
+
const {
|
|
4619
|
+
audioContext,
|
|
4620
|
+
gainNode,
|
|
4621
|
+
audioSyncAnchor,
|
|
4622
|
+
scheduleAudioNode,
|
|
4623
|
+
unscheduleAudioNode
|
|
4624
|
+
} = sharedAudioContext;
|
|
4625
|
+
if (!gainNode) {
|
|
4626
|
+
return;
|
|
4627
|
+
}
|
|
4736
4628
|
try {
|
|
4737
4629
|
const player = new MediaPlayer({
|
|
4738
4630
|
canvas: canvasRef.current,
|
|
4739
4631
|
src: preloadedSrc,
|
|
4740
4632
|
logLevel,
|
|
4741
|
-
sharedAudioContext: {
|
|
4633
|
+
sharedAudioContext: {
|
|
4634
|
+
audioContext,
|
|
4635
|
+
gainNode,
|
|
4636
|
+
audioSyncAnchor,
|
|
4637
|
+
scheduleAudioNode,
|
|
4638
|
+
unscheduleAudioNode
|
|
4639
|
+
},
|
|
4742
4640
|
loop,
|
|
4743
4641
|
trimAfter: initialTrimAfterRef.current,
|
|
4744
4642
|
trimBefore: initialTrimBeforeRef.current,
|
|
@@ -4746,12 +4644,11 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4746
4644
|
playbackRate: initialPlaybackRate.current,
|
|
4747
4645
|
audioStreamIndex,
|
|
4748
4646
|
debugOverlay,
|
|
4749
|
-
debugAudioScheduling,
|
|
4750
4647
|
bufferState: buffer,
|
|
4751
4648
|
isPremounting: initialIsPremounting.current,
|
|
4752
4649
|
isPostmounting: initialIsPostmounting.current,
|
|
4753
4650
|
globalPlaybackRate: initialGlobalPlaybackRate.current,
|
|
4754
|
-
durationInFrames:
|
|
4651
|
+
durationInFrames: initialSequenceDuration.current,
|
|
4755
4652
|
onVideoFrameCallback: initialOnVideoFrameRef.current ?? null,
|
|
4756
4653
|
playing: initialPlaying.current,
|
|
4757
4654
|
sequenceOffset: initialSequenceOffset.current,
|
|
@@ -4773,7 +4670,7 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4773
4670
|
if (action === "fail") {
|
|
4774
4671
|
throw errorToUse;
|
|
4775
4672
|
}
|
|
4776
|
-
|
|
4673
|
+
Internals19.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
|
|
4777
4674
|
setShouldFallbackToNativeVideo(true);
|
|
4778
4675
|
};
|
|
4779
4676
|
if (result.type === "unknown-container-format") {
|
|
@@ -4808,7 +4705,7 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4808
4705
|
if (action === "fail") {
|
|
4809
4706
|
throw errorToUse;
|
|
4810
4707
|
}
|
|
4811
|
-
|
|
4708
|
+
Internals19.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
|
|
4812
4709
|
setShouldFallbackToNativeVideo(true);
|
|
4813
4710
|
});
|
|
4814
4711
|
} catch (error) {
|
|
@@ -4822,12 +4719,12 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4822
4719
|
if (action === "fail") {
|
|
4823
4720
|
throw errorToUse;
|
|
4824
4721
|
}
|
|
4825
|
-
|
|
4722
|
+
Internals19.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
|
|
4826
4723
|
setShouldFallbackToNativeVideo(true);
|
|
4827
4724
|
}
|
|
4828
4725
|
return () => {
|
|
4829
4726
|
if (mediaPlayerRef.current) {
|
|
4830
|
-
|
|
4727
|
+
Internals19.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
|
|
4831
4728
|
mediaPlayerRef.current.dispose();
|
|
4832
4729
|
mediaPlayerRef.current = null;
|
|
4833
4730
|
}
|
|
@@ -4839,7 +4736,6 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4839
4736
|
audioStreamIndex,
|
|
4840
4737
|
buffer,
|
|
4841
4738
|
debugOverlay,
|
|
4842
|
-
debugAudioScheduling,
|
|
4843
4739
|
disallowFallbackToOffthreadVideo,
|
|
4844
4740
|
logLevel,
|
|
4845
4741
|
loop,
|
|
@@ -4851,7 +4747,7 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4851
4747
|
]);
|
|
4852
4748
|
warnAboutObjectFitInStyleOrClassName({ style, className, logLevel });
|
|
4853
4749
|
const classNameValue = useMemo4(() => {
|
|
4854
|
-
return [
|
|
4750
|
+
return [Internals19.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals19.truthy).join(" ");
|
|
4855
4751
|
}, [className]);
|
|
4856
4752
|
useCommonEffects({
|
|
4857
4753
|
mediaPlayerRef,
|
|
@@ -4869,13 +4765,11 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
4869
4765
|
fps: videoConfig.fps,
|
|
4870
4766
|
sequenceOffset,
|
|
4871
4767
|
loop,
|
|
4872
|
-
debugAudioScheduling,
|
|
4873
4768
|
durationInFrames: videoConfig.durationInFrames,
|
|
4874
4769
|
isPremounting,
|
|
4875
4770
|
isPostmounting,
|
|
4876
4771
|
currentTime,
|
|
4877
4772
|
logLevel,
|
|
4878
|
-
sharedAudioContext,
|
|
4879
4773
|
label: "VideoForPreview"
|
|
4880
4774
|
});
|
|
4881
4775
|
useLayoutEffect3(() => {
|
|
@@ -4969,7 +4863,7 @@ import {
|
|
|
4969
4863
|
useState as useState5
|
|
4970
4864
|
} from "react";
|
|
4971
4865
|
import {
|
|
4972
|
-
Internals as
|
|
4866
|
+
Internals as Internals20,
|
|
4973
4867
|
Loop,
|
|
4974
4868
|
random as random2,
|
|
4975
4869
|
useCurrentFrame as useCurrentFrame5,
|
|
@@ -5008,11 +4902,11 @@ var VideoForRendering = ({
|
|
|
5008
4902
|
throw new TypeError("No `src` was passed to <Video>.");
|
|
5009
4903
|
}
|
|
5010
4904
|
const frame = useCurrentFrame5();
|
|
5011
|
-
const absoluteFrame =
|
|
4905
|
+
const absoluteFrame = Internals20.useTimelinePosition();
|
|
5012
4906
|
const { fps } = useVideoConfig4();
|
|
5013
|
-
const { registerRenderAsset, unregisterRenderAsset } = useContext6(
|
|
5014
|
-
const startsAt =
|
|
5015
|
-
const sequenceContext = useContext6(
|
|
4907
|
+
const { registerRenderAsset, unregisterRenderAsset } = useContext6(Internals20.RenderAssetManager);
|
|
4908
|
+
const startsAt = Internals20.useMediaStartsAt();
|
|
4909
|
+
const sequenceContext = useContext6(Internals20.SequenceContext);
|
|
5016
4910
|
const id = useMemo5(() => `media-video-${random2(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
|
|
5017
4911
|
src,
|
|
5018
4912
|
sequenceContext?.cumulatedFrom,
|
|
@@ -5023,8 +4917,8 @@ var VideoForRendering = ({
|
|
|
5023
4917
|
const { delayRender, continueRender, cancelRender: cancelRender3 } = useDelayRender2();
|
|
5024
4918
|
const canvasRef = useRef3(null);
|
|
5025
4919
|
const [replaceWithOffthreadVideo, setReplaceWithOffthreadVideo] = useState5(false);
|
|
5026
|
-
const audioEnabled =
|
|
5027
|
-
const videoEnabled =
|
|
4920
|
+
const audioEnabled = Internals20.useAudioEnabled();
|
|
4921
|
+
const videoEnabled = Internals20.useVideoEnabled();
|
|
5028
4922
|
const maxCacheSize = useMaxMediaCacheSize(logLevel);
|
|
5029
4923
|
const [error, setError] = useState5(null);
|
|
5030
4924
|
if (error) {
|
|
@@ -5089,7 +4983,7 @@ var VideoForRendering = ({
|
|
|
5089
4983
|
return;
|
|
5090
4984
|
}
|
|
5091
4985
|
if (window.remotion_isMainTab) {
|
|
5092
|
-
|
|
4986
|
+
Internals20.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
|
|
5093
4987
|
}
|
|
5094
4988
|
setReplaceWithOffthreadVideo({
|
|
5095
4989
|
durationInSeconds: mediaDurationInSeconds
|
|
@@ -5144,12 +5038,12 @@ var VideoForRendering = ({
|
|
|
5144
5038
|
frame,
|
|
5145
5039
|
startsAt
|
|
5146
5040
|
});
|
|
5147
|
-
const volume =
|
|
5041
|
+
const volume = Internals20.evaluateVolume({
|
|
5148
5042
|
volume: volumeProp,
|
|
5149
5043
|
frame: volumePropsFrame,
|
|
5150
5044
|
mediaVolume: 1
|
|
5151
5045
|
});
|
|
5152
|
-
|
|
5046
|
+
Internals20.warnAboutTooHighVolume(volume);
|
|
5153
5047
|
if (audio && volume > 0) {
|
|
5154
5048
|
applyVolume(audio.data, volume);
|
|
5155
5049
|
registerRenderAsset({
|
|
@@ -5207,7 +5101,7 @@ var VideoForRendering = ({
|
|
|
5207
5101
|
]);
|
|
5208
5102
|
warnAboutObjectFitInStyleOrClassName({ style, className, logLevel });
|
|
5209
5103
|
const classNameValue = useMemo5(() => {
|
|
5210
|
-
return [
|
|
5104
|
+
return [Internals20.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals20.truthy).join(" ");
|
|
5211
5105
|
}, [className]);
|
|
5212
5106
|
const styleWithObjectFit = useMemo5(() => {
|
|
5213
5107
|
return {
|
|
@@ -5216,7 +5110,7 @@ var VideoForRendering = ({
|
|
|
5216
5110
|
};
|
|
5217
5111
|
}, [objectFitProp, style]);
|
|
5218
5112
|
if (replaceWithOffthreadVideo) {
|
|
5219
|
-
const fallback = /* @__PURE__ */ jsx5(
|
|
5113
|
+
const fallback = /* @__PURE__ */ jsx5(Internals20.InnerOffthreadVideo, {
|
|
5220
5114
|
src,
|
|
5221
5115
|
playbackRate: playbackRate ?? 1,
|
|
5222
5116
|
muted: muted ?? false,
|
|
@@ -5256,7 +5150,7 @@ var VideoForRendering = ({
|
|
|
5256
5150
|
}
|
|
5257
5151
|
return /* @__PURE__ */ jsx5(Loop, {
|
|
5258
5152
|
layout: "none",
|
|
5259
|
-
durationInFrames:
|
|
5153
|
+
durationInFrames: Internals20.calculateMediaDuration({
|
|
5260
5154
|
trimAfter: trimAfterValue,
|
|
5261
5155
|
mediaDurationInFrames: replaceWithOffthreadVideo.durationInSeconds * fps,
|
|
5262
5156
|
playbackRate,
|
|
@@ -5279,7 +5173,7 @@ var VideoForRendering = ({
|
|
|
5279
5173
|
|
|
5280
5174
|
// src/video/video.tsx
|
|
5281
5175
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
5282
|
-
var { validateMediaTrimProps, resolveTrimProps, validateMediaProps: validateMediaProps2 } =
|
|
5176
|
+
var { validateMediaTrimProps, resolveTrimProps, validateMediaProps: validateMediaProps2 } = Internals21;
|
|
5283
5177
|
var videoSchema = {
|
|
5284
5178
|
volume: {
|
|
5285
5179
|
type: "number",
|
|
@@ -5349,7 +5243,6 @@ var InnerVideo = ({
|
|
|
5349
5243
|
toneFrequency,
|
|
5350
5244
|
showInTimeline,
|
|
5351
5245
|
debugOverlay,
|
|
5352
|
-
debugAudioScheduling,
|
|
5353
5246
|
headless,
|
|
5354
5247
|
onError,
|
|
5355
5248
|
credentials,
|
|
@@ -5422,7 +5315,6 @@ var InnerVideo = ({
|
|
|
5422
5315
|
disallowFallbackToOffthreadVideo,
|
|
5423
5316
|
fallbackOffthreadVideoProps,
|
|
5424
5317
|
debugOverlay: debugOverlay ?? false,
|
|
5425
|
-
debugAudioScheduling: debugAudioScheduling ?? false,
|
|
5426
5318
|
headless: headless ?? false,
|
|
5427
5319
|
onError,
|
|
5428
5320
|
credentials,
|
|
@@ -5454,7 +5346,6 @@ var VideoInner = ({
|
|
|
5454
5346
|
stack,
|
|
5455
5347
|
toneFrequency,
|
|
5456
5348
|
debugOverlay,
|
|
5457
|
-
debugAudioScheduling,
|
|
5458
5349
|
headless,
|
|
5459
5350
|
onError,
|
|
5460
5351
|
credentials,
|
|
@@ -5464,7 +5355,7 @@ var VideoInner = ({
|
|
|
5464
5355
|
from,
|
|
5465
5356
|
durationInFrames
|
|
5466
5357
|
}) => {
|
|
5467
|
-
const fallbackLogLevel =
|
|
5358
|
+
const fallbackLogLevel = Internals21.useLogLevel();
|
|
5468
5359
|
return /* @__PURE__ */ jsx6(Sequence2, {
|
|
5469
5360
|
layout: "none",
|
|
5470
5361
|
from: from ?? 0,
|
|
@@ -5493,7 +5384,6 @@ var VideoInner = ({
|
|
|
5493
5384
|
toneFrequency: toneFrequency ?? 1,
|
|
5494
5385
|
stack,
|
|
5495
5386
|
debugOverlay: debugOverlay ?? false,
|
|
5496
|
-
debugAudioScheduling: debugAudioScheduling ?? false,
|
|
5497
5387
|
headless: headless ?? false,
|
|
5498
5388
|
onError,
|
|
5499
5389
|
credentials,
|
|
@@ -5503,8 +5393,8 @@ var VideoInner = ({
|
|
|
5503
5393
|
})
|
|
5504
5394
|
});
|
|
5505
5395
|
};
|
|
5506
|
-
var Video =
|
|
5507
|
-
|
|
5396
|
+
var Video = Internals21.wrapInSchema(VideoInner, videoSchema);
|
|
5397
|
+
Internals21.addSequenceStackTraces(Video);
|
|
5508
5398
|
|
|
5509
5399
|
// src/index.ts
|
|
5510
5400
|
var experimental_Audio = Audio;
|