@remotion/media 4.0.486 → 4.0.487

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.
Files changed (2) hide show
  1. package/dist/esm/index.mjs +91 -23
  2. package/package.json +5 -5
@@ -1203,6 +1203,7 @@ var makePrewarmedVideoIteratorCache = (videoSink) => {
1203
1203
  };
1204
1204
 
1205
1205
  // src/video/video-preview-iterator.ts
1206
+ var MAXIMUM_AWAITED_PEEK_DISTANCE_SECONDS = 0.05;
1206
1207
  var createVideoIterator = async (timeToSeek, cache) => {
1207
1208
  let destroyed = false;
1208
1209
  const iterator = cache.makeIteratorOrUsePrewarmed(timeToSeek);
@@ -1217,17 +1218,61 @@ var createVideoIterator = async (timeToSeek, cache) => {
1217
1218
  }
1218
1219
  lastReturnedFrame = frame;
1219
1220
  };
1220
- const peek = async () => {
1221
+ const setPeekedFrame = (frame) => {
1222
+ peekedFrame = frame;
1223
+ if (peekedFrame === null) {
1224
+ iteratorEnded = true;
1225
+ }
1226
+ return peekedFrame;
1227
+ };
1228
+ const peekIfReady = () => {
1221
1229
  if (peekedFrame) {
1222
- return peekedFrame;
1230
+ return { type: "ready", frame: peekedFrame };
1231
+ }
1232
+ if (iteratorEnded) {
1233
+ return { type: "ready", frame: null };
1223
1234
  }
1224
1235
  const next = iterator.next();
1225
1236
  if (next.type === "ready") {
1226
- peekedFrame = next.frame;
1227
- } else {
1228
- peekedFrame = await next.wait();
1237
+ return { type: "ready", frame: setPeekedFrame(next.frame) };
1229
1238
  }
1230
- return peekedFrame;
1239
+ return {
1240
+ type: "pending",
1241
+ wait: next.wait
1242
+ };
1243
+ };
1244
+ const peek = async () => {
1245
+ const peeked = peekIfReady();
1246
+ if (peeked.type === "ready") {
1247
+ return peeked.frame;
1248
+ }
1249
+ return setPeekedFrame(await peeked.wait());
1250
+ };
1251
+ const getFrameEndTimestampFromPeek = (frame) => {
1252
+ return frame ? roundTo4Digits(frame.timestamp) : Infinity;
1253
+ };
1254
+ const getFrameEndTimestamp = async () => {
1255
+ return getFrameEndTimestampFromPeek(await peek());
1256
+ };
1257
+ const getFrameEndTimestampIfCloseEnough = async ({
1258
+ timestamp,
1259
+ frameTimestamp
1260
+ }) => {
1261
+ const peeked = peekIfReady();
1262
+ if (peeked.type === "ready") {
1263
+ return {
1264
+ type: "ready",
1265
+ timestamp: getFrameEndTimestampFromPeek(peeked.frame)
1266
+ };
1267
+ }
1268
+ if (timestamp - frameTimestamp > MAXIMUM_AWAITED_PEEK_DISTANCE_SECONDS) {
1269
+ return { type: "pending" };
1270
+ }
1271
+ const awaitedPeeked = setPeekedFrame(await peeked.wait());
1272
+ return {
1273
+ type: "ready",
1274
+ timestamp: getFrameEndTimestampFromPeek(awaitedPeeked)
1275
+ };
1231
1276
  };
1232
1277
  const getNextOrNullIfNotAvailable = () => {
1233
1278
  if (peekedFrame) {
@@ -1295,14 +1340,7 @@ var createVideoIterator = async (timeToSeek, cache) => {
1295
1340
  reason: `iterator is too far, most recently returned ${frameTimestamp}`
1296
1341
  };
1297
1342
  }
1298
- let lastFrameDuration = lastReturnedFrame.duration;
1299
- if (lastFrameDuration === 0) {
1300
- const peeked = await peek();
1301
- if (peeked) {
1302
- lastFrameDuration = peeked.timestamp - lastReturnedFrame.timestamp;
1303
- }
1304
- }
1305
- const frameEndTimestamp = roundTo4Digits(lastReturnedFrame.timestamp + lastFrameDuration);
1343
+ const frameEndTimestamp = await getFrameEndTimestamp();
1306
1344
  if (frameTimestamp <= timestamp && frameEndTimestamp > timestamp) {
1307
1345
  return {
1308
1346
  type: "satisfied",
@@ -1345,8 +1383,17 @@ var createVideoIterator = async (timeToSeek, cache) => {
1345
1383
  };
1346
1384
  }
1347
1385
  const frameTimestamp = roundTo4Digits(frame.frame.timestamp);
1348
- const frameEndTimestamp = roundTo4Digits(frame.frame.timestamp + frame.frame.duration);
1349
- if (frameTimestamp <= timestamp && frameEndTimestamp > timestamp) {
1386
+ const frameEndTimestamp = await getFrameEndTimestampIfCloseEnough({
1387
+ frameTimestamp,
1388
+ timestamp
1389
+ });
1390
+ if (frameEndTimestamp.type === "pending") {
1391
+ return {
1392
+ type: "not-satisfied",
1393
+ reason: "iterator did not have next frame ready"
1394
+ };
1395
+ }
1396
+ if (frameTimestamp <= timestamp && frameEndTimestamp.timestamp > timestamp) {
1350
1397
  return {
1351
1398
  type: "satisfied",
1352
1399
  frame: frame.frame
@@ -2961,17 +3008,30 @@ var makeKeyframeBank = async ({
2961
3008
  let hasReachedEndOfVideo = false;
2962
3009
  let lastUsed = Date.now();
2963
3010
  let allocationSize = 0;
2964
- const getDurationOfFrame = (timestamp) => {
3011
+ const getMeasuredDurationOfFrame = (timestamp) => {
2965
3012
  const index = frameTimestamps.indexOf(timestamp);
2966
3013
  if (index === -1) {
2967
3014
  throw new Error(`Frame ${timestamp} not found`);
2968
3015
  }
2969
3016
  const nextTimestamp = frameTimestamps[index + 1];
2970
- if (!nextTimestamp) {
3017
+ if (nextTimestamp === undefined) {
2971
3018
  return null;
2972
3019
  }
2973
3020
  return nextTimestamp - timestamp;
2974
3021
  };
3022
+ const getKnownDurationOfFrame = (timestamp) => {
3023
+ const measuredDuration = getMeasuredDurationOfFrame(timestamp);
3024
+ if (measuredDuration !== null) {
3025
+ return measuredDuration;
3026
+ }
3027
+ if (!hasReachedEndOfVideo) {
3028
+ return null;
3029
+ }
3030
+ return frames[timestamp].duration ?? 0;
3031
+ };
3032
+ const getEstimatedDurationOfFrame = (timestamp) => {
3033
+ return getMeasuredDurationOfFrame(timestamp) ?? frames[timestamp].duration ?? 0;
3034
+ };
2975
3035
  const deleteFrameAtTimestamp = (timestamp) => {
2976
3036
  allocationSize -= getAllocationSize(frames[timestamp]);
2977
3037
  frameTimestamps.splice(frameTimestamps.indexOf(timestamp), 1);
@@ -2993,7 +3053,10 @@ var makeKeyframeBank = async ({
2993
3053
  if (!frames[frameTimestamp]) {
2994
3054
  continue;
2995
3055
  }
2996
- const duration = getDurationOfFrame(frameTimestamp) ?? frames[frameTimestamp].duration;
3056
+ const duration = getKnownDurationOfFrame(frameTimestamp);
3057
+ if (duration === null) {
3058
+ continue;
3059
+ }
2997
3060
  if (frameTimestamp + duration < timestampInSeconds) {
2998
3061
  deleteFrameAtTimestamp(frameTimestamp);
2999
3062
  deletedTimestamps.push(frameTimestamp);
@@ -3005,14 +3068,20 @@ var makeKeyframeBank = async ({
3005
3068
  };
3006
3069
  const hasDecodedEnoughForTimestamp = (timestamp) => {
3007
3070
  const lastFrameTimestamp = frameTimestamps[frameTimestamps.length - 1];
3008
- if (!lastFrameTimestamp) {
3071
+ if (lastFrameTimestamp === undefined) {
3009
3072
  return false;
3010
3073
  }
3011
3074
  const lastFrame = frames[lastFrameTimestamp];
3012
3075
  if (!lastFrame) {
3013
3076
  return true;
3014
3077
  }
3015
- const duration = getDurationOfFrame(lastFrameTimestamp) ?? lastFrame.duration;
3078
+ if (roundTo4Digits(lastFrameTimestamp) >= roundTo4Digits(timestamp)) {
3079
+ return true;
3080
+ }
3081
+ const duration = getKnownDurationOfFrame(lastFrameTimestamp);
3082
+ if (duration === null) {
3083
+ return false;
3084
+ }
3016
3085
  return roundTo4Digits(lastFrameTimestamp + duration) > roundTo4Digits(timestamp);
3017
3086
  };
3018
3087
  const addFrame = (frame, logLevel) => {
@@ -3086,8 +3155,7 @@ var makeKeyframeBank = async ({
3086
3155
  }
3087
3156
  const firstTimestamp = frameTimestamps[0];
3088
3157
  const lastTimestamp = frameTimestamps[frameTimestamps.length - 1];
3089
- const lastFrame = frames[lastTimestamp];
3090
- const lastFrameDuration = getDurationOfFrame(lastTimestamp) ?? lastFrame.duration ?? 0;
3158
+ const lastFrameDuration = getEstimatedDurationOfFrame(lastTimestamp);
3091
3159
  return {
3092
3160
  firstTimestamp,
3093
3161
  lastTimestamp: lastTimestamp + lastFrameDuration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/media",
3
- "version": "4.0.486",
3
+ "version": "4.0.487",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -22,8 +22,8 @@
22
22
  "make": "tsgo && bun --env-file=../.env.bundle bundle.ts"
23
23
  },
24
24
  "dependencies": {
25
- "mediabunny": "1.50.3",
26
- "remotion": "4.0.486",
25
+ "mediabunny": "1.50.7",
26
+ "remotion": "4.0.487",
27
27
  "zod": "4.3.6"
28
28
  },
29
29
  "peerDependencies": {
@@ -31,8 +31,8 @@
31
31
  "react-dom": ">=16.8.0"
32
32
  },
33
33
  "devDependencies": {
34
- "@remotion/eslint-config-internal": "4.0.486",
35
- "@remotion/player": "4.0.486",
34
+ "@remotion/eslint-config-internal": "4.0.487",
35
+ "@remotion/player": "4.0.487",
36
36
  "@vitest/browser-webdriverio": "4.0.9",
37
37
  "eslint": "9.19.0",
38
38
  "react": "19.2.3",