@remotion/media 4.0.361 → 4.0.362
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/esm/index.mjs
CHANGED
|
@@ -226,11 +226,18 @@ function isNetworkError(error) {
|
|
|
226
226
|
|
|
227
227
|
// src/video/timeout-utils.ts
|
|
228
228
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
229
|
+
|
|
230
|
+
class TimeoutError extends Error {
|
|
231
|
+
constructor(message = "Operation timed out") {
|
|
232
|
+
super(message);
|
|
233
|
+
this.name = "TimeoutError";
|
|
234
|
+
}
|
|
235
|
+
}
|
|
229
236
|
function withTimeout(promise, timeoutMs, errorMessage = "Operation timed out") {
|
|
230
237
|
let timeoutId = null;
|
|
231
238
|
const timeoutPromise = new Promise((_, reject) => {
|
|
232
239
|
timeoutId = window.setTimeout(() => {
|
|
233
|
-
reject(new
|
|
240
|
+
reject(new TimeoutError(errorMessage));
|
|
234
241
|
}, timeoutMs);
|
|
235
242
|
});
|
|
236
243
|
return Promise.race([
|
|
@@ -280,6 +287,7 @@ class MediaPlayer {
|
|
|
280
287
|
audioBufferHealth = 0;
|
|
281
288
|
audioIteratorStarted = false;
|
|
282
289
|
HEALTHY_BUFER_THRESHOLD_SECONDS = 1;
|
|
290
|
+
mediaEnded = false;
|
|
283
291
|
onVideoFrameCallback;
|
|
284
292
|
constructor({
|
|
285
293
|
canvas,
|
|
@@ -440,6 +448,8 @@ class MediaPlayer {
|
|
|
440
448
|
src: this.src
|
|
441
449
|
});
|
|
442
450
|
if (newTime === null) {
|
|
451
|
+
this.videoAsyncId++;
|
|
452
|
+
this.nextFrame = null;
|
|
443
453
|
this.clearCanvas();
|
|
444
454
|
await this.cleanAudioIteratorAndNodes();
|
|
445
455
|
return;
|
|
@@ -449,6 +459,7 @@ class MediaPlayer {
|
|
|
449
459
|
if (isSignificantSeek) {
|
|
450
460
|
this.nextFrame = null;
|
|
451
461
|
this.audioSyncAnchor = this.sharedAudioContext.currentTime - newTime;
|
|
462
|
+
this.mediaEnded = false;
|
|
452
463
|
if (this.audioSink) {
|
|
453
464
|
await this.cleanAudioIteratorAndNodes();
|
|
454
465
|
}
|
|
@@ -646,6 +657,7 @@ class MediaPlayer {
|
|
|
646
657
|
while (true) {
|
|
647
658
|
const newNextFrame = (await this.videoFrameIterator.next()).value ?? null;
|
|
648
659
|
if (!newNextFrame) {
|
|
660
|
+
this.mediaEnded = true;
|
|
649
661
|
break;
|
|
650
662
|
}
|
|
651
663
|
const playbackTime = this.getPlaybackTime();
|
|
@@ -716,12 +728,15 @@ class MediaPlayer {
|
|
|
716
728
|
let result;
|
|
717
729
|
try {
|
|
718
730
|
result = await withTimeout(this.audioBufferIterator.next(), BUFFERING_TIMEOUT_MS, "Iterator timeout");
|
|
719
|
-
} catch {
|
|
720
|
-
this.
|
|
731
|
+
} catch (error) {
|
|
732
|
+
if (error instanceof TimeoutError && !this.mediaEnded) {
|
|
733
|
+
this.setBufferingState(true);
|
|
734
|
+
}
|
|
721
735
|
await sleep(10);
|
|
722
736
|
continue;
|
|
723
737
|
}
|
|
724
738
|
if (result.done || !result.value) {
|
|
739
|
+
this.mediaEnded = true;
|
|
725
740
|
break;
|
|
726
741
|
}
|
|
727
742
|
const { buffer, timestamp, duration } = result.value;
|
|
@@ -45,6 +45,7 @@ export declare class MediaPlayer {
|
|
|
45
45
|
private audioBufferHealth;
|
|
46
46
|
private audioIteratorStarted;
|
|
47
47
|
private readonly HEALTHY_BUFER_THRESHOLD_SECONDS;
|
|
48
|
+
private mediaEnded;
|
|
48
49
|
private onVideoFrameCallback?;
|
|
49
50
|
constructor({ canvas, src, logLevel, sharedAudioContext, loop, trimBefore, trimAfter, playbackRate, audioStreamIndex, fps, }: {
|
|
50
51
|
canvas: HTMLCanvasElement | null;
|
|
@@ -2,7 +2,7 @@ import { ALL_FORMATS, AudioBufferSink, CanvasSink, Input, UrlSource, } from 'med
|
|
|
2
2
|
import { Internals } from 'remotion';
|
|
3
3
|
import { getTimeInSeconds } from '../get-time-in-seconds';
|
|
4
4
|
import { isNetworkError } from '../is-network-error';
|
|
5
|
-
import { sleep, withTimeout } from './timeout-utils';
|
|
5
|
+
import { sleep, TimeoutError, withTimeout } from './timeout-utils';
|
|
6
6
|
export const SEEK_THRESHOLD = 0.05;
|
|
7
7
|
const AUDIO_BUFFER_TOLERANCE_THRESHOLD = 0.1;
|
|
8
8
|
export class MediaPlayer {
|
|
@@ -30,6 +30,7 @@ export class MediaPlayer {
|
|
|
30
30
|
this.audioBufferHealth = 0;
|
|
31
31
|
this.audioIteratorStarted = false;
|
|
32
32
|
this.HEALTHY_BUFER_THRESHOLD_SECONDS = 1;
|
|
33
|
+
this.mediaEnded = false;
|
|
33
34
|
this.input = null;
|
|
34
35
|
this.render = () => {
|
|
35
36
|
if (this.isBuffering) {
|
|
@@ -100,6 +101,7 @@ export class MediaPlayer {
|
|
|
100
101
|
while (true) {
|
|
101
102
|
const newNextFrame = (await this.videoFrameIterator.next()).value ?? null;
|
|
102
103
|
if (!newNextFrame) {
|
|
104
|
+
this.mediaEnded = true;
|
|
103
105
|
break;
|
|
104
106
|
}
|
|
105
107
|
const playbackTime = this.getPlaybackTime();
|
|
@@ -138,12 +140,16 @@ export class MediaPlayer {
|
|
|
138
140
|
try {
|
|
139
141
|
result = await withTimeout(this.audioBufferIterator.next(), BUFFERING_TIMEOUT_MS, 'Iterator timeout');
|
|
140
142
|
}
|
|
141
|
-
catch {
|
|
142
|
-
this.
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (error instanceof TimeoutError && !this.mediaEnded) {
|
|
145
|
+
this.setBufferingState(true);
|
|
146
|
+
}
|
|
143
147
|
await sleep(10);
|
|
144
148
|
continue;
|
|
145
149
|
}
|
|
150
|
+
// media has ended
|
|
146
151
|
if (result.done || !result.value) {
|
|
152
|
+
this.mediaEnded = true;
|
|
147
153
|
break;
|
|
148
154
|
}
|
|
149
155
|
const { buffer, timestamp, duration } = result.value;
|
|
@@ -337,6 +343,9 @@ export class MediaPlayer {
|
|
|
337
343
|
src: this.src,
|
|
338
344
|
});
|
|
339
345
|
if (newTime === null) {
|
|
346
|
+
// invalidate in-flight video operations
|
|
347
|
+
this.videoAsyncId++;
|
|
348
|
+
this.nextFrame = null;
|
|
340
349
|
this.clearCanvas();
|
|
341
350
|
await this.cleanAudioIteratorAndNodes();
|
|
342
351
|
return;
|
|
@@ -347,6 +356,7 @@ export class MediaPlayer {
|
|
|
347
356
|
if (isSignificantSeek) {
|
|
348
357
|
this.nextFrame = null;
|
|
349
358
|
this.audioSyncAnchor = this.sharedAudioContext.currentTime - newTime;
|
|
359
|
+
this.mediaEnded = false;
|
|
350
360
|
if (this.audioSink) {
|
|
351
361
|
await this.cleanAudioIteratorAndNodes();
|
|
352
362
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/* eslint-disable no-promise-executor-return */
|
|
2
2
|
export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
export class TimeoutError extends Error {
|
|
4
|
+
constructor(message = 'Operation timed out') {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'TimeoutError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
3
9
|
export function withTimeout(promise, timeoutMs, errorMessage = 'Operation timed out') {
|
|
4
10
|
let timeoutId = null;
|
|
5
11
|
const timeoutPromise = new Promise((_, reject) => {
|
|
6
12
|
timeoutId = window.setTimeout(() => {
|
|
7
|
-
reject(new
|
|
13
|
+
reject(new TimeoutError(errorMessage));
|
|
8
14
|
}, timeoutMs);
|
|
9
15
|
});
|
|
10
16
|
return Promise.race([
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/media",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.362",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"mediabunny": "1.23.0",
|
|
25
|
-
"remotion": "4.0.
|
|
25
|
+
"remotion": "4.0.362",
|
|
26
26
|
"webdriverio": "9.19.2"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"react-dom": ">=16.8.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
33
|
+
"@remotion/eslint-config-internal": "4.0.362",
|
|
34
34
|
"@vitest/browser": "^3.2.4",
|
|
35
35
|
"eslint": "9.19.0",
|
|
36
36
|
"react": "19.0.0",
|