@remotion/web-renderer 4.0.398 → 4.0.400

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 (123) hide show
  1. package/dist/compose.d.ts +21 -5
  2. package/dist/create-scaffold.d.ts +4 -5
  3. package/dist/drawing/border-radius.d.ts +4 -2
  4. package/dist/drawing/calculate-object-fit.d.ts +40 -0
  5. package/dist/drawing/calculate-transforms.d.ts +1 -1
  6. package/dist/drawing/draw-background.d.ts +30 -0
  7. package/dist/drawing/draw-box-shadow.d.ts +2 -3
  8. package/dist/drawing/draw-element.d.ts +21 -3
  9. package/dist/drawing/drawn-fn.d.ts +1 -1
  10. package/dist/drawing/fit-svg-into-its-dimensions.d.ts +12 -0
  11. package/dist/drawing/get-clipped-background.d.ts +23 -0
  12. package/dist/drawing/get-padding-box.d.ts +1 -0
  13. package/dist/drawing/handle-3d-transform.d.ts +20 -2
  14. package/dist/drawing/overflow.d.ts +3 -1
  15. package/dist/drawing/parse-linear-gradient.d.ts +3 -1
  16. package/dist/drawing/precompose.d.ts +19 -4
  17. package/dist/drawing/process-node.d.ts +19 -4
  18. package/dist/drawing/text/draw-text.d.ts +3 -3
  19. package/dist/drawing/text/handle-text-node.d.ts +21 -5
  20. package/dist/drawing/transform-in-3d.d.ts +20 -2
  21. package/dist/drawing/transform-rect-with-matrix.d.ts +1 -1
  22. package/dist/esm/index.mjs +1158 -517
  23. package/dist/index.d.ts +1 -0
  24. package/dist/internal-state.d.ts +27 -0
  25. package/dist/mediabunny-mappings.d.ts +2 -2
  26. package/dist/props-if-has-props.d.ts +1 -2
  27. package/dist/render-still-on-web.d.ts +18 -2
  28. package/dist/take-screenshot.d.ts +38 -6
  29. package/dist/tree-walker-cleanup-after-children.d.ts +5 -0
  30. package/dist/wait-for-ready.d.ts +21 -3
  31. package/package.json +12 -10
  32. package/dist/add-sample.js +0 -20
  33. package/dist/artifact.js +0 -56
  34. package/dist/audio.js +0 -42
  35. package/dist/border-radius.d.ts +0 -31
  36. package/dist/border-radius.js +0 -152
  37. package/dist/calculate-transforms.d.ts +0 -11
  38. package/dist/calculate-transforms.js +0 -91
  39. package/dist/can-use-webfs-target.js +0 -19
  40. package/dist/composable.d.ts +0 -4
  41. package/dist/composable.js +0 -1
  42. package/dist/compose-canvas.d.ts +0 -1
  43. package/dist/compose-canvas.js +0 -36
  44. package/dist/compose-svg.d.ts +0 -1
  45. package/dist/compose-svg.js +0 -34
  46. package/dist/compose.js +0 -86
  47. package/dist/create-scaffold.js +0 -104
  48. package/dist/drawing/border-radius.js +0 -130
  49. package/dist/drawing/calculate-transforms.js +0 -127
  50. package/dist/drawing/canvas-offset-from-rect.d.ts +0 -8
  51. package/dist/drawing/canvas-offset-from-rect.js +0 -12
  52. package/dist/drawing/clamp-rect-to-parent-bounds.js +0 -18
  53. package/dist/drawing/compose-canvas.d.ts +0 -1
  54. package/dist/drawing/compose-canvas.js +0 -36
  55. package/dist/drawing/compose-svg.d.ts +0 -1
  56. package/dist/drawing/compose-svg.js +0 -34
  57. package/dist/drawing/compose.d.ts +0 -5
  58. package/dist/drawing/compose.js +0 -6
  59. package/dist/drawing/do-rects-intersect.js +0 -6
  60. package/dist/drawing/draw-border.js +0 -353
  61. package/dist/drawing/draw-box-shadow.js +0 -103
  62. package/dist/drawing/draw-dom-element.js +0 -17
  63. package/dist/drawing/draw-element-to-canvas.d.ts +0 -12
  64. package/dist/drawing/draw-element-to-canvas.js +0 -36
  65. package/dist/drawing/draw-element.js +0 -96
  66. package/dist/drawing/draw-outline.js +0 -93
  67. package/dist/drawing/draw-rounded.js +0 -34
  68. package/dist/drawing/drawn-fn.js +0 -1
  69. package/dist/drawing/get-bounding-box-including-shadow.d.ts +0 -1
  70. package/dist/drawing/get-bounding-box-including-shadow.js +0 -6
  71. package/dist/drawing/get-computed-style-cache.js +0 -1
  72. package/dist/drawing/get-pretransform-rect.js +0 -36
  73. package/dist/drawing/handle-3d-transform.js +0 -25
  74. package/dist/drawing/handle-mask.js +0 -19
  75. package/dist/drawing/has-transform.js +0 -14
  76. package/dist/drawing/mask-image.js +0 -14
  77. package/dist/drawing/opacity.js +0 -7
  78. package/dist/drawing/overflow.js +0 -12
  79. package/dist/drawing/parse-linear-gradient.js +0 -260
  80. package/dist/drawing/parse-transform-origin.js +0 -7
  81. package/dist/drawing/precompose.js +0 -13
  82. package/dist/drawing/process-node.js +0 -116
  83. package/dist/drawing/round-to-expand-rect.js +0 -7
  84. package/dist/drawing/text/apply-text-transform.js +0 -12
  85. package/dist/drawing/text/draw-text.js +0 -47
  86. package/dist/drawing/text/find-line-breaks.text.js +0 -67
  87. package/dist/drawing/text/get-collapsed-text.js +0 -46
  88. package/dist/drawing/text/handle-text-node.js +0 -24
  89. package/dist/drawing/transform-in-3d.js +0 -158
  90. package/dist/drawing/transform-rect-with-matrix.js +0 -19
  91. package/dist/drawing/transform.js +0 -10
  92. package/dist/drawing/turn-svg-into-drawable.js +0 -41
  93. package/dist/find-canvas-elements.d.ts +0 -1
  94. package/dist/find-canvas-elements.js +0 -13
  95. package/dist/find-capturable-elements.d.ts +0 -2
  96. package/dist/find-capturable-elements.js +0 -26
  97. package/dist/frame-range.js +0 -15
  98. package/dist/get-audio-encoding-config.js +0 -18
  99. package/dist/get-biggest-bounding-client-rect.js +0 -43
  100. package/dist/index.js +0 -2
  101. package/dist/internal-state.js +0 -12
  102. package/dist/mediabunny-mappings.js +0 -63
  103. package/dist/opacity.d.ts +0 -4
  104. package/dist/opacity.js +0 -7
  105. package/dist/output-target.js +0 -1
  106. package/dist/parse-transform-origin.d.ts +0 -4
  107. package/dist/parse-transform-origin.js +0 -7
  108. package/dist/props-if-has-props.js +0 -1
  109. package/dist/render-media-on-web.js +0 -297
  110. package/dist/render-operations-queue.js +0 -3
  111. package/dist/render-still-on-web.js +0 -108
  112. package/dist/send-telemetry-event.js +0 -22
  113. package/dist/take-screenshot.js +0 -29
  114. package/dist/throttle-progress.js +0 -43
  115. package/dist/transform.d.ts +0 -4
  116. package/dist/transform.js +0 -6
  117. package/dist/update-time.js +0 -17
  118. package/dist/validate-video-frame.js +0 -34
  119. package/dist/wait-for-ready.js +0 -35
  120. package/dist/walk-tree.js +0 -14
  121. package/dist/web-fs-target.js +0 -41
  122. package/dist/with-resolvers.js +0 -9
  123. /package/dist/{drawing/get-computed-style-cache.d.ts → symbol-dispose.d.ts} +0 -0
@@ -1,43 +0,0 @@
1
- import { parseBoxShadow } from './drawing/draw-box-shadow';
2
- import { parseOutlineOffset, parseOutlineWidth } from './drawing/draw-outline';
3
- import { skipToNextNonDescendant } from './walk-tree';
4
- export const getBiggestBoundingClientRect = (element) => {
5
- const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
6
- let mostLeft = Infinity;
7
- let mostTop = Infinity;
8
- let mostRight = -Infinity;
9
- let mostBottom = -Infinity;
10
- while (true) {
11
- const computedStyle = getComputedStyle(treeWalker.currentNode);
12
- const outlineWidth = parseOutlineWidth(computedStyle.outlineWidth);
13
- const outlineOffset = parseOutlineOffset(computedStyle.outlineOffset);
14
- const rect = treeWalker.currentNode.getBoundingClientRect();
15
- // Calculate box shadow extensions
16
- const shadows = parseBoxShadow(computedStyle.boxShadow);
17
- let shadowLeft = 0;
18
- let shadowRight = 0;
19
- let shadowTop = 0;
20
- let shadowBottom = 0;
21
- for (const shadow of shadows) {
22
- if (!shadow.inset) {
23
- shadowLeft = Math.max(shadowLeft, Math.abs(Math.min(shadow.offsetX, 0)) + shadow.blurRadius);
24
- shadowRight = Math.max(shadowRight, Math.max(shadow.offsetX, 0) + shadow.blurRadius);
25
- shadowTop = Math.max(shadowTop, Math.abs(Math.min(shadow.offsetY, 0)) + shadow.blurRadius);
26
- shadowBottom = Math.max(shadowBottom, Math.max(shadow.offsetY, 0) + shadow.blurRadius);
27
- }
28
- }
29
- mostLeft = Math.min(mostLeft, rect.left - outlineOffset - outlineWidth - shadowLeft);
30
- mostTop = Math.min(mostTop, rect.top - outlineOffset - outlineWidth - shadowTop);
31
- mostRight = Math.max(mostRight, rect.right + outlineOffset + outlineWidth + shadowRight);
32
- mostBottom = Math.max(mostBottom, rect.bottom + outlineOffset + outlineWidth + shadowBottom);
33
- if (computedStyle.overflow === 'hidden') {
34
- if (!skipToNextNonDescendant(treeWalker)) {
35
- break;
36
- }
37
- }
38
- if (!treeWalker.nextNode()) {
39
- break;
40
- }
41
- }
42
- return new DOMRect(mostLeft, mostTop, mostRight - mostLeft, mostBottom - mostTop);
43
- };
package/dist/index.js DELETED
@@ -1,2 +0,0 @@
1
- export { renderMediaOnWeb } from './render-media-on-web';
2
- export { renderStillOnWeb } from './render-still-on-web';
@@ -1,12 +0,0 @@
1
- export const makeInternalState = () => {
2
- let drawnPrecomposedPixels = 0;
3
- let precomposedTextures = 0;
4
- return {
5
- getDrawn3dPixels: () => drawnPrecomposedPixels,
6
- getPrecomposedTiles: () => precomposedTextures,
7
- addPrecompose: ({ canvasWidth, canvasHeight, }) => {
8
- drawnPrecomposedPixels += canvasWidth * canvasHeight;
9
- precomposedTextures++;
10
- },
11
- };
12
- };
@@ -1,63 +0,0 @@
1
- import { Mp4OutputFormat, QUALITY_HIGH, QUALITY_LOW, QUALITY_MEDIUM, QUALITY_VERY_HIGH, QUALITY_VERY_LOW, WebMOutputFormat, } from 'mediabunny';
2
- export const codecToMediabunnyCodec = (codec) => {
3
- switch (codec) {
4
- case 'h264':
5
- return 'avc';
6
- case 'h265':
7
- return 'hevc';
8
- case 'vp8':
9
- return 'vp8';
10
- case 'vp9':
11
- return 'vp9';
12
- case 'av1':
13
- return 'av1';
14
- default:
15
- throw new Error(`Unsupported codec: ${codec}`);
16
- }
17
- };
18
- export const containerToMediabunnyContainer = (container) => {
19
- switch (container) {
20
- case 'mp4':
21
- return new Mp4OutputFormat();
22
- case 'webm':
23
- return new WebMOutputFormat();
24
- default:
25
- throw new Error(`Unsupported container: ${container}`);
26
- }
27
- };
28
- export const getDefaultVideoCodecForContainer = (container) => {
29
- switch (container) {
30
- case 'mp4':
31
- return 'h264';
32
- case 'webm':
33
- return 'vp8';
34
- default:
35
- throw new Error(`Unsupported container: ${container}`);
36
- }
37
- };
38
- export const getQualityForWebRendererQuality = (quality) => {
39
- switch (quality) {
40
- case 'very-low':
41
- return QUALITY_VERY_LOW;
42
- case 'low':
43
- return QUALITY_LOW;
44
- case 'medium':
45
- return QUALITY_MEDIUM;
46
- case 'high':
47
- return QUALITY_HIGH;
48
- case 'very-high':
49
- return QUALITY_VERY_HIGH;
50
- default:
51
- throw new Error(`Unsupported quality: ${quality}`);
52
- }
53
- };
54
- export const getMimeType = (container) => {
55
- switch (container) {
56
- case 'mp4':
57
- return 'video/mp4';
58
- case 'webm':
59
- return 'video/webm';
60
- default:
61
- throw new Error(`Unsupported container: ${container}`);
62
- }
63
- };
package/dist/opacity.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export declare const setOpacity: ({ ctx, opacity, }: {
2
- ctx: OffscreenCanvasRenderingContext2D;
3
- opacity: number;
4
- }) => () => void;
package/dist/opacity.js DELETED
@@ -1,7 +0,0 @@
1
- export const setOpacity = ({ ctx, opacity, }) => {
2
- const previousAlpha = ctx.globalAlpha;
3
- ctx.globalAlpha = opacity;
4
- return () => {
5
- ctx.globalAlpha = previousAlpha;
6
- };
7
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- export declare const parseTransformOrigin: (transformOrigin: string) => {
2
- x: number;
3
- y: number;
4
- } | null;
@@ -1,7 +0,0 @@
1
- export const parseTransformOrigin = (transformOrigin) => {
2
- if (transformOrigin.trim() === '') {
3
- return null;
4
- }
5
- const [x, y] = transformOrigin.split(' ');
6
- return { x: parseFloat(x), y: parseFloat(y) };
7
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,297 +0,0 @@
1
- import { AudioSampleSource, BufferTarget, Output, StreamTarget, VideoSampleSource, } from 'mediabunny';
2
- import { Internals } from 'remotion';
3
- import { addAudioSample, addVideoSampleAndCloseFrame } from './add-sample';
4
- import { handleArtifacts } from './artifact';
5
- import { onlyInlineAudio } from './audio';
6
- import { canUseWebFsWriter } from './can-use-webfs-target';
7
- import { createScaffold } from './create-scaffold';
8
- import { getRealFrameRange } from './frame-range';
9
- import { getDefaultAudioEncodingConfig } from './get-audio-encoding-config';
10
- import { makeInternalState } from './internal-state';
11
- import { codecToMediabunnyCodec, containerToMediabunnyContainer, getDefaultVideoCodecForContainer, getMimeType, getQualityForWebRendererQuality, } from './mediabunny-mappings';
12
- import { onlyOneRenderAtATimeQueue } from './render-operations-queue';
13
- import { sendUsageEvent } from './send-telemetry-event';
14
- import { createFrame } from './take-screenshot';
15
- import { createThrottledProgressCallback } from './throttle-progress';
16
- import { validateVideoFrame } from './validate-video-frame';
17
- import { waitForReady } from './wait-for-ready';
18
- import { cleanupStaleOpfsFiles, createWebFsTarget } from './web-fs-target';
19
- // TODO: More containers
20
- // TODO: Audio
21
- // TODO: Metadata
22
- // TODO: Validating inputs
23
- // TODO: Apply defaultCodec
24
- const internalRenderMediaOnWeb = async ({ composition, inputProps, delayRenderTimeoutInMilliseconds, logLevel, mediaCacheSizeInBytes, schema, videoCodec: codec, container, signal, onProgress, hardwareAcceleration, keyframeIntervalInSeconds, videoBitrate, frameRange, transparent, onArtifact, onFrame, outputTarget: userDesiredOutputTarget, licenseKey, muted, }) => {
25
- var _a, _b, _c, _d, _e, _f, _g;
26
- const outputTarget = userDesiredOutputTarget === null
27
- ? (await canUseWebFsWriter())
28
- ? 'web-fs'
29
- : 'arraybuffer'
30
- : userDesiredOutputTarget;
31
- if (outputTarget === 'web-fs') {
32
- await cleanupStaleOpfsFiles();
33
- }
34
- const cleanupFns = [];
35
- const format = containerToMediabunnyContainer(container);
36
- if (codec &&
37
- !format.getSupportedCodecs().includes(codecToMediabunnyCodec(codec))) {
38
- return Promise.reject(new Error(`Codec ${codec} is not supported for container ${container}`));
39
- }
40
- const resolved = await Internals.resolveVideoConfig({
41
- calculateMetadata: (_a = composition.calculateMetadata) !== null && _a !== void 0 ? _a : null,
42
- signal: signal !== null && signal !== void 0 ? signal : new AbortController().signal,
43
- defaultProps: (_b = composition.defaultProps) !== null && _b !== void 0 ? _b : {},
44
- inputProps: inputProps !== null && inputProps !== void 0 ? inputProps : {},
45
- compositionId: composition.id,
46
- compositionDurationInFrames: (_c = composition.durationInFrames) !== null && _c !== void 0 ? _c : null,
47
- compositionFps: (_d = composition.fps) !== null && _d !== void 0 ? _d : null,
48
- compositionHeight: (_e = composition.height) !== null && _e !== void 0 ? _e : null,
49
- compositionWidth: (_f = composition.width) !== null && _f !== void 0 ? _f : null,
50
- });
51
- const realFrameRange = getRealFrameRange(resolved.durationInFrames, frameRange);
52
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
53
- return Promise.reject(new Error('renderMediaOnWeb() was cancelled'));
54
- }
55
- const { delayRenderScope, div, cleanupScaffold, timeUpdater, collectAssets } = await createScaffold({
56
- width: resolved.width,
57
- height: resolved.height,
58
- fps: resolved.fps,
59
- durationInFrames: resolved.durationInFrames,
60
- Component: composition.component,
61
- resolvedProps: resolved.props,
62
- id: resolved.id,
63
- delayRenderTimeoutInMilliseconds,
64
- logLevel,
65
- mediaCacheSizeInBytes,
66
- schema: schema !== null && schema !== void 0 ? schema : null,
67
- audioEnabled: !muted,
68
- videoEnabled: true,
69
- initialFrame: 0,
70
- defaultCodec: resolved.defaultCodec,
71
- defaultOutName: resolved.defaultOutName,
72
- });
73
- const internalState = makeInternalState();
74
- const artifactsHandler = handleArtifacts();
75
- cleanupFns.push(() => {
76
- cleanupScaffold();
77
- });
78
- const webFsTarget = outputTarget === 'web-fs' ? await createWebFsTarget() : null;
79
- const target = webFsTarget
80
- ? new StreamTarget(webFsTarget.stream)
81
- : new BufferTarget();
82
- const output = new Output({
83
- format,
84
- target,
85
- });
86
- try {
87
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
88
- throw new Error('renderMediaOnWeb() was cancelled');
89
- }
90
- await waitForReady({
91
- timeoutInMilliseconds: delayRenderTimeoutInMilliseconds,
92
- scope: delayRenderScope,
93
- signal,
94
- apiName: 'renderMediaOnWeb',
95
- });
96
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
97
- throw new Error('renderMediaOnWeb() was cancelled');
98
- }
99
- cleanupFns.push(() => {
100
- if (output.state === 'finalized' || output.state === 'canceled') {
101
- return;
102
- }
103
- output.cancel();
104
- });
105
- const videoSampleSource = new VideoSampleSource({
106
- codec: codecToMediabunnyCodec(codec),
107
- bitrate: typeof videoBitrate === 'number'
108
- ? videoBitrate
109
- : getQualityForWebRendererQuality(videoBitrate),
110
- sizeChangeBehavior: 'deny',
111
- hardwareAcceleration,
112
- latencyMode: 'quality',
113
- keyFrameInterval: keyframeIntervalInSeconds,
114
- alpha: transparent ? 'keep' : 'discard',
115
- });
116
- cleanupFns.push(() => {
117
- videoSampleSource.close();
118
- });
119
- output.addVideoTrack(videoSampleSource);
120
- // TODO: Should be able to customize
121
- let audioSampleSource = null;
122
- if (!muted) {
123
- const defaultAudioEncodingConfig = await getDefaultAudioEncodingConfig();
124
- if (!defaultAudioEncodingConfig) {
125
- return Promise.reject(new Error('No default audio encoding config found'));
126
- }
127
- audioSampleSource = new AudioSampleSource(defaultAudioEncodingConfig);
128
- cleanupFns.push(() => {
129
- audioSampleSource === null || audioSampleSource === void 0 ? void 0 : audioSampleSource.close();
130
- });
131
- output.addAudioTrack(audioSampleSource);
132
- }
133
- await output.start();
134
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
135
- throw new Error('renderMediaOnWeb() was cancelled');
136
- }
137
- const progress = {
138
- renderedFrames: 0,
139
- encodedFrames: 0,
140
- };
141
- const throttledOnProgress = createThrottledProgressCallback(onProgress);
142
- for (let frame = realFrameRange[0]; frame <= realFrameRange[1]; frame++) {
143
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
144
- throw new Error('renderMediaOnWeb() was cancelled');
145
- }
146
- (_g = timeUpdater.current) === null || _g === void 0 ? void 0 : _g.update(frame);
147
- await waitForReady({
148
- timeoutInMilliseconds: delayRenderTimeoutInMilliseconds,
149
- scope: delayRenderScope,
150
- signal,
151
- apiName: 'renderMediaOnWeb',
152
- });
153
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
154
- throw new Error('renderMediaOnWeb() was cancelled');
155
- }
156
- const imageData = await createFrame({
157
- div,
158
- width: resolved.width,
159
- height: resolved.height,
160
- logLevel,
161
- internalState,
162
- });
163
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
164
- throw new Error('renderMediaOnWeb() was cancelled');
165
- }
166
- const assets = collectAssets.current.collectAssets();
167
- if (onArtifact) {
168
- await artifactsHandler.handle({
169
- imageData,
170
- frame,
171
- assets,
172
- onArtifact,
173
- });
174
- }
175
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
176
- throw new Error('renderMediaOnWeb() was cancelled');
177
- }
178
- const audio = muted
179
- ? null
180
- : onlyInlineAudio({ assets, fps: resolved.fps, frame });
181
- const timestamp = Math.round(((frame - realFrameRange[0]) / resolved.fps) * 1000000);
182
- const videoFrame = new VideoFrame(imageData, {
183
- timestamp,
184
- });
185
- progress.renderedFrames++;
186
- throttledOnProgress === null || throttledOnProgress === void 0 ? void 0 : throttledOnProgress({ ...progress });
187
- // Process frame through onFrame callback if provided
188
- let frameToEncode = videoFrame;
189
- if (onFrame) {
190
- const returnedFrame = await onFrame(videoFrame);
191
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
192
- throw new Error('renderMediaOnWeb() was cancelled');
193
- }
194
- frameToEncode = validateVideoFrame({
195
- originalFrame: videoFrame,
196
- returnedFrame,
197
- expectedWidth: resolved.width,
198
- expectedHeight: resolved.height,
199
- expectedTimestamp: timestamp,
200
- });
201
- }
202
- await Promise.all([
203
- addVideoSampleAndCloseFrame(frameToEncode, videoSampleSource),
204
- audio && audioSampleSource
205
- ? addAudioSample(audio, audioSampleSource)
206
- : Promise.resolve(),
207
- ]);
208
- progress.encodedFrames++;
209
- throttledOnProgress === null || throttledOnProgress === void 0 ? void 0 : throttledOnProgress({ ...progress });
210
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
211
- throw new Error('renderMediaOnWeb() was cancelled');
212
- }
213
- }
214
- // Call progress one final time to ensure final state is reported
215
- onProgress === null || onProgress === void 0 ? void 0 : onProgress({ ...progress });
216
- videoSampleSource.close();
217
- audioSampleSource === null || audioSampleSource === void 0 ? void 0 : audioSampleSource.close();
218
- await output.finalize();
219
- const mimeType = getMimeType(container);
220
- if (webFsTarget) {
221
- sendUsageEvent({
222
- licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
223
- succeeded: true,
224
- apiName: 'renderMediaOnWeb',
225
- });
226
- await webFsTarget.close();
227
- return {
228
- getBlob: () => {
229
- return webFsTarget.getBlob();
230
- },
231
- internalState,
232
- };
233
- }
234
- if (!(target instanceof BufferTarget)) {
235
- throw new Error('Expected target to be a BufferTarget');
236
- }
237
- sendUsageEvent({
238
- licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
239
- succeeded: true,
240
- apiName: 'renderMediaOnWeb',
241
- });
242
- return {
243
- getBlob: () => {
244
- if (!target.buffer) {
245
- throw new Error('The resulting buffer is empty');
246
- }
247
- return Promise.resolve(new Blob([target.buffer], { type: mimeType }));
248
- },
249
- internalState,
250
- };
251
- }
252
- catch (err) {
253
- sendUsageEvent({
254
- succeeded: false,
255
- licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
256
- apiName: 'renderMediaOnWeb',
257
- }).catch((err2) => {
258
- Internals.Log.error({ logLevel: 'error', tag: 'web-renderer' }, 'Failed to send usage event', err2);
259
- });
260
- throw err;
261
- }
262
- finally {
263
- cleanupFns.forEach((fn) => fn());
264
- }
265
- };
266
- export const renderMediaOnWeb = (options) => {
267
- var _a, _b;
268
- const container = (_a = options.container) !== null && _a !== void 0 ? _a : 'mp4';
269
- const codec = (_b = options.videoCodec) !== null && _b !== void 0 ? _b : getDefaultVideoCodecForContainer(container);
270
- onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref
271
- .catch(() => Promise.resolve())
272
- .then(() => {
273
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
274
- return internalRenderMediaOnWeb({
275
- ...options,
276
- delayRenderTimeoutInMilliseconds: (_a = options.delayRenderTimeoutInMilliseconds) !== null && _a !== void 0 ? _a : 30000,
277
- logLevel: (_c = (_b = options.logLevel) !== null && _b !== void 0 ? _b : window.remotion_logLevel) !== null && _c !== void 0 ? _c : 'info',
278
- schema: (_d = options.schema) !== null && _d !== void 0 ? _d : undefined,
279
- mediaCacheSizeInBytes: (_e = options.mediaCacheSizeInBytes) !== null && _e !== void 0 ? _e : null,
280
- videoCodec: codec,
281
- container,
282
- signal: (_f = options.signal) !== null && _f !== void 0 ? _f : null,
283
- onProgress: (_g = options.onProgress) !== null && _g !== void 0 ? _g : null,
284
- hardwareAcceleration: (_h = options.hardwareAcceleration) !== null && _h !== void 0 ? _h : 'no-preference',
285
- keyframeIntervalInSeconds: (_j = options.keyframeIntervalInSeconds) !== null && _j !== void 0 ? _j : 5,
286
- videoBitrate: (_k = options.videoBitrate) !== null && _k !== void 0 ? _k : 'medium',
287
- frameRange: (_l = options.frameRange) !== null && _l !== void 0 ? _l : null,
288
- transparent: (_m = options.transparent) !== null && _m !== void 0 ? _m : false,
289
- onArtifact: (_o = options.onArtifact) !== null && _o !== void 0 ? _o : null,
290
- onFrame: (_p = options.onFrame) !== null && _p !== void 0 ? _p : null,
291
- outputTarget: (_q = options.outputTarget) !== null && _q !== void 0 ? _q : null,
292
- licenseKey: (_r = options.licenseKey) !== null && _r !== void 0 ? _r : undefined,
293
- muted: (_s = options.muted) !== null && _s !== void 0 ? _s : false,
294
- });
295
- });
296
- return onlyOneRenderAtATimeQueue.ref;
297
- };
@@ -1,3 +0,0 @@
1
- export const onlyOneRenderAtATimeQueue = {
2
- ref: Promise.resolve(),
3
- };
@@ -1,108 +0,0 @@
1
- import { Internals, } from 'remotion';
2
- import { handleArtifacts } from './artifact';
3
- import { createScaffold } from './create-scaffold';
4
- import { makeInternalState } from './internal-state';
5
- import { onlyOneRenderAtATimeQueue } from './render-operations-queue';
6
- import { sendUsageEvent } from './send-telemetry-event';
7
- import { takeScreenshot } from './take-screenshot';
8
- import { waitForReady } from './wait-for-ready';
9
- async function internalRenderStillOnWeb({ frame, delayRenderTimeoutInMilliseconds, logLevel, inputProps, schema, imageFormat, mediaCacheSizeInBytes, composition, signal, onArtifact, licenseKey, }) {
10
- var _a, _b, _c, _d, _e, _f;
11
- const resolved = await Internals.resolveVideoConfig({
12
- calculateMetadata: (_a = composition.calculateMetadata) !== null && _a !== void 0 ? _a : null,
13
- signal: signal !== null && signal !== void 0 ? signal : new AbortController().signal,
14
- defaultProps: (_b = composition.defaultProps) !== null && _b !== void 0 ? _b : {},
15
- inputProps: inputProps !== null && inputProps !== void 0 ? inputProps : {},
16
- compositionId: composition.id,
17
- compositionDurationInFrames: (_c = composition.durationInFrames) !== null && _c !== void 0 ? _c : null,
18
- compositionFps: (_d = composition.fps) !== null && _d !== void 0 ? _d : null,
19
- compositionHeight: (_e = composition.height) !== null && _e !== void 0 ? _e : null,
20
- compositionWidth: (_f = composition.width) !== null && _f !== void 0 ? _f : null,
21
- });
22
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
23
- return Promise.reject(new Error('renderStillOnWeb() was cancelled'));
24
- }
25
- const internalState = makeInternalState();
26
- const { delayRenderScope, div, cleanupScaffold, collectAssets } = await createScaffold({
27
- width: resolved.width,
28
- height: resolved.height,
29
- delayRenderTimeoutInMilliseconds,
30
- logLevel,
31
- resolvedProps: resolved.props,
32
- id: resolved.id,
33
- mediaCacheSizeInBytes,
34
- audioEnabled: false,
35
- Component: composition.component,
36
- videoEnabled: true,
37
- durationInFrames: resolved.durationInFrames,
38
- fps: resolved.fps,
39
- schema: schema !== null && schema !== void 0 ? schema : null,
40
- initialFrame: frame,
41
- defaultCodec: resolved.defaultCodec,
42
- defaultOutName: resolved.defaultOutName,
43
- });
44
- const artifactsHandler = handleArtifacts();
45
- try {
46
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
47
- throw new Error('renderStillOnWeb() was cancelled');
48
- }
49
- await waitForReady({
50
- timeoutInMilliseconds: delayRenderTimeoutInMilliseconds,
51
- scope: delayRenderScope,
52
- signal,
53
- apiName: 'renderStillOnWeb',
54
- });
55
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
56
- throw new Error('renderStillOnWeb() was cancelled');
57
- }
58
- const imageData = await takeScreenshot({
59
- div,
60
- width: resolved.width,
61
- height: resolved.height,
62
- imageFormat,
63
- logLevel,
64
- internalState,
65
- });
66
- const assets = collectAssets.current.collectAssets();
67
- if (onArtifact) {
68
- await artifactsHandler.handle({ imageData, frame, assets, onArtifact });
69
- }
70
- sendUsageEvent({
71
- licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
72
- succeeded: true,
73
- apiName: 'renderStillOnWeb',
74
- });
75
- return { blob: imageData, internalState };
76
- }
77
- catch (err) {
78
- sendUsageEvent({
79
- succeeded: false,
80
- licenseKey: licenseKey !== null && licenseKey !== void 0 ? licenseKey : null,
81
- apiName: 'renderStillOnWeb',
82
- }).catch((err2) => {
83
- Internals.Log.error({ logLevel: 'error', tag: 'web-renderer' }, 'Failed to send usage event', err2);
84
- });
85
- throw err;
86
- }
87
- finally {
88
- cleanupScaffold();
89
- }
90
- }
91
- export const renderStillOnWeb = (options) => {
92
- onlyOneRenderAtATimeQueue.ref = onlyOneRenderAtATimeQueue.ref
93
- .catch(() => Promise.resolve())
94
- .then(() => {
95
- var _a, _b, _c, _d, _e, _f, _g, _h;
96
- return internalRenderStillOnWeb({
97
- ...options,
98
- delayRenderTimeoutInMilliseconds: (_a = options.delayRenderTimeoutInMilliseconds) !== null && _a !== void 0 ? _a : 30000,
99
- logLevel: (_c = (_b = options.logLevel) !== null && _b !== void 0 ? _b : window.remotion_logLevel) !== null && _c !== void 0 ? _c : 'info',
100
- schema: (_d = options.schema) !== null && _d !== void 0 ? _d : undefined,
101
- mediaCacheSizeInBytes: (_e = options.mediaCacheSizeInBytes) !== null && _e !== void 0 ? _e : null,
102
- signal: (_f = options.signal) !== null && _f !== void 0 ? _f : null,
103
- onArtifact: (_g = options.onArtifact) !== null && _g !== void 0 ? _g : null,
104
- licenseKey: (_h = options.licenseKey) !== null && _h !== void 0 ? _h : undefined,
105
- });
106
- });
107
- return onlyOneRenderAtATimeQueue.ref;
108
- };
@@ -1,22 +0,0 @@
1
- import { registerUsageEvent } from '@remotion/licensing';
2
- import { Internals } from 'remotion';
3
- export const sendUsageEvent = async ({ licenseKey, succeeded, apiName, }) => {
4
- var _a;
5
- const host = typeof window === 'undefined'
6
- ? null
7
- : typeof window.location === 'undefined'
8
- ? null
9
- : ((_a = window.location.origin) !== null && _a !== void 0 ? _a : null);
10
- if (host === null) {
11
- return;
12
- }
13
- if (licenseKey === null) {
14
- Internals.Log.warn({ logLevel: 'warn', tag: 'web-renderer' }, `Pass "licenseKey" to ${apiName}(). If you qualify for the Free License (https://remotion.dev/license), pass "free-license" instead.`);
15
- }
16
- await registerUsageEvent({
17
- apiKey: licenseKey === 'free-license' ? null : licenseKey,
18
- event: 'webcodec-conversion',
19
- host,
20
- succeeded,
21
- });
22
- };
@@ -1,29 +0,0 @@
1
- import { compose } from './compose';
2
- export const createFrame = async ({ div, width, height, logLevel, internalState, }) => {
3
- const canvas = new OffscreenCanvas(width, height);
4
- const context = canvas.getContext('2d');
5
- if (!context) {
6
- throw new Error('Could not get context');
7
- }
8
- await compose({
9
- element: div,
10
- context,
11
- logLevel,
12
- parentRect: new DOMRect(0, 0, width, height),
13
- internalState,
14
- });
15
- return canvas;
16
- };
17
- export const takeScreenshot = async ({ div, width, height, imageFormat, logLevel, internalState, }) => {
18
- const frame = await createFrame({
19
- div,
20
- width,
21
- height,
22
- logLevel,
23
- internalState,
24
- });
25
- const imageData = await frame.convertToBlob({
26
- type: `image/${imageFormat}`,
27
- });
28
- return imageData;
29
- };
@@ -1,43 +0,0 @@
1
- const DEFAULT_THROTTLE_MS = 250;
2
- /**
3
- * Creates a throttled version of a progress callback that ensures it's not called
4
- * more frequently than the specified interval (default: 250ms)
5
- */
6
- export const createThrottledProgressCallback = (callback, throttleMs = DEFAULT_THROTTLE_MS) => {
7
- if (!callback) {
8
- return null;
9
- }
10
- let lastCallTime = 0;
11
- let pendingUpdate = null;
12
- let timeoutId = null;
13
- const throttled = (progress) => {
14
- const now = Date.now();
15
- const timeSinceLastCall = now - lastCallTime;
16
- // Always store the latest progress
17
- pendingUpdate = progress;
18
- // If enough time has passed, call immediately
19
- if (timeSinceLastCall >= throttleMs) {
20
- lastCallTime = now;
21
- callback(progress);
22
- pendingUpdate = null;
23
- // Clear any pending timeout
24
- if (timeoutId !== null) {
25
- clearTimeout(timeoutId);
26
- timeoutId = null;
27
- }
28
- }
29
- else if (timeoutId === null) {
30
- // Schedule a call for when the throttle period expires
31
- const remainingTime = throttleMs - timeSinceLastCall;
32
- timeoutId = setTimeout(() => {
33
- if (pendingUpdate !== null) {
34
- lastCallTime = Date.now();
35
- callback(pendingUpdate);
36
- pendingUpdate = null;
37
- }
38
- timeoutId = null;
39
- }, remainingTime);
40
- }
41
- };
42
- return throttled;
43
- };
@@ -1,4 +0,0 @@
1
- export declare const setTransform: ({ ctx, transform, }: {
2
- ctx: OffscreenCanvasRenderingContext2D;
3
- transform: DOMMatrix;
4
- }) => () => void;