{"record":{"id":"1058452d7320291f","repo":"remotion-dev/remotion","slug":"video-frames-must-be-in-presentation-order","errorCode":null,"errorMessage":"Video frames must be in presentation order.","messagePattern":"Video frames must be in presentation order\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/video-matting/src/video-timing.ts","lineNumber":14,"sourceCode":"export const rebaseVideoTimestamp = ({\n\ttimestamp,\n\tfirstVideoTimestamp,\n}: {\n\ttimestamp: number;\n\tfirstVideoTimestamp: number;\n}): number => {\n\tif (!Number.isFinite(timestamp) || !Number.isFinite(firstVideoTimestamp)) {\n\t\tthrow new TypeError('Video timestamps must be finite numbers.');\n\t}\n\n\tconst rebased = timestamp - firstVideoTimestamp;\n\tif (rebased < -Number.EPSILON * 16) {\n\t\tthrow new Error('Video frames must be in presentation order.');\n\t}\n\n\treturn Math.max(0, rebased);\n};\n\nexport const getClippedVideoFrameTiming = ({\n\ttimestamp,\n\tduration,\n\tvideoStartTimestamp,\n\tvideoEndTimestamp,\n}: {\n\ttimestamp: number;\n\tduration: number;\n\tvideoStartTimestamp: number;\n\tvideoEndTimestamp: number;\n}): {timestamp: number; duration: number} | null => {\n\tif (!Number.isFinite(timestamp)) {\n\t\tthrow new TypeError('The video frame timestamp must be finite.');","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/remotion-dev/remotion/blob/b2f4e34732f3c6c222ea029413e22dc402218cd7/packages/video-matting/src/video-timing.ts#L1-L32","documentation":"After rebasing (timestamp - firstVideoTimestamp), rebaseVideoTimestamp rejects frames that precede the video start by more than a tiny epsilon (-Number.EPSILON * 16), throwing 'Video frames must be in presentation order.' A small negative slack is tolerated to absorb floating-point jitter. This enforces monotonically non-decreasing frame order expected by the encoder/processor.","triggerScenarios":"Feeding frames whose timestamps go backwards relative to firstVideoTimestamp beyond floating-point jitter — e.g. interleaved tracks processed out of order, B-frame/PTS-vs-DTS confusion, or frames from a seek arriving before the seek point.","commonSituations":"Manually sorting frames with an unstable sort, mixing keyframe-first decoding with presentation-order playback, or concatenating frames from multiple video segments without resetting firstVideoTimestamp.","solutions":["Sort frames by timestamp (stable sort) before processing","Set firstVideoTimestamp to the minimum frame timestamp of the batch, not the first decoded frame","Check whether you are using DTS instead of PTS and switch to presentation timestamps","Handle seeking explicitly: reset processing state and firstVideoTimestamp after a seek","If jitter is legitimate, clamp tiny negatives instead of reordering frames"],"exampleFix":"// before\nframes.forEach((f) => process(rebasedTimestamp({timestamp: f.dts, firstVideoTimestamp})));\n// after\nconst ordered = [...frames].sort((a, b) => a.pts - b.pts);\nordered.forEach((f) => process(rebasedTimestamp({timestamp: f.pts, firstVideoTimestamp: ordered[0].pts})));","handlingStrategy":"validation","validationCode":"let last = -Infinity;\nfor (const f of frames) {\n  if (f.pts < last) throw new Error('Frames not in presentation order');\n  last = f.pts;\n}","typeGuard":"const isInPresentationOrder = (frames: {pts: number}[]): boolean =>\n  frames.every((f, i) => i === 0 || f.pts >= frames[i - 1].pts);","tryCatchPattern":"try {\n  const ts = rebasedTimestamp({timestamp: frame.pts, firstVideoTimestamp});\n} catch (err) {\n  if (err instanceof Error && err.message === 'Video frames must be in presentation order.') {\n    console.warn('Out-of-order frame dropped');\n    return;\n  }\n  throw err;\n}","preventionTips":["Stable-sort frames by PTS before processing","Use PTS, not DTS, for presentation ordering","Reset firstVideoTimestamp and state after seeks or segment switches","Watch for floating-point jitter; rely on the library's epsilon tolerance instead of exact comparisons"],"tags":["video-matting","timestamps","frame-order"],"backgroundTag":"invalid-state-transition","analyzedSha":"b2f4e34732f3c6c222ea029413e22dc402218cd7","analyzedAt":"2026-09-09T13:27:51.281Z","contentChangedAt":"2026-09-09T13:27:51.281Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}