@remotion/studio 4.0.459 → 4.0.461
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/Studio.d.ts +0 -1
- package/dist/Studio.js +4 -4
- package/dist/components/AudioWaveform.js +21 -13
- package/dist/components/Checkbox.d.ts +7 -0
- package/dist/components/Checkbox.js +38 -24
- package/dist/components/Editor.js +10 -9
- package/dist/components/ExpandedTracksProvider.d.ts +9 -4
- package/dist/components/ExpandedTracksProvider.js +45 -15
- package/dist/components/MenuBuildIndicator.js +1 -2
- package/dist/components/MenuCompositionName.js +1 -0
- package/dist/components/NewComposition/ComboBox.d.ts +1 -0
- package/dist/components/NewComposition/ComboBox.js +14 -5
- package/dist/components/RenderButton.js +1 -1
- package/dist/components/SequencePropsSubscriptionProvider.d.ts +3 -0
- package/dist/components/SequencePropsSubscriptionProvider.js +26 -0
- package/dist/components/Timeline/SequencePropsObserver.d.ts +1 -0
- package/dist/components/Timeline/SequencePropsObserver.js +24 -0
- package/dist/components/Timeline/SubscribeToNodePaths.d.ts +7 -0
- package/dist/components/Timeline/SubscribeToNodePaths.js +15 -0
- package/dist/components/Timeline/Timeline.js +30 -49
- package/dist/components/Timeline/TimelineBooleanField.d.ts +4 -4
- package/dist/components/Timeline/TimelineBooleanField.js +5 -5
- package/dist/components/Timeline/TimelineDragHandler.js +37 -3
- package/dist/components/Timeline/TimelineEnumField.d.ts +5 -5
- package/dist/components/Timeline/TimelineEnumField.js +23 -15
- package/dist/components/Timeline/TimelineExpandArrowButton.d.ts +1 -0
- package/dist/components/Timeline/TimelineExpandArrowButton.js +5 -3
- package/dist/components/Timeline/TimelineExpandedRow.d.ts +6 -6
- package/dist/components/Timeline/TimelineExpandedRow.js +4 -5
- package/dist/components/Timeline/TimelineExpandedSection.d.ts +2 -2
- package/dist/components/Timeline/TimelineExpandedSection.js +20 -9
- package/dist/components/Timeline/TimelineFieldRow.d.ts +2 -3
- package/dist/components/Timeline/TimelineFieldRow.js +66 -30
- package/dist/components/Timeline/TimelineHeightContainer.d.ts +7 -0
- package/dist/components/Timeline/TimelineHeightContainer.js +51 -0
- package/dist/components/Timeline/TimelineList.js +1 -1
- package/dist/components/Timeline/TimelineListItem.d.ts +2 -0
- package/dist/components/Timeline/TimelineListItem.js +33 -18
- package/dist/components/Timeline/TimelineNumberField.d.ts +5 -5
- package/dist/components/Timeline/TimelineNumberField.js +12 -10
- package/dist/components/Timeline/TimelineRotationField.d.ts +5 -5
- package/dist/components/Timeline/TimelineRotationField.js +10 -10
- package/dist/components/Timeline/TimelineSchemaField.d.ts +4 -6
- package/dist/components/Timeline/TimelineSchemaField.js +11 -11
- package/dist/components/Timeline/TimelineSequence.js +2 -2
- package/dist/components/Timeline/TimelineSlider.js +2 -2
- package/dist/components/Timeline/TimelineStack/get-stack.js +17 -31
- package/dist/components/Timeline/TimelineStack/index.js +0 -10
- package/dist/components/Timeline/TimelineTimeIndicators.js +2 -2
- package/dist/components/Timeline/TimelineTracks.d.ts +1 -1
- package/dist/components/Timeline/TimelineTracks.js +53 -12
- package/dist/components/Timeline/TimelineTranslateField.d.ts +5 -5
- package/dist/components/Timeline/TimelineTranslateField.js +19 -37
- package/dist/components/Timeline/TimelineVideoInfo.js +25 -140
- package/dist/components/Timeline/sequence-props-subscription-store.d.ts +10 -13
- package/dist/components/Timeline/sequence-props-subscription-store.js +56 -123
- package/dist/components/Timeline/use-sequence-props-subscription.d.ts +6 -6
- package/dist/components/Timeline/use-sequence-props-subscription.js +25 -55
- package/dist/components/Timeline/use-timeline-height.d.ts +5 -0
- package/dist/components/Timeline/use-timeline-height.js +39 -0
- package/dist/error-overlay/react-overlay/utils/get-source-map.d.ts +3 -3
- package/dist/error-overlay/react-overlay/utils/get-source-map.js +5 -5
- package/dist/error-overlay/react-overlay/utils/unmapper.d.ts +0 -6
- package/dist/error-overlay/react-overlay/utils/unmapper.js +8 -1
- package/dist/esm/{chunk-0njpenna.js → chunk-yzh34sp0.js} +3026 -3446
- package/dist/esm/internals.mjs +3026 -3446
- package/dist/esm/previewEntry.mjs +3028 -3449
- package/dist/esm/renderEntry.mjs +2 -5
- package/dist/helpers/calculate-timeline.d.ts +3 -2
- package/dist/helpers/calculate-timeline.js +43 -2
- package/dist/helpers/get-timeline-sequence-layout.js +3 -3
- package/dist/helpers/get-timeline-sequence-sort-key.d.ts +7 -1
- package/dist/helpers/timeline-layout.d.ts +19 -9
- package/dist/helpers/timeline-layout.js +50 -20
- package/dist/icons/Checkmark.d.ts +4 -1
- package/dist/icons/Checkmark.js +1 -5
- package/dist/icons/caret.d.ts +3 -1
- package/dist/icons/caret.js +5 -2
- package/dist/internals.d.ts +0 -1
- package/dist/previewEntry.js +1 -1
- package/dist/renderEntry.js +3 -3
- package/package.json +13 -21
- package/dist/audio-waveform-worker.d.ts +0 -1
- package/dist/audio-waveform-worker.js +0 -102
- package/dist/components/audio-waveform-worker-types.d.ts +0 -28
- package/dist/components/audio-waveform-worker-types.js +0 -2
- package/dist/components/draw-peaks.d.ts +0 -1
- package/dist/components/draw-peaks.js +0 -68
- package/dist/components/load-waveform-peaks.d.ts +0 -13
- package/dist/components/load-waveform-peaks.js +0 -76
- package/dist/components/looped-media-timeline.d.ts +0 -6
- package/dist/components/looped-media-timeline.js +0 -14
- package/dist/components/parse-color.d.ts +0 -1
- package/dist/components/parse-color.js +0 -17
- package/dist/components/slice-waveform-peaks.d.ts +0 -7
- package/dist/components/slice-waveform-peaks.js +0 -15
- package/dist/components/waveform-peak-processor.d.ts +0 -23
- package/dist/components/waveform-peak-processor.js +0 -77
- package/dist/esm/audio-waveform-worker.mjs +0 -354
- package/dist/helpers/extract-frames.d.ts +0 -18
- package/dist/helpers/extract-frames.js +0 -87
- package/dist/helpers/frame-database.d.ts +0 -16
- package/dist/helpers/frame-database.js +0 -65
- package/dist/helpers/resize-video-frame.d.ts +0 -4
- package/dist/helpers/resize-video-frame.js +0 -39
- package/dist/make-audio-waveform-worker.d.ts +0 -1
- package/dist/make-audio-waveform-worker.js +0 -10
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { CanUpdateSequencePropStatus } from 'remotion';
|
|
3
|
+
import type { SchemaFieldInfo, TimelineFieldOnDragValueChange, TimelineFieldOnSave } from '../../helpers/timeline-layout';
|
|
3
4
|
export declare const TimelineTranslateField: React.FC<{
|
|
4
5
|
readonly field: SchemaFieldInfo;
|
|
5
|
-
readonly
|
|
6
|
+
readonly propStatus: CanUpdateSequencePropStatus;
|
|
6
7
|
readonly effectiveValue: unknown;
|
|
7
|
-
readonly
|
|
8
|
-
readonly
|
|
9
|
-
readonly onDragValueChange: (key: string, value: unknown) => void;
|
|
8
|
+
readonly onSave: TimelineFieldOnSave;
|
|
9
|
+
readonly onDragValueChange: TimelineFieldOnDragValueChange;
|
|
10
10
|
readonly onDragEnd: () => void;
|
|
11
11
|
}>;
|
|
@@ -23,7 +23,7 @@ const containerStyle = {
|
|
|
23
23
|
display: 'flex',
|
|
24
24
|
gap: 4,
|
|
25
25
|
};
|
|
26
|
-
const TimelineTranslateField = ({ field,
|
|
26
|
+
const TimelineTranslateField = ({ field, propStatus, effectiveValue, onSave, onDragValueChange, onDragEnd, }) => {
|
|
27
27
|
var _a;
|
|
28
28
|
const [dragX, setDragX] = (0, react_1.useState)(null);
|
|
29
29
|
const [dragY, setDragY] = (0, react_1.useState)(null);
|
|
@@ -41,13 +41,13 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
|
|
|
41
41
|
const onXChange = (0, react_1.useCallback)((newVal) => {
|
|
42
42
|
setDragX(newVal);
|
|
43
43
|
const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
|
|
44
|
-
onDragValueChange(
|
|
45
|
-
}, [onDragValueChange,
|
|
44
|
+
onDragValueChange(makeString(newVal, currentY));
|
|
45
|
+
}, [onDragValueChange, dragY, codeY, makeString]);
|
|
46
46
|
const onXChangeEnd = (0, react_1.useCallback)((newVal) => {
|
|
47
47
|
const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
|
|
48
48
|
const newStr = makeString(newVal, currentY);
|
|
49
|
-
if (canUpdate && newStr !== codeValue) {
|
|
50
|
-
onSave(
|
|
49
|
+
if (propStatus.canUpdate && newStr !== propStatus.codeValue) {
|
|
50
|
+
onSave(newStr).finally(() => {
|
|
51
51
|
setDragX(null);
|
|
52
52
|
onDragEnd();
|
|
53
53
|
});
|
|
@@ -56,40 +56,31 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
|
|
|
56
56
|
setDragX(null);
|
|
57
57
|
onDragEnd();
|
|
58
58
|
}
|
|
59
|
-
}, [
|
|
60
|
-
dragY,
|
|
61
|
-
codeY,
|
|
62
|
-
makeString,
|
|
63
|
-
canUpdate,
|
|
64
|
-
codeValue,
|
|
65
|
-
onSave,
|
|
66
|
-
field.key,
|
|
67
|
-
onDragEnd,
|
|
68
|
-
]);
|
|
59
|
+
}, [dragY, codeY, makeString, propStatus, onSave, onDragEnd]);
|
|
69
60
|
const onXTextChange = (0, react_1.useCallback)((newVal) => {
|
|
70
|
-
if (canUpdate) {
|
|
61
|
+
if (propStatus.canUpdate) {
|
|
71
62
|
const parsed = Number(newVal);
|
|
72
63
|
if (!Number.isNaN(parsed)) {
|
|
73
64
|
const currentY = dragY !== null && dragY !== void 0 ? dragY : codeY;
|
|
74
65
|
const newStr = makeString(parsed, currentY);
|
|
75
|
-
if (newStr !== codeValue) {
|
|
66
|
+
if (newStr !== propStatus.codeValue) {
|
|
76
67
|
setDragX(parsed);
|
|
77
|
-
onSave(
|
|
68
|
+
onSave(newStr);
|
|
78
69
|
}
|
|
79
70
|
}
|
|
80
71
|
}
|
|
81
|
-
}, [
|
|
72
|
+
}, [propStatus, dragY, codeY, makeString, onSave]);
|
|
82
73
|
// --- Y callbacks ---
|
|
83
74
|
const onYChange = (0, react_1.useCallback)((newVal) => {
|
|
84
75
|
setDragY(newVal);
|
|
85
76
|
const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
|
|
86
|
-
onDragValueChange(
|
|
87
|
-
}, [onDragValueChange,
|
|
77
|
+
onDragValueChange(makeString(currentX, newVal));
|
|
78
|
+
}, [onDragValueChange, dragX, codeX, makeString]);
|
|
88
79
|
const onYChangeEnd = (0, react_1.useCallback)((newVal) => {
|
|
89
80
|
const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
|
|
90
81
|
const newStr = makeString(currentX, newVal);
|
|
91
|
-
if (canUpdate && newStr !== codeValue) {
|
|
92
|
-
onSave(
|
|
82
|
+
if (propStatus.canUpdate && newStr !== propStatus.codeValue) {
|
|
83
|
+
onSave(newStr).finally(() => {
|
|
93
84
|
setDragY(null);
|
|
94
85
|
onDragEnd();
|
|
95
86
|
});
|
|
@@ -98,31 +89,22 @@ const TimelineTranslateField = ({ field, codeValue, effectiveValue, canUpdate, o
|
|
|
98
89
|
setDragY(null);
|
|
99
90
|
onDragEnd();
|
|
100
91
|
}
|
|
101
|
-
}, [
|
|
102
|
-
dragX,
|
|
103
|
-
codeX,
|
|
104
|
-
makeString,
|
|
105
|
-
canUpdate,
|
|
106
|
-
codeValue,
|
|
107
|
-
onSave,
|
|
108
|
-
field.key,
|
|
109
|
-
onDragEnd,
|
|
110
|
-
]);
|
|
92
|
+
}, [dragX, codeX, makeString, propStatus, onSave, onDragEnd]);
|
|
111
93
|
const onYTextChange = (0, react_1.useCallback)((newVal) => {
|
|
112
|
-
if (canUpdate) {
|
|
94
|
+
if (propStatus.canUpdate) {
|
|
113
95
|
const parsed = Number(newVal);
|
|
114
96
|
if (!Number.isNaN(parsed)) {
|
|
115
97
|
const currentX = dragX !== null && dragX !== void 0 ? dragX : codeX;
|
|
116
98
|
const newStr = makeString(currentX, parsed);
|
|
117
|
-
if (newStr !== codeValue) {
|
|
99
|
+
if (newStr !== propStatus.codeValue) {
|
|
118
100
|
setDragY(parsed);
|
|
119
|
-
onSave(
|
|
101
|
+
onSave(newStr).catch(() => {
|
|
120
102
|
setDragY(null);
|
|
121
103
|
});
|
|
122
104
|
}
|
|
123
105
|
}
|
|
124
106
|
}
|
|
125
|
-
}, [
|
|
107
|
+
}, [propStatus, onSave, dragX, codeX, makeString]);
|
|
126
108
|
return (jsx_runtime_1.jsxs("span", { style: containerStyle, children: [
|
|
127
109
|
jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragX !== null && dragX !== void 0 ? dragX : codeX, style: leftDraggerStyle, status: "ok", small: true, onValueChange: onXChange, onValueChangeEnd: onXChangeEnd, onTextChange: onXTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false }), jsx_runtime_1.jsx("div", { style: { marginLeft: -6, marginRight: -6 } }), jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: dragY !== null && dragY !== void 0 ? dragY : codeY, style: rightDraggerStyle, status: "ok", small: true, onValueChange: onYChange, onValueChangeEnd: onYChangeEnd, onTextChange: onYTextChange, min: -Infinity, max: Infinity, step: step, formatter: formatter, rightAlign: false })
|
|
128
110
|
] }));
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TimelineVideoInfo = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const timeline_utils_1 = require("@remotion/timeline-utils");
|
|
5
6
|
const react_1 = require("react");
|
|
6
7
|
const remotion_1 = require("remotion");
|
|
7
|
-
const extract_frames_1 = require("../../helpers/extract-frames");
|
|
8
|
-
const frame_database_1 = require("../../helpers/frame-database");
|
|
9
|
-
const resize_video_frame_1 = require("../../helpers/resize-video-frame");
|
|
10
8
|
const timeline_layout_1 = require("../../helpers/timeline-layout");
|
|
11
9
|
const AudioWaveform_1 = require("../AudioWaveform");
|
|
12
|
-
const looped_media_timeline_1 = require("../looped-media-timeline");
|
|
13
10
|
const FILMSTRIP_HEIGHT = timeline_layout_1.TIMELINE_LAYER_HEIGHT_IMAGE - 2;
|
|
14
11
|
const outerStyle = {
|
|
15
12
|
width: '100%',
|
|
@@ -26,132 +23,11 @@ const filmstripContainerStyle = {
|
|
|
26
23
|
fontSize: 10,
|
|
27
24
|
fontFamily: 'Arial, Helvetica',
|
|
28
25
|
};
|
|
29
|
-
const WEBCODECS_TIMESCALE = 1000000;
|
|
30
|
-
const MAX_TIME_DEVIATION = WEBCODECS_TIMESCALE * 0.05;
|
|
31
|
-
const getDurationOfOneFrame = ({ visualizationWidth, aspectRatio, segmentDuration, }) => {
|
|
32
|
-
const framesFitInWidthUnrounded = visualizationWidth / (FILMSTRIP_HEIGHT * aspectRatio);
|
|
33
|
-
return (segmentDuration / framesFitInWidthUnrounded) * WEBCODECS_TIMESCALE;
|
|
34
|
-
};
|
|
35
|
-
const fixRounding = (value) => {
|
|
36
|
-
if (value % 1 >= 0.49999999) {
|
|
37
|
-
return Math.ceil(value);
|
|
38
|
-
}
|
|
39
|
-
return Math.floor(value);
|
|
40
|
-
};
|
|
41
|
-
const calculateTimestampSlots = ({ visualizationWidth, fromSeconds, segmentDuration, aspectRatio, }) => {
|
|
42
|
-
const framesFitInWidthUnrounded = visualizationWidth / (FILMSTRIP_HEIGHT * aspectRatio);
|
|
43
|
-
const framesFitInWidth = Math.ceil(framesFitInWidthUnrounded);
|
|
44
|
-
const durationOfOneFrame = getDurationOfOneFrame({
|
|
45
|
-
visualizationWidth,
|
|
46
|
-
aspectRatio,
|
|
47
|
-
segmentDuration,
|
|
48
|
-
});
|
|
49
|
-
const timestampTargets = [];
|
|
50
|
-
for (let i = 0; i < framesFitInWidth + 1; i++) {
|
|
51
|
-
const target = fromSeconds * WEBCODECS_TIMESCALE + durationOfOneFrame * (i + 0.5);
|
|
52
|
-
const snappedToDuration = (Math.round(fixRounding(target / durationOfOneFrame)) - 1) *
|
|
53
|
-
durationOfOneFrame;
|
|
54
|
-
timestampTargets.push(snappedToDuration);
|
|
55
|
-
}
|
|
56
|
-
return timestampTargets;
|
|
57
|
-
};
|
|
58
|
-
const ensureSlots = ({ filledSlots, naturalWidth, fromSeconds, toSeconds, aspectRatio, }) => {
|
|
59
|
-
const segmentDuration = toSeconds - fromSeconds;
|
|
60
|
-
const timestampTargets = calculateTimestampSlots({
|
|
61
|
-
visualizationWidth: naturalWidth,
|
|
62
|
-
fromSeconds,
|
|
63
|
-
segmentDuration,
|
|
64
|
-
aspectRatio,
|
|
65
|
-
});
|
|
66
|
-
for (const timestamp of timestampTargets) {
|
|
67
|
-
if (!filledSlots.has(timestamp)) {
|
|
68
|
-
filledSlots.set(timestamp, undefined);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
const drawSlot = ({ frame, ctx, filledSlots, visualizationWidth, timestamp, segmentDuration, fromSeconds, }) => {
|
|
73
|
-
const durationOfOneFrame = getDurationOfOneFrame({
|
|
74
|
-
visualizationWidth,
|
|
75
|
-
aspectRatio: frame.displayWidth / frame.displayHeight,
|
|
76
|
-
segmentDuration,
|
|
77
|
-
});
|
|
78
|
-
const relativeTimestamp = timestamp - fromSeconds * WEBCODECS_TIMESCALE;
|
|
79
|
-
const frameIndex = relativeTimestamp / durationOfOneFrame;
|
|
80
|
-
const thumbnailWidth = frame.displayWidth / window.devicePixelRatio;
|
|
81
|
-
const left = Math.floor(frameIndex * thumbnailWidth);
|
|
82
|
-
const right = Math.ceil((frameIndex + 1) * thumbnailWidth);
|
|
83
|
-
ctx.drawImage(frame, left, 0, right - left, frame.displayHeight / window.devicePixelRatio);
|
|
84
|
-
filledSlots.set(timestamp, frame.timestamp);
|
|
85
|
-
};
|
|
86
|
-
const fillWithCachedFrames = ({ ctx, naturalWidth, filledSlots, src, segmentDuration, fromSeconds, }) => {
|
|
87
|
-
const prefix = (0, frame_database_1.getFrameDatabaseKeyPrefix)(src);
|
|
88
|
-
const keys = Array.from(frame_database_1.frameDatabase.keys()).filter((k) => k.startsWith(prefix));
|
|
89
|
-
const targets = Array.from(filledSlots.keys());
|
|
90
|
-
for (const timestamp of targets) {
|
|
91
|
-
let bestKey;
|
|
92
|
-
let bestDistance = Infinity;
|
|
93
|
-
for (const key of keys) {
|
|
94
|
-
const distance = Math.abs((0, frame_database_1.getTimestampFromFrameDatabaseKey)(key) - timestamp);
|
|
95
|
-
if (distance < bestDistance) {
|
|
96
|
-
bestDistance = distance;
|
|
97
|
-
bestKey = key;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (!bestKey) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
const frame = frame_database_1.frameDatabase.get(bestKey);
|
|
104
|
-
if (!frame) {
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
const alreadyFilled = filledSlots.get(timestamp);
|
|
108
|
-
// Don't fill if a closer frame was already drawn
|
|
109
|
-
if (alreadyFilled &&
|
|
110
|
-
Math.abs(alreadyFilled - timestamp) <=
|
|
111
|
-
Math.abs(frame.frame.timestamp - timestamp)) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
frame.lastUsed = Date.now();
|
|
115
|
-
drawSlot({
|
|
116
|
-
ctx,
|
|
117
|
-
frame: frame.frame,
|
|
118
|
-
filledSlots,
|
|
119
|
-
visualizationWidth: naturalWidth,
|
|
120
|
-
timestamp,
|
|
121
|
-
segmentDuration,
|
|
122
|
-
fromSeconds,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
const fillFrameWhereItFits = ({ frame, filledSlots, ctx, visualizationWidth, segmentDuration, fromSeconds, }) => {
|
|
127
|
-
const slots = Array.from(filledSlots.keys());
|
|
128
|
-
for (let i = 0; i < slots.length; i++) {
|
|
129
|
-
const slot = slots[i];
|
|
130
|
-
if (Math.abs(slot - frame.timestamp) > MAX_TIME_DEVIATION) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const filled = filledSlots.get(slot);
|
|
134
|
-
// Don't fill if a better timestamp was already filled
|
|
135
|
-
if (filled &&
|
|
136
|
-
Math.abs(filled - slot) <= Math.abs(filled - frame.timestamp)) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
drawSlot({
|
|
140
|
-
ctx,
|
|
141
|
-
frame,
|
|
142
|
-
filledSlots,
|
|
143
|
-
visualizationWidth,
|
|
144
|
-
timestamp: slot,
|
|
145
|
-
segmentDuration,
|
|
146
|
-
fromSeconds,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
26
|
const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore, durationInFrames, playbackRate, volume, doesVolumeChange, premountWidth, postmountWidth, loopDisplay, }) => {
|
|
151
27
|
const { fps } = (0, remotion_1.useVideoConfig)();
|
|
152
28
|
const ref = (0, react_1.useRef)(null);
|
|
153
29
|
const [error, setError] = (0, react_1.useState)(null);
|
|
154
|
-
const aspectRatio = (0, react_1.useRef)((0,
|
|
30
|
+
const aspectRatio = (0, react_1.useRef)((0, timeline_utils_1.getAspectRatioFromCache)(src));
|
|
155
31
|
// for rendering frames
|
|
156
32
|
(0, react_1.useEffect)(() => {
|
|
157
33
|
if (error) {
|
|
@@ -170,11 +46,11 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
170
46
|
return;
|
|
171
47
|
}
|
|
172
48
|
current.appendChild(canvas);
|
|
173
|
-
const loopWidth = (0,
|
|
49
|
+
const loopWidth = (0, timeline_utils_1.getLoopDisplayWidth)({
|
|
174
50
|
visualizationWidth: naturalWidth,
|
|
175
51
|
loopDisplay,
|
|
176
52
|
});
|
|
177
|
-
const shouldRepeatVideo = (0,
|
|
53
|
+
const shouldRepeatVideo = (0, timeline_utils_1.shouldTileLoopDisplay)(loopDisplay);
|
|
178
54
|
const targetCanvas = shouldRepeatVideo
|
|
179
55
|
? document.createElement('canvas')
|
|
180
56
|
: canvas;
|
|
@@ -211,20 +87,23 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
211
87
|
const toSeconds = fromSeconds + (visibleDurationInFrames * playbackRate) / fps;
|
|
212
88
|
const targetWidth = shouldRepeatVideo ? targetCanvas.width : naturalWidth;
|
|
213
89
|
if (aspectRatio.current !== null) {
|
|
214
|
-
ensureSlots({
|
|
90
|
+
(0, timeline_utils_1.ensureSlots)({
|
|
215
91
|
filledSlots,
|
|
216
92
|
naturalWidth: targetWidth,
|
|
217
93
|
fromSeconds,
|
|
218
94
|
toSeconds,
|
|
219
95
|
aspectRatio: aspectRatio.current,
|
|
96
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
220
97
|
});
|
|
221
|
-
fillWithCachedFrames({
|
|
98
|
+
(0, timeline_utils_1.fillWithCachedFrames)({
|
|
222
99
|
ctx: targetCtx,
|
|
223
100
|
naturalWidth: targetWidth,
|
|
224
101
|
filledSlots,
|
|
225
102
|
src,
|
|
226
103
|
segmentDuration: toSeconds - fromSeconds,
|
|
227
104
|
fromSeconds,
|
|
105
|
+
devicePixelRatio: window.devicePixelRatio,
|
|
106
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
228
107
|
});
|
|
229
108
|
repeatTarget();
|
|
230
109
|
const unfilled = Array.from(filledSlots.keys()).filter((timestamp) => !filledSlots.get(timestamp));
|
|
@@ -235,18 +114,19 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
235
114
|
};
|
|
236
115
|
}
|
|
237
116
|
}
|
|
238
|
-
(0,
|
|
117
|
+
(0, timeline_utils_1.extractFrames)({
|
|
239
118
|
timestampsInSeconds: ({ track, }) => {
|
|
240
119
|
aspectRatio.current = track.width / track.height;
|
|
241
|
-
|
|
242
|
-
ensureSlots({
|
|
120
|
+
timeline_utils_1.aspectRatioCache.set(src, aspectRatio.current);
|
|
121
|
+
(0, timeline_utils_1.ensureSlots)({
|
|
243
122
|
filledSlots,
|
|
244
123
|
fromSeconds,
|
|
245
124
|
toSeconds,
|
|
246
125
|
naturalWidth: targetWidth,
|
|
247
126
|
aspectRatio: aspectRatio.current,
|
|
127
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
248
128
|
});
|
|
249
|
-
return Array.from(filledSlots.keys()).map((timestamp) => timestamp / WEBCODECS_TIMESCALE);
|
|
129
|
+
return Array.from(filledSlots.keys()).map((timestamp) => timestamp / timeline_utils_1.WEBCODECS_TIMESCALE);
|
|
250
130
|
},
|
|
251
131
|
src,
|
|
252
132
|
onVideoSample: (sample) => {
|
|
@@ -254,7 +134,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
254
134
|
try {
|
|
255
135
|
frame = sample.toVideoFrame();
|
|
256
136
|
const scale = (FILMSTRIP_HEIGHT / frame.displayHeight) * window.devicePixelRatio;
|
|
257
|
-
const transformed = (0,
|
|
137
|
+
const transformed = (0, timeline_utils_1.resizeVideoFrame)({
|
|
258
138
|
frame,
|
|
259
139
|
scale,
|
|
260
140
|
});
|
|
@@ -262,25 +142,28 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
262
142
|
frame.close();
|
|
263
143
|
}
|
|
264
144
|
frame = undefined;
|
|
265
|
-
const databaseKey = (0,
|
|
266
|
-
(0,
|
|
145
|
+
const databaseKey = (0, timeline_utils_1.makeFrameDatabaseKey)(src, transformed.timestamp);
|
|
146
|
+
(0, timeline_utils_1.addFrameToCache)(databaseKey, transformed);
|
|
267
147
|
if (aspectRatio.current === null) {
|
|
268
148
|
throw new Error('Aspect ratio is not set');
|
|
269
149
|
}
|
|
270
|
-
ensureSlots({
|
|
150
|
+
(0, timeline_utils_1.ensureSlots)({
|
|
271
151
|
filledSlots,
|
|
272
152
|
fromSeconds,
|
|
273
153
|
toSeconds,
|
|
274
154
|
naturalWidth: targetWidth,
|
|
275
155
|
aspectRatio: aspectRatio.current,
|
|
156
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
276
157
|
});
|
|
277
|
-
fillFrameWhereItFits({
|
|
158
|
+
(0, timeline_utils_1.fillFrameWhereItFits)({
|
|
278
159
|
ctx: targetCtx,
|
|
279
160
|
filledSlots,
|
|
280
161
|
visualizationWidth: targetWidth,
|
|
281
162
|
frame: transformed,
|
|
282
163
|
segmentDuration: toSeconds - fromSeconds,
|
|
283
164
|
fromSeconds,
|
|
165
|
+
devicePixelRatio: window.devicePixelRatio,
|
|
166
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
284
167
|
});
|
|
285
168
|
repeatTarget();
|
|
286
169
|
}
|
|
@@ -300,13 +183,15 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
300
183
|
if (controller.signal.aborted) {
|
|
301
184
|
return;
|
|
302
185
|
}
|
|
303
|
-
fillWithCachedFrames({
|
|
186
|
+
(0, timeline_utils_1.fillWithCachedFrames)({
|
|
304
187
|
ctx: targetCtx,
|
|
305
188
|
naturalWidth: targetWidth,
|
|
306
189
|
filledSlots,
|
|
307
190
|
src,
|
|
308
191
|
segmentDuration: toSeconds - fromSeconds,
|
|
309
192
|
fromSeconds,
|
|
193
|
+
devicePixelRatio: window.devicePixelRatio,
|
|
194
|
+
frameHeight: FILMSTRIP_HEIGHT,
|
|
310
195
|
});
|
|
311
196
|
repeatTarget();
|
|
312
197
|
})
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import type { EventSourceEvent, SequenceNodePath } from '@remotion/studio-shared';
|
|
2
|
-
import { type CanUpdateSequencePropStatus } from 'remotion';
|
|
3
1
|
import type { SequenceSchema } from 'remotion';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
type SubscribeToEvent = (type: EventSourceEvent['type'], listener: (event: EventSourceEvent) => void) => () => void;
|
|
10
|
-
export declare const acquireSequencePropsSubscription: ({ clientId, fileName, line, column, schema, subscribeToEvent, onChange, }: {
|
|
11
|
-
clientId: string;
|
|
2
|
+
import { callApi } from '../call-api';
|
|
3
|
+
type SubscribeResult = Awaited<ReturnType<typeof callApi<'/api/subscribe-to-sequence-props'>>>;
|
|
4
|
+
type ApplyResult = (result: SubscribeResult) => void;
|
|
5
|
+
export declare const acquireSequencePropsSubscription: ({ fileName, line, column, schema, clientId, applyOnce, applyEach, }: {
|
|
12
6
|
fileName: string;
|
|
13
7
|
line: number;
|
|
14
8
|
column: number;
|
|
15
9
|
schema: SequenceSchema;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
clientId: string;
|
|
11
|
+
applyOnce: ApplyResult;
|
|
12
|
+
applyEach: ApplyResult;
|
|
13
|
+
}) => {
|
|
14
|
+
release: () => void;
|
|
15
|
+
};
|
|
19
16
|
export {};
|
|
@@ -3,149 +3,82 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.acquireSequencePropsSubscription = void 0;
|
|
4
4
|
const remotion_1 = require("remotion");
|
|
5
5
|
const call_api_1 = require("../call-api");
|
|
6
|
-
const
|
|
7
|
-
nodePath: null,
|
|
8
|
-
jsxInMapCallback: false,
|
|
9
|
-
props: null,
|
|
10
|
-
};
|
|
6
|
+
const makeKey = (fileName, line, column) => `${fileName}\0${line}\0${column}`;
|
|
11
7
|
const entries = new Map();
|
|
12
|
-
|
|
13
|
-
const makeKey = (fileName, line, column) => `${fileName}|${line}|${column}`;
|
|
14
|
-
const nodePathsEqual = (a, b) => {
|
|
15
|
-
if (!a || !b) {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
19
|
-
};
|
|
20
|
-
const notify = (entry) => {
|
|
21
|
-
for (const listener of entry.listeners) {
|
|
22
|
-
listener(entry.snapshot);
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const handleEvent = (event) => {
|
|
26
|
-
if (event.type !== 'sequence-props-updated') {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
for (const entry of entries.values()) {
|
|
30
|
-
if (entry.fileName !== event.fileName) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
if (!nodePathsEqual(entry.snapshot.nodePath, event.nodePath)) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (event.result.canUpdate) {
|
|
37
|
-
entry.snapshot = {
|
|
38
|
-
nodePath: entry.snapshot.nodePath,
|
|
39
|
-
jsxInMapCallback: event.result.jsxInMapCallback,
|
|
40
|
-
props: event.result.props,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
entry.snapshot = {
|
|
45
|
-
nodePath: entry.snapshot.nodePath,
|
|
46
|
-
jsxInMapCallback: false,
|
|
47
|
-
props: null,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
notify(entry);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
const ensureGlobalListener = (subscribeToEvent) => {
|
|
54
|
-
if (globalUnsubscribe) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
globalUnsubscribe = subscribeToEvent('sequence-props-updated', handleEvent);
|
|
58
|
-
};
|
|
59
|
-
const teardownGlobalListenerIfEmpty = () => {
|
|
60
|
-
if (entries.size > 0) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (globalUnsubscribe) {
|
|
64
|
-
globalUnsubscribe();
|
|
65
|
-
globalUnsubscribe = null;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
const fireUnsubscribe = (fileName, nodePath, clientId) => {
|
|
69
|
-
(0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
|
|
70
|
-
fileName,
|
|
71
|
-
nodePath,
|
|
72
|
-
clientId,
|
|
73
|
-
}).catch(() => {
|
|
74
|
-
// Ignore unsubscribe errors
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
const acquireSequencePropsSubscription = ({ clientId, fileName, line, column, schema, subscribeToEvent, onChange, }) => {
|
|
8
|
+
const acquireSequencePropsSubscription = ({ fileName, line, column, schema, clientId, applyOnce, applyEach, }) => {
|
|
78
9
|
const key = makeKey(fileName, line, column);
|
|
79
10
|
let entry = entries.get(key);
|
|
80
11
|
if (!entry) {
|
|
81
|
-
const
|
|
82
|
-
clientId,
|
|
83
|
-
fileName,
|
|
84
|
-
refCount: 0,
|
|
85
|
-
snapshot: INITIAL_SNAPSHOT,
|
|
86
|
-
listeners: new Set(),
|
|
87
|
-
tornDown: false,
|
|
88
|
-
};
|
|
89
|
-
entries.set(key, newEntry);
|
|
90
|
-
ensureGlobalListener(subscribeToEvent);
|
|
91
|
-
(0, call_api_1.callApi)('/api/subscribe-to-sequence-props', {
|
|
12
|
+
const promise = (0, call_api_1.callApi)('/api/subscribe-to-sequence-props', {
|
|
92
13
|
fileName,
|
|
93
14
|
line,
|
|
94
15
|
column,
|
|
95
16
|
schema,
|
|
96
17
|
clientId,
|
|
97
|
-
})
|
|
18
|
+
});
|
|
19
|
+
const created = {
|
|
20
|
+
refCount: 0,
|
|
21
|
+
promise,
|
|
22
|
+
fileName,
|
|
23
|
+
clientId,
|
|
24
|
+
applyOnce,
|
|
25
|
+
};
|
|
26
|
+
entries.set(key, created);
|
|
27
|
+
entry = created;
|
|
28
|
+
promise
|
|
98
29
|
.then((result) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
fireUnsubscribe(fileName, result.nodePath, clientId);
|
|
102
|
-
}
|
|
30
|
+
const current = entries.get(key);
|
|
31
|
+
if (current !== created || !current.applyOnce) {
|
|
103
32
|
return;
|
|
104
33
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
jsxInMapCallback: result.jsxInMapCallback,
|
|
109
|
-
props: result.props,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
newEntry.snapshot = INITIAL_SNAPSHOT;
|
|
114
|
-
}
|
|
115
|
-
notify(newEntry);
|
|
34
|
+
const cb = current.applyOnce;
|
|
35
|
+
current.applyOnce = null;
|
|
36
|
+
cb(result);
|
|
116
37
|
})
|
|
117
38
|
.catch((err) => {
|
|
118
|
-
|
|
39
|
+
const current = entries.get(key);
|
|
40
|
+
if (current !== created) {
|
|
119
41
|
return;
|
|
120
42
|
}
|
|
43
|
+
current.applyOnce = null;
|
|
121
44
|
remotion_1.Internals.Log.error(err);
|
|
122
|
-
newEntry.snapshot = INITIAL_SNAPSHOT;
|
|
123
|
-
notify(newEntry);
|
|
124
45
|
});
|
|
125
|
-
entry = newEntry;
|
|
126
46
|
}
|
|
127
|
-
entry.refCount
|
|
128
|
-
entry
|
|
129
|
-
|
|
47
|
+
entry.refCount++;
|
|
48
|
+
const acquired = entry;
|
|
49
|
+
acquired.promise.then(applyEach).catch(() => {
|
|
50
|
+
// Error already logged by the first acquirer.
|
|
51
|
+
});
|
|
130
52
|
let released = false;
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
53
|
+
return {
|
|
54
|
+
release: () => {
|
|
55
|
+
if (released) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
released = true;
|
|
59
|
+
acquired.refCount--;
|
|
60
|
+
if (acquired.refCount > 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (entries.get(key) === acquired) {
|
|
64
|
+
entries.delete(key);
|
|
65
|
+
}
|
|
66
|
+
acquired.promise
|
|
67
|
+
.then((result) => {
|
|
68
|
+
if (!result.success) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
return (0, call_api_1.callApi)('/api/unsubscribe-from-sequence-props', {
|
|
72
|
+
fileName: acquired.fileName,
|
|
73
|
+
nodePath: result.nodePath,
|
|
74
|
+
clientId: acquired.clientId,
|
|
75
|
+
});
|
|
76
|
+
})
|
|
77
|
+
.catch(() => {
|
|
78
|
+
// Ignore — either the subscribe failed (nothing to clean up) or
|
|
79
|
+
// the unsubscribe failed (server-side TTL will handle it).
|
|
80
|
+
});
|
|
81
|
+
},
|
|
149
82
|
};
|
|
150
83
|
};
|
|
151
84
|
exports.acquireSequencePropsSubscription = acquireSequencePropsSubscription;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { TSequence } from 'remotion';
|
|
1
|
+
import type { SequenceSchema } from 'remotion';
|
|
3
2
|
import type { OriginalPosition } from '../../error-overlay/react-overlay/utils/get-source-map';
|
|
4
|
-
export declare const useSequencePropsSubscription: (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export declare const useSequencePropsSubscription: ({ originalLocation, overrideId, schema, }: {
|
|
4
|
+
overrideId: string;
|
|
5
|
+
schema: SequenceSchema;
|
|
6
|
+
originalLocation: OriginalPosition | null;
|
|
7
|
+
}) => void;
|