@remotion/renderer 4.0.347 → 4.0.348

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.
@@ -5389,7 +5389,7 @@ var DEFAULT_RENDER_FRAMES_OFFTHREAD_VIDEO_THREADS = 2;
5389
5389
 
5390
5390
  // src/prepare-server.ts
5391
5391
  import { existsSync as existsSync4 } from "node:fs";
5392
- import path18 from "node:path";
5392
+ import path19 from "node:path";
5393
5393
  import { NoReactInternals as NoReactInternals7 } from "remotion/no-react";
5394
5394
 
5395
5395
  // src/assets/download-and-map-assets-to-file.ts
@@ -14624,7 +14624,7 @@ var attachDownloadListenerToEmitter = (downloadMap, onDownload) => {
14624
14624
 
14625
14625
  // src/assets/download-map.ts
14626
14626
  import { mkdirSync as mkdirSync2 } from "node:fs";
14627
- import path14 from "node:path";
14627
+ import path15 from "node:path";
14628
14628
  import { VERSION as VERSION2 } from "remotion/version";
14629
14629
 
14630
14630
  // src/offthread-video-server.ts
@@ -15050,9 +15050,126 @@ var tmpDir = (str) => {
15050
15050
  return newDir;
15051
15051
  };
15052
15052
 
15053
+ // src/assets/inline-audio-mixing.ts
15054
+ import fs12, { writeSync } from "node:fs";
15055
+ import path14 from "node:path";
15056
+
15057
+ // src/sample-rate.ts
15058
+ var DEFAULT_SAMPLE_RATE = 48000;
15059
+
15060
+ // src/assets/inline-audio-mixing.ts
15061
+ var numberTo32BiIntLittleEndian = (num) => {
15062
+ return new Uint8Array([
15063
+ num & 255,
15064
+ num >> 8 & 255,
15065
+ num >> 16 & 255,
15066
+ num >> 24 & 255
15067
+ ]);
15068
+ };
15069
+ var numberTo16BitLittleEndian = (num) => {
15070
+ return new Uint8Array([num & 255, num >> 8 & 255]);
15071
+ };
15072
+ var BIT_DEPTH = 16;
15073
+ var BYTES_PER_SAMPLE = BIT_DEPTH / 8;
15074
+ var makeInlineAudioMixing = (dir) => {
15075
+ const folderToAdd = makeAndReturn(dir, "remotion-inline-audio-mixing");
15076
+ const openFiles = {};
15077
+ const writtenHeaders = {};
15078
+ const cleanup = () => {
15079
+ for (const fd of Object.values(openFiles)) {
15080
+ try {
15081
+ fs12.closeSync(fd);
15082
+ } catch {}
15083
+ }
15084
+ deleteDirectory(folderToAdd);
15085
+ };
15086
+ const getListOfAssets = () => {
15087
+ return Object.keys(openFiles);
15088
+ };
15089
+ const getFilePath = (asset) => {
15090
+ return path14.join(folderToAdd, `${asset.id}.wav`);
15091
+ };
15092
+ const ensureAsset = ({
15093
+ asset,
15094
+ fps,
15095
+ totalNumberOfFrames,
15096
+ trimLeftOffset,
15097
+ trimRightOffset
15098
+ }) => {
15099
+ const filePath = getFilePath(asset);
15100
+ if (!openFiles[filePath]) {
15101
+ openFiles[filePath] = fs12.openSync(filePath, "w");
15102
+ }
15103
+ if (writtenHeaders[filePath]) {
15104
+ return;
15105
+ }
15106
+ writtenHeaders[filePath] = true;
15107
+ const expectedDataSize = Math.round((totalNumberOfFrames / fps - trimLeftOffset + trimRightOffset) * asset.numberOfChannels * DEFAULT_SAMPLE_RATE * BYTES_PER_SAMPLE);
15108
+ const expectedSize = 40 + expectedDataSize;
15109
+ const { numberOfChannels } = asset;
15110
+ const fd = openFiles[filePath];
15111
+ writeSync(fd, new Uint8Array([82, 73, 70, 70]), 0, 4, 0);
15112
+ writeSync(fd, new Uint8Array(numberTo32BiIntLittleEndian(expectedSize)), 0, 4, 4);
15113
+ writeSync(fd, new Uint8Array([87, 65, 86, 69]), 0, 4, 8);
15114
+ writeSync(fd, new Uint8Array([102, 109, 116, 32]), 0, 4, 12);
15115
+ writeSync(fd, new Uint8Array([BIT_DEPTH, 0, 0, 0]), 0, 4, 16);
15116
+ writeSync(fd, new Uint8Array([1, 0]), 0, 2, 20);
15117
+ writeSync(fd, new Uint8Array([numberOfChannels, 0]), 0, 2, 22);
15118
+ writeSync(fd, new Uint8Array(numberTo32BiIntLittleEndian(DEFAULT_SAMPLE_RATE)), 0, 4, 24);
15119
+ writeSync(fd, new Uint8Array(numberTo32BiIntLittleEndian(DEFAULT_SAMPLE_RATE * numberOfChannels * BYTES_PER_SAMPLE)), 0, 4, 28);
15120
+ writeSync(fd, new Uint8Array(numberTo16BitLittleEndian(numberOfChannels * BYTES_PER_SAMPLE)), 0, 2, 32);
15121
+ writeSync(fd, numberTo16BitLittleEndian(BIT_DEPTH), 0, 2, 34);
15122
+ writeSync(fd, new Uint8Array([100, 97, 116, 97]), 0, 4, 36);
15123
+ writeSync(fd, new Uint8Array(numberTo32BiIntLittleEndian(expectedDataSize)), 0, 4, 40);
15124
+ };
15125
+ const addAsset = ({
15126
+ asset,
15127
+ fps,
15128
+ totalNumberOfFrames,
15129
+ firstFrame,
15130
+ trimLeftOffset,
15131
+ trimRightOffset
15132
+ }) => {
15133
+ ensureAsset({
15134
+ asset,
15135
+ fps,
15136
+ totalNumberOfFrames,
15137
+ trimLeftOffset,
15138
+ trimRightOffset
15139
+ });
15140
+ const filePath = getFilePath(asset);
15141
+ const fileDescriptor = openFiles[filePath];
15142
+ let arr = new Int16Array(asset.audio);
15143
+ const isFirst = asset.frame === firstFrame;
15144
+ const isLast = asset.frame === totalNumberOfFrames + firstFrame - 1;
15145
+ const samplesToShaveFromStart = trimLeftOffset * DEFAULT_SAMPLE_RATE;
15146
+ const samplesToShaveFromEnd = trimRightOffset * DEFAULT_SAMPLE_RATE;
15147
+ if (Math.abs(Math.round(samplesToShaveFromEnd) - samplesToShaveFromEnd) > 0.00000001) {
15148
+ throw new Error("samplesToShaveFromEnd should be approximately an integer");
15149
+ }
15150
+ if (Math.abs(Math.round(samplesToShaveFromStart) - samplesToShaveFromStart) > 0.00000001) {
15151
+ throw new Error("samplesToShaveFromStart should be approximately an integer");
15152
+ }
15153
+ if (isFirst) {
15154
+ arr = arr.slice(Math.round(samplesToShaveFromStart) * asset.numberOfChannels);
15155
+ }
15156
+ if (isLast) {
15157
+ arr = arr.slice(0, arr.length + Math.round(samplesToShaveFromEnd) * asset.numberOfChannels);
15158
+ }
15159
+ const positionInSeconds = (asset.frame - firstFrame) / fps - (isFirst ? 0 : trimLeftOffset);
15160
+ const position = Math.round(positionInSeconds * asset.numberOfChannels * DEFAULT_SAMPLE_RATE * BYTES_PER_SAMPLE);
15161
+ writeSync(fileDescriptor, arr, 0, arr.byteLength, 44 + position);
15162
+ };
15163
+ return {
15164
+ cleanup,
15165
+ addAsset,
15166
+ getListOfAssets
15167
+ };
15168
+ };
15169
+
15053
15170
  // src/assets/download-map.ts
15054
15171
  var makeAndReturn = (dir, name) => {
15055
- const p = path14.join(dir, name);
15172
+ const p = path15.join(dir, name);
15056
15173
  mkdirSync2(p);
15057
15174
  return p;
15058
15175
  };
@@ -15083,7 +15200,8 @@ var makeDownloadMap = () => {
15083
15200
  },
15084
15201
  isPreventedFromCleanup: () => {
15085
15202
  return prevented;
15086
- }
15203
+ },
15204
+ inlineAudioMixing: makeInlineAudioMixing(dir)
15087
15205
  };
15088
15206
  };
15089
15207
  var cleanDownloadMap = (downloadMap) => {
@@ -15093,11 +15211,12 @@ var cleanDownloadMap = (downloadMap) => {
15093
15211
  deleteDirectory(downloadMap.downloadDir);
15094
15212
  deleteDirectory(downloadMap.complexFilter);
15095
15213
  deleteDirectory(downloadMap.compositingDir);
15214
+ downloadMap.inlineAudioMixing.cleanup();
15096
15215
  deleteDirectory(downloadMap.assetDir);
15097
15216
  };
15098
15217
 
15099
15218
  // src/get-bundle-url-from-serve-url.ts
15100
- import path15 from "path";
15219
+ import path16 from "path";
15101
15220
  import { NoReactInternals as NoReactInternals6 } from "remotion/no-react";
15102
15221
  var map = (webpackBundleOrServeUrl, suffix) => {
15103
15222
  if (isServeUrl(webpackBundleOrServeUrl)) {
@@ -15108,7 +15227,7 @@ var map = (webpackBundleOrServeUrl, suffix) => {
15108
15227
  }
15109
15228
  return parsed.origin + parsed.pathname.substring(0, idx + 1) + suffix;
15110
15229
  }
15111
- const index = webpackBundleOrServeUrl.lastIndexOf(path15.sep);
15230
+ const index = webpackBundleOrServeUrl.lastIndexOf(path16.sep);
15112
15231
  const url = webpackBundleOrServeUrl.substring(0, index + 1) + suffix;
15113
15232
  return url;
15114
15233
  };
@@ -15339,10 +15458,10 @@ var hasIpv4LoopbackAddress = (flattened) => {
15339
15458
 
15340
15459
  // src/serve-handler/index.ts
15341
15460
  import { createReadStream, promises as promises2 } from "node:fs";
15342
- import path17 from "node:path";
15461
+ import path18 from "node:path";
15343
15462
 
15344
15463
  // src/serve-handler/is-path-inside.ts
15345
- import path16 from "node:path";
15464
+ import path17 from "node:path";
15346
15465
  var isPathInside = function(thePath, potentialParent) {
15347
15466
  thePath = stripTrailingSep(thePath);
15348
15467
  potentialParent = stripTrailingSep(potentialParent);
@@ -15350,10 +15469,10 @@ var isPathInside = function(thePath, potentialParent) {
15350
15469
  thePath = thePath.toLowerCase();
15351
15470
  potentialParent = potentialParent.toLowerCase();
15352
15471
  }
15353
- return thePath.lastIndexOf(potentialParent, 0) === 0 && (thePath[potentialParent.length] === path16.sep || thePath[potentialParent.length] === undefined);
15472
+ return thePath.lastIndexOf(potentialParent, 0) === 0 && (thePath[potentialParent.length] === path17.sep || thePath[potentialParent.length] === undefined);
15354
15473
  };
15355
15474
  function stripTrailingSep(thePath) {
15356
- if (thePath[thePath.length - 1] === path16.sep) {
15475
+ if (thePath[thePath.length - 1] === path17.sep) {
15357
15476
  return thePath.slice(0, -1);
15358
15477
  }
15359
15478
  return thePath;
@@ -15406,7 +15525,7 @@ var rangeParser = (size, str) => {
15406
15525
 
15407
15526
  // src/serve-handler/index.ts
15408
15527
  var getHeaders = (absolutePath, stats) => {
15409
- const { base } = path17.parse(absolutePath);
15528
+ const { base } = path18.parse(absolutePath);
15410
15529
  let defaultHeaders = {};
15411
15530
  if (stats) {
15412
15531
  defaultHeaders = {
@@ -15422,15 +15541,15 @@ var getHeaders = (absolutePath, stats) => {
15422
15541
  return defaultHeaders;
15423
15542
  };
15424
15543
  var getPossiblePaths = (relativePath, extension) => [
15425
- path17.join(relativePath, `index${extension}`),
15544
+ path18.join(relativePath, `index${extension}`),
15426
15545
  relativePath.endsWith("/") ? relativePath.replace(/\/$/g, extension) : relativePath + extension
15427
- ].filter((item) => path17.basename(item) !== extension);
15546
+ ].filter((item) => path18.basename(item) !== extension);
15428
15547
  var findRelated = async (current, relativePath) => {
15429
15548
  const possible = getPossiblePaths(relativePath, ".html");
15430
15549
  let stats = null;
15431
15550
  for (let index = 0;index < possible.length; index++) {
15432
15551
  const related = possible[index];
15433
- const absolutePath = path17.join(current, related);
15552
+ const absolutePath = path18.join(current, related);
15434
15553
  try {
15435
15554
  stats = await promises2.lstat(absolutePath);
15436
15555
  } catch (err) {
@@ -15465,7 +15584,7 @@ var internalError = (absolutePath, response) => {
15465
15584
  };
15466
15585
  var serveHandler = async (request, response, config) => {
15467
15586
  const cwd = process.cwd();
15468
- const current = path17.resolve(cwd, config.public);
15587
+ const current = path18.resolve(cwd, config.public);
15469
15588
  let relativePath = null;
15470
15589
  try {
15471
15590
  const parsedUrl = new URL(request.url, `http://${request.headers.host}`);
@@ -15477,7 +15596,7 @@ var serveHandler = async (request, response, config) => {
15477
15596
  message: "Bad Request"
15478
15597
  });
15479
15598
  }
15480
- let absolutePath = path17.join(current, relativePath);
15599
+ let absolutePath = path18.join(current, relativePath);
15481
15600
  if (!isPathInside(absolutePath, current)) {
15482
15601
  return sendError(absolutePath, response, {
15483
15602
  statusCode: 400,
@@ -15486,7 +15605,7 @@ var serveHandler = async (request, response, config) => {
15486
15605
  });
15487
15606
  }
15488
15607
  let stats = null;
15489
- if (path17.extname(relativePath) !== "") {
15608
+ if (path18.extname(relativePath) !== "") {
15490
15609
  try {
15491
15610
  stats = await promises2.lstat(absolutePath);
15492
15611
  } catch (err) {
@@ -15569,7 +15688,7 @@ var serveHandler = async (request, response, config) => {
15569
15688
  };
15570
15689
 
15571
15690
  // src/serve-static.ts
15572
- var serveStatic = async (path18, options) => {
15691
+ var serveStatic = async (path19, options) => {
15573
15692
  const {
15574
15693
  listener: offthreadRequest,
15575
15694
  close: closeCompositor,
@@ -15587,13 +15706,13 @@ var serveStatic = async (path18, options) => {
15587
15706
  if (request.url?.startsWith("/proxy")) {
15588
15707
  return offthreadRequest(request, response);
15589
15708
  }
15590
- if (path18 === null) {
15709
+ if (path19 === null) {
15591
15710
  response.writeHead(404);
15592
15711
  response.end("Server only supports /proxy");
15593
15712
  return;
15594
15713
  }
15595
15714
  serveHandler(request, response, {
15596
- public: path18
15715
+ public: path19
15597
15716
  }).catch(() => {
15598
15717
  if (!response.headersSent) {
15599
15718
  response.writeHead(500);
@@ -15744,13 +15863,13 @@ var prepareServer = async ({
15744
15863
  downloadMap
15745
15864
  });
15746
15865
  }
15747
- const indexFile = path18.join(webpackConfigOrServeUrl, "index.html");
15866
+ const indexFile = path19.join(webpackConfigOrServeUrl, "index.html");
15748
15867
  const exists = existsSync4(indexFile);
15749
15868
  if (!exists) {
15750
15869
  throw new Error(`Tried to serve the Webpack bundle on a HTTP server, but the file ${indexFile} does not exist. Is this a valid path to a Webpack bundle?`);
15751
15870
  }
15752
15871
  let localSourceMap = null;
15753
- getSourceMapFromLocalFile(path18.join(webpackConfigOrServeUrl, NoReactInternals7.bundleName)).then((s) => {
15872
+ getSourceMapFromLocalFile(path19.join(webpackConfigOrServeUrl, NoReactInternals7.bundleName)).then((s) => {
15754
15873
  localSourceMap = s;
15755
15874
  }).catch((err) => {
15756
15875
  Log.verbose({ indent, logLevel }, "Could not fetch sourcemap for ", webpackConfigOrServeUrl, err);
@@ -16785,21 +16904,21 @@ var defaultCodecsForFileExtension = {
16785
16904
  // src/path-normalize.ts
16786
16905
  var SLASH = 47;
16787
16906
  var DOT = 46;
16788
- var assertPath = (path19) => {
16789
- const t = typeof path19;
16907
+ var assertPath = (path20) => {
16908
+ const t = typeof path20;
16790
16909
  if (t !== "string") {
16791
16910
  throw new TypeError(`Expected a string, got a ${t}`);
16792
16911
  }
16793
16912
  };
16794
- var posixNormalize = (path19, allowAboveRoot) => {
16913
+ var posixNormalize = (path20, allowAboveRoot) => {
16795
16914
  let res = "";
16796
16915
  let lastSegmentLength = 0;
16797
16916
  let lastSlash = -1;
16798
16917
  let dots = 0;
16799
16918
  let code;
16800
- for (let i = 0;i <= path19.length; ++i) {
16801
- if (i < path19.length) {
16802
- code = path19.charCodeAt(i);
16919
+ for (let i = 0;i <= path20.length; ++i) {
16920
+ if (i < path20.length) {
16921
+ code = path20.charCodeAt(i);
16803
16922
  } else if (code === SLASH) {
16804
16923
  break;
16805
16924
  } else {
@@ -16840,9 +16959,9 @@ var posixNormalize = (path19, allowAboveRoot) => {
16840
16959
  }
16841
16960
  } else {
16842
16961
  if (res.length > 0) {
16843
- res += "/" + path19.slice(lastSlash + 1, i);
16962
+ res += "/" + path20.slice(lastSlash + 1, i);
16844
16963
  } else {
16845
- res = path19.slice(lastSlash + 1, i);
16964
+ res = path20.slice(lastSlash + 1, i);
16846
16965
  }
16847
16966
  lastSegmentLength = i - lastSlash - 1;
16848
16967
  }
@@ -16865,24 +16984,24 @@ var decode = (s) => {
16865
16984
  };
16866
16985
  var pathNormalize = (p) => {
16867
16986
  assertPath(p);
16868
- let path19 = p;
16869
- if (path19.length === 0) {
16987
+ let path20 = p;
16988
+ if (path20.length === 0) {
16870
16989
  return ".";
16871
16990
  }
16872
- const isAbsolute = path19.charCodeAt(0) === SLASH;
16873
- const trailingSeparator = path19.charCodeAt(path19.length - 1) === SLASH;
16874
- path19 = decode(path19);
16875
- path19 = posixNormalize(path19, !isAbsolute);
16876
- if (path19.length === 0 && !isAbsolute) {
16877
- path19 = ".";
16991
+ const isAbsolute = path20.charCodeAt(0) === SLASH;
16992
+ const trailingSeparator = path20.charCodeAt(path20.length - 1) === SLASH;
16993
+ path20 = decode(path20);
16994
+ path20 = posixNormalize(path20, !isAbsolute);
16995
+ if (path20.length === 0 && !isAbsolute) {
16996
+ path20 = ".";
16878
16997
  }
16879
- if (path19.length > 0 && trailingSeparator) {
16880
- path19 += "/";
16998
+ if (path20.length > 0 && trailingSeparator) {
16999
+ path20 += "/";
16881
17000
  }
16882
17001
  if (isAbsolute) {
16883
- return "/" + path19;
17002
+ return "/" + path20;
16884
17003
  }
16885
- return path19;
17004
+ return path20;
16886
17005
  };
16887
17006
 
16888
17007
  // src/get-extension-of-filename.ts
@@ -17035,8 +17154,8 @@ var validateSelectedPixelFormatAndCodecCombination = (pixelFormat, codec) => {
17035
17154
  };
17036
17155
 
17037
17156
  // src/render-frames.ts
17038
- import fs13 from "node:fs";
17039
- import path20 from "node:path";
17157
+ import fs14 from "node:fs";
17158
+ import path21 from "node:path";
17040
17159
  import { NoReactInternals as NoReactInternals12 } from "remotion/no-react";
17041
17160
 
17042
17161
  // src/cycle-browser-tabs.ts
@@ -17308,9 +17427,6 @@ var parseFfmpegProgress = (input, fps) => {
17308
17427
  }
17309
17428
  };
17310
17429
 
17311
- // src/sample-rate.ts
17312
- var DEFAULT_SAMPLE_RATE = 48000;
17313
-
17314
17430
  // src/combine-audio.ts
17315
17431
  var durationOf1Frame = 1024 / DEFAULT_SAMPLE_RATE * 1e6;
17316
17432
  var getClosestAlignedTime = (targetTime) => {
@@ -17862,40 +17978,7 @@ var getRetriesLeftFromError = (error) => {
17862
17978
  };
17863
17979
 
17864
17980
  // src/render-frame-with-option-to-reject.ts
17865
- import path19 from "path";
17866
-
17867
- // src/filter-asset-types.ts
17868
- var onlyAudioAndVideoAssets = (assets) => {
17869
- return assets.filter((asset) => asset.type === "audio" || asset.type === "video");
17870
- };
17871
- var onlyArtifact = ({
17872
- assets,
17873
- frameBuffer
17874
- }) => {
17875
- const artifacts = assets.filter((asset) => asset.type === "artifact");
17876
- return artifacts.map((artifact) => {
17877
- if (artifact.contentType === "binary" || artifact.contentType === "text") {
17878
- return {
17879
- frame: artifact.frame,
17880
- content: artifact.content,
17881
- filename: artifact.filename,
17882
- downloadBehavior: artifact.downloadBehavior
17883
- };
17884
- }
17885
- if (artifact.contentType === "thumbnail") {
17886
- if (frameBuffer === null) {
17887
- return null;
17888
- }
17889
- return {
17890
- frame: artifact.frame,
17891
- content: new Uint8Array(frameBuffer),
17892
- filename: artifact.filename,
17893
- downloadBehavior: artifact.downloadBehavior
17894
- };
17895
- }
17896
- throw new Error("Unknown artifact type: " + artifact);
17897
- }).filter(truthy);
17898
- };
17981
+ import path20 from "path";
17899
17982
 
17900
17983
  // src/collect-assets.ts
17901
17984
  var collectAssets = async ({
@@ -17934,18 +18017,54 @@ var collectAssets = async ({
17934
18017
  return fixedArtifacts;
17935
18018
  };
17936
18019
 
18020
+ // src/filter-asset-types.ts
18021
+ var onlyAudioAndVideoAssets = (assets) => {
18022
+ return assets.filter((asset) => asset.type === "audio" || asset.type === "video");
18023
+ };
18024
+ var onlyArtifact = ({
18025
+ assets,
18026
+ frameBuffer
18027
+ }) => {
18028
+ const artifacts = assets.filter((asset) => asset.type === "artifact");
18029
+ return artifacts.map((artifact) => {
18030
+ if (artifact.contentType === "binary" || artifact.contentType === "text") {
18031
+ return {
18032
+ frame: artifact.frame,
18033
+ content: artifact.content,
18034
+ filename: artifact.filename,
18035
+ downloadBehavior: artifact.downloadBehavior
18036
+ };
18037
+ }
18038
+ if (artifact.contentType === "thumbnail") {
18039
+ if (frameBuffer === null) {
18040
+ return null;
18041
+ }
18042
+ return {
18043
+ frame: artifact.frame,
18044
+ content: new Uint8Array(frameBuffer),
18045
+ filename: artifact.filename,
18046
+ downloadBehavior: artifact.downloadBehavior
18047
+ };
18048
+ }
18049
+ throw new Error("Unknown artifact type: " + artifact);
18050
+ }).filter(truthy);
18051
+ };
18052
+ var onlyInlineAudio = (assets) => {
18053
+ return assets.filter((asset) => asset.type === "inline-audio");
18054
+ };
18055
+
17937
18056
  // src/puppeteer-screenshot.ts
17938
18057
  import * as assert2 from "node:assert";
17939
18058
 
17940
18059
  // src/screenshot-task.ts
17941
- import fs12 from "node:fs";
18060
+ import fs13 from "node:fs";
17942
18061
  var screenshotTask = async ({
17943
18062
  format,
17944
18063
  height,
17945
18064
  omitBackground,
17946
18065
  page,
17947
18066
  width,
17948
- path: path19,
18067
+ path: path20,
17949
18068
  jpegQuality,
17950
18069
  scale
17951
18070
  }) => {
@@ -17998,8 +18117,8 @@ var screenshotTask = async ({
17998
18117
  await client.send("Emulation.setDefaultBackgroundColorOverride");
17999
18118
  }
18000
18119
  const buffer = Buffer.from(result.data, "base64");
18001
- if (path19) {
18002
- await fs12.promises.writeFile(path19, buffer);
18120
+ if (path20) {
18121
+ await fs13.promises.writeFile(path20, buffer);
18003
18122
  }
18004
18123
  return buffer;
18005
18124
  } catch (err) {
@@ -18038,7 +18157,6 @@ var takeFrame = async ({
18038
18157
  freePage,
18039
18158
  imageFormat,
18040
18159
  jpegQuality,
18041
- frame,
18042
18160
  width,
18043
18161
  height,
18044
18162
  output,
@@ -18046,13 +18164,8 @@ var takeFrame = async ({
18046
18164
  wantsBuffer,
18047
18165
  timeoutInMilliseconds
18048
18166
  }) => {
18049
- const collectedAssets = await collectAssets({
18050
- frame,
18051
- freePage,
18052
- timeoutInMilliseconds
18053
- });
18054
18167
  if (imageFormat === "none") {
18055
- return { buffer: null, collectedAssets };
18168
+ return null;
18056
18169
  }
18057
18170
  if (imageFormat === "png" || imageFormat === "pdf" || imageFormat === "webp") {
18058
18171
  await puppeteerEvaluateWithCatch({
@@ -18085,7 +18198,7 @@ var takeFrame = async ({
18085
18198
  height,
18086
18199
  scale
18087
18200
  });
18088
- return { buffer: buf, collectedAssets };
18201
+ return buf;
18089
18202
  };
18090
18203
 
18091
18204
  // src/render-frame-with-option-to-reject.ts
@@ -18119,7 +18232,11 @@ var renderFrameWithOptionToReject = async ({
18119
18232
  onFrameUpdate,
18120
18233
  frame,
18121
18234
  page,
18122
- imageSequencePattern
18235
+ imageSequencePattern,
18236
+ fps,
18237
+ trimLeftOffset,
18238
+ trimRightOffset,
18239
+ allFramesAndExtraFrames
18123
18240
  }) => {
18124
18241
  const startTime = performance.now();
18125
18242
  const index = framesToRender.indexOf(frame);
@@ -18156,26 +18273,32 @@ var renderFrameWithOptionToReject = async ({
18156
18273
  if (outputDir && onFrameBuffer && imageFormat !== "none") {
18157
18274
  throw new Error("Pass either `outputDir` or `onFrameBuffer` to renderFrames(), not both.");
18158
18275
  }
18159
- const { buffer, collectedAssets } = await takeFrame({
18160
- frame,
18161
- freePage: page,
18162
- height,
18163
- imageFormat: assetsOnly ? "none" : imageFormat,
18164
- output: index === null ? null : path19.join(frameDir, getFrameOutputFileName({
18276
+ const [buffer, collectedAssets] = await Promise.all([
18277
+ takeFrame({
18278
+ freePage: page,
18279
+ height,
18280
+ imageFormat: assetsOnly ? "none" : imageFormat,
18281
+ output: index === null ? null : path20.join(frameDir, getFrameOutputFileName({
18282
+ frame,
18283
+ imageFormat,
18284
+ index,
18285
+ countType,
18286
+ lastFrame,
18287
+ totalFrames: framesToRender.length,
18288
+ imageSequencePattern
18289
+ })),
18290
+ jpegQuality,
18291
+ width,
18292
+ scale,
18293
+ wantsBuffer: Boolean(onFrameBuffer),
18294
+ timeoutInMilliseconds
18295
+ }),
18296
+ collectAssets({
18165
18297
  frame,
18166
- imageFormat,
18167
- index,
18168
- countType,
18169
- lastFrame,
18170
- totalFrames: framesToRender.length,
18171
- imageSequencePattern
18172
- })),
18173
- jpegQuality,
18174
- width,
18175
- scale,
18176
- wantsBuffer: Boolean(onFrameBuffer),
18177
- timeoutInMilliseconds
18178
- });
18298
+ freePage: page,
18299
+ timeoutInMilliseconds
18300
+ })
18301
+ ]);
18179
18302
  if (onFrameBuffer && !assetsOnly) {
18180
18303
  if (!buffer) {
18181
18304
  throw new Error("unexpected null buffer");
@@ -18201,6 +18324,7 @@ var renderFrameWithOptionToReject = async ({
18201
18324
  const compressedAssets = audioAndVideoAssets.map((asset) => {
18202
18325
  return compressAsset(previousAudioRenderAssets, asset);
18203
18326
  });
18327
+ const inlineAudioAssets = onlyInlineAudio(collectedAssets);
18204
18328
  assets.push({
18205
18329
  audioAndVideoAssets: compressedAssets,
18206
18330
  frame,
@@ -18209,7 +18333,8 @@ var renderFrameWithOptionToReject = async ({
18209
18333
  frame: a.frame,
18210
18334
  filename: a.filename
18211
18335
  };
18212
- })
18336
+ }),
18337
+ inlineAudioAssets
18213
18338
  });
18214
18339
  for (const renderAsset of compressedAssets) {
18215
18340
  downloadAndMapAssetsToFileUrl({
@@ -18226,6 +18351,16 @@ var renderFrameWithOptionToReject = async ({
18226
18351
  onError(new Error(`Error while downloading ${truncateWithEllipsis}: ${err.stack}`));
18227
18352
  });
18228
18353
  }
18354
+ for (const renderAsset of inlineAudioAssets) {
18355
+ downloadMap.inlineAudioMixing.addAsset({
18356
+ asset: renderAsset,
18357
+ fps,
18358
+ totalNumberOfFrames: allFramesAndExtraFrames.length,
18359
+ firstFrame: allFramesAndExtraFrames[0],
18360
+ trimLeftOffset,
18361
+ trimRightOffset
18362
+ });
18363
+ }
18229
18364
  cleanupPageError();
18230
18365
  page.off("error", errorCallbackOnFrame);
18231
18366
  if (!assetsOnly) {
@@ -18262,7 +18397,10 @@ var renderFrame = ({
18262
18397
  framesRenderedObj,
18263
18398
  frame,
18264
18399
  page,
18265
- imageSequencePattern
18400
+ imageSequencePattern,
18401
+ trimLeftOffset,
18402
+ trimRightOffset,
18403
+ allFramesAndExtraFrames
18266
18404
  }) => {
18267
18405
  return new Promise((resolve2, reject) => {
18268
18406
  renderFrameWithOptionToReject({
@@ -18295,7 +18433,11 @@ var renderFrame = ({
18295
18433
  onFrameUpdate,
18296
18434
  frame,
18297
18435
  page,
18298
- imageSequencePattern
18436
+ imageSequencePattern,
18437
+ fps: composition.fps,
18438
+ trimLeftOffset,
18439
+ trimRightOffset,
18440
+ allFramesAndExtraFrames
18299
18441
  }).then(() => {
18300
18442
  resolve2();
18301
18443
  }).catch((err) => {
@@ -18337,7 +18479,10 @@ var renderFrameAndRetryTargetClose = async ({
18337
18479
  onFrameBuffer,
18338
18480
  onFrameUpdate,
18339
18481
  nextFrameToRender,
18340
- imageSequencePattern
18482
+ imageSequencePattern,
18483
+ trimLeftOffset,
18484
+ trimRightOffset,
18485
+ allFramesAndExtraFrames
18341
18486
  }) => {
18342
18487
  const currentPool = await poolPromise;
18343
18488
  if (stoppedSignal.stopped) {
@@ -18348,6 +18493,9 @@ var renderFrameAndRetryTargetClose = async ({
18348
18493
  try {
18349
18494
  await Promise.race([
18350
18495
  renderFrame({
18496
+ trimLeftOffset,
18497
+ trimRightOffset,
18498
+ allFramesAndExtraFrames,
18351
18499
  attempt,
18352
18500
  assets,
18353
18501
  binariesDirectory,
@@ -18443,7 +18591,10 @@ var renderFrameAndRetryTargetClose = async ({
18443
18591
  onFrameBuffer,
18444
18592
  onFrameUpdate,
18445
18593
  nextFrameToRender,
18446
- imageSequencePattern
18594
+ imageSequencePattern,
18595
+ trimLeftOffset,
18596
+ trimRightOffset,
18597
+ allFramesAndExtraFrames
18447
18598
  });
18448
18599
  }
18449
18600
  Log.warn({ indent, logLevel }, `The browser crashed while rendering frame ${frame}, retrying ${retriesLeft} more times. Learn more about this error under https://www.remotion.dev/docs/target-closed`);
@@ -18488,7 +18639,10 @@ var renderFrameAndRetryTargetClose = async ({
18488
18639
  onFrameBuffer,
18489
18640
  onFrameUpdate,
18490
18641
  nextFrameToRender,
18491
- imageSequencePattern
18642
+ imageSequencePattern,
18643
+ trimLeftOffset,
18644
+ trimRightOffset,
18645
+ allFramesAndExtraFrames
18492
18646
  });
18493
18647
  }
18494
18648
  };
@@ -18599,8 +18753,8 @@ var innerRenderFrames = async ({
18599
18753
  imageSequencePattern
18600
18754
  }) => {
18601
18755
  if (outputDir) {
18602
- if (!fs13.existsSync(outputDir)) {
18603
- fs13.mkdirSync(outputDir, {
18756
+ if (!fs14.existsSync(outputDir)) {
18757
+ fs14.mkdirSync(outputDir, {
18604
18758
  recursive: true
18605
18759
  });
18606
18760
  }
@@ -18723,7 +18877,10 @@ var innerRenderFrames = async ({
18723
18877
  onFrameBuffer,
18724
18878
  onFrameUpdate,
18725
18879
  nextFrameToRender,
18726
- imageSequencePattern: pattern
18880
+ imageSequencePattern: pattern,
18881
+ trimLeftOffset,
18882
+ trimRightOffset,
18883
+ allFramesAndExtraFrames
18727
18884
  });
18728
18885
  }));
18729
18886
  const firstFrameIndex = countType === "from-zero" ? 0 : framesToRender[0];
@@ -18733,7 +18890,7 @@ var innerRenderFrames = async ({
18733
18890
  assets: assets.sort((a, b) => {
18734
18891
  return a.frame - b.frame;
18735
18892
  }),
18736
- imageSequenceName: path20.join(frameDir, imageSequenceName),
18893
+ imageSequenceName: path21.join(frameDir, imageSequenceName),
18737
18894
  firstFrameIndex,
18738
18895
  downloadMap,
18739
18896
  trimLeftOffset,
@@ -19016,9 +19173,9 @@ var renderFrames = (options) => {
19016
19173
  };
19017
19174
 
19018
19175
  // src/render-media.ts
19019
- import fs15 from "node:fs";
19176
+ import fs16 from "node:fs";
19020
19177
  import os6 from "node:os";
19021
- import path25 from "node:path";
19178
+ import path26 from "node:path";
19022
19179
  import { NoReactInternals as NoReactInternals14 } from "remotion/no-react";
19023
19180
 
19024
19181
  // src/crf.ts
@@ -19651,7 +19808,7 @@ var validateSelectedCodecAndProResCombination = ({
19651
19808
 
19652
19809
  // src/stitch-frames-to-video.ts
19653
19810
  import { cpSync as cpSync2, promises as promises3, rmSync as rmSync3 } from "node:fs";
19654
- import path24 from "node:path";
19811
+ import path25 from "node:path";
19655
19812
 
19656
19813
  // src/convert-number-of-gif-loops-to-ffmpeg.ts
19657
19814
  var convertNumberOfGifLoopsToFfmpegSyntax = (loops) => {
@@ -19665,7 +19822,7 @@ var convertNumberOfGifLoopsToFfmpegSyntax = (loops) => {
19665
19822
  };
19666
19823
 
19667
19824
  // src/create-audio.ts
19668
- import path23 from "path";
19825
+ import path24 from "path";
19669
19826
 
19670
19827
  // src/resolve-asset-src.ts
19671
19828
  import url from "node:url";
@@ -19866,7 +20023,7 @@ var compressAudio = async ({
19866
20023
  };
19867
20024
 
19868
20025
  // src/merge-audio-track.ts
19869
- import path22 from "node:path";
20026
+ import path23 from "node:path";
19870
20027
 
19871
20028
  // src/chunk.ts
19872
20029
  var chunk2 = (input, size) => {
@@ -19897,22 +20054,30 @@ var createFfmpegMergeFilter = ({
19897
20054
  };
19898
20055
 
19899
20056
  // src/ffmpeg-filter-file.ts
19900
- import fs14, { existsSync as existsSync5 } from "node:fs";
19901
- import path21 from "node:path";
20057
+ import fs15, { existsSync as existsSync5 } from "node:fs";
20058
+ import path22 from "node:path";
19902
20059
  var makeFfmpegFilterFile = (complexFilter, downloadMap) => {
20060
+ if (complexFilter.filter === null) {
20061
+ return {
20062
+ file: null,
20063
+ cleanup: () => {
20064
+ return;
20065
+ }
20066
+ };
20067
+ }
19903
20068
  return makeFfmpegFilterFileStr(complexFilter.filter, downloadMap);
19904
20069
  };
19905
20070
  var makeFfmpegFilterFileStr = async (complexFilter, downloadMap) => {
19906
20071
  const random2 = Math.random().toString().replace(".", "");
19907
- const filterFile = path21.join(downloadMap.complexFilter, "complex-filter-" + random2 + ".txt");
20072
+ const filterFile = path22.join(downloadMap.complexFilter, "complex-filter-" + random2 + ".txt");
19908
20073
  if (!existsSync5(downloadMap.complexFilter)) {
19909
- fs14.mkdirSync(downloadMap.complexFilter, { recursive: true });
20074
+ fs15.mkdirSync(downloadMap.complexFilter, { recursive: true });
19910
20075
  }
19911
- await fs14.promises.writeFile(filterFile, complexFilter);
20076
+ await fs15.promises.writeFile(filterFile, complexFilter);
19912
20077
  return {
19913
20078
  file: filterFile,
19914
20079
  cleanup: () => {
19915
- fs14.unlinkSync(filterFile);
20080
+ fs15.unlinkSync(filterFile);
19916
20081
  }
19917
20082
  };
19918
20083
  };
@@ -20011,7 +20176,7 @@ var mergeAudioTrackUnlimited = async ({
20011
20176
  onProgress(combinedProgress);
20012
20177
  };
20013
20178
  const chunkNames = await Promise.all(chunked.map(async (chunkFiles, i) => {
20014
- const chunkOutname = path22.join(tempPath, `chunk-${i}.wav`);
20179
+ const chunkOutname = path23.join(tempPath, `chunk-${i}.wav`);
20015
20180
  await mergeAudioTrack({
20016
20181
  files: chunkFiles,
20017
20182
  chunkLengthInSeconds,
@@ -20196,6 +20361,32 @@ var ffmpegVolumeExpression = ({
20196
20361
  };
20197
20362
  };
20198
20363
 
20364
+ // src/seamless-aac-trim.ts
20365
+ var getActualTrimLeft = ({
20366
+ fps,
20367
+ trimLeftOffset,
20368
+ seamless,
20369
+ assetDuration,
20370
+ audioStartFrame,
20371
+ trimLeft,
20372
+ playbackRate
20373
+ }) => {
20374
+ const sinceStart = trimLeft - audioStartFrame;
20375
+ if (!seamless) {
20376
+ return {
20377
+ trimLeft: audioStartFrame / fps + sinceStart / fps * playbackRate + trimLeftOffset,
20378
+ maxTrim: assetDuration
20379
+ };
20380
+ }
20381
+ if (seamless) {
20382
+ return {
20383
+ trimLeft: audioStartFrame / fps / playbackRate + sinceStart / fps + trimLeftOffset,
20384
+ maxTrim: assetDuration ? assetDuration / playbackRate : null
20385
+ };
20386
+ }
20387
+ throw new Error("This should never happen");
20388
+ };
20389
+
20199
20390
  // src/stringify-ffmpeg-filter.ts
20200
20391
  var cleanUpFloatingPointError = (value) => {
20201
20392
  if (value % 1 < 0.0000001) {
@@ -20214,28 +20405,6 @@ var stringifyTrim = (trim) => {
20214
20405
  }
20215
20406
  return asString;
20216
20407
  };
20217
- var getActualTrimLeft = ({
20218
- asset,
20219
- fps,
20220
- trimLeftOffset,
20221
- seamless,
20222
- assetDuration
20223
- }) => {
20224
- const sinceStart = asset.trimLeft - asset.audioStartFrame;
20225
- if (!seamless) {
20226
- return {
20227
- trimLeft: asset.audioStartFrame / fps + sinceStart / fps * asset.playbackRate + trimLeftOffset,
20228
- maxTrim: assetDuration
20229
- };
20230
- }
20231
- if (seamless) {
20232
- return {
20233
- trimLeft: asset.audioStartFrame / fps / asset.playbackRate + sinceStart / fps + trimLeftOffset,
20234
- maxTrim: assetDuration ? assetDuration / asset.playbackRate : null
20235
- };
20236
- }
20237
- throw new Error("This should never happen");
20238
- };
20239
20408
  var trimAndSetTempo = ({
20240
20409
  assetDuration,
20241
20410
  asset,
@@ -20246,11 +20415,13 @@ var trimAndSetTempo = ({
20246
20415
  logLevel
20247
20416
  }) => {
20248
20417
  const { trimLeft, maxTrim } = getActualTrimLeft({
20249
- asset,
20418
+ trimLeft: asset.trimLeft,
20250
20419
  fps,
20251
20420
  trimLeftOffset,
20252
20421
  seamless: true,
20253
- assetDuration
20422
+ assetDuration,
20423
+ audioStartFrame: asset.audioStartFrame,
20424
+ playbackRate: asset.playbackRate
20254
20425
  });
20255
20426
  const trimRight = trimLeft + asset.duration / fps - trimLeftOffset + trimRightOffset;
20256
20427
  let trimRightOrAssetDuration = maxTrim ? Math.min(trimRight, maxTrim) : trimRight;
@@ -20292,11 +20463,13 @@ var stringifyFfmpegFilter = ({
20292
20463
  const { toneFrequency, startInVideo } = asset;
20293
20464
  const startInVideoSeconds = startInVideo / fps;
20294
20465
  const { trimLeft, maxTrim } = getActualTrimLeft({
20295
- asset,
20466
+ trimLeft: asset.trimLeft,
20296
20467
  fps,
20297
20468
  trimLeftOffset,
20298
20469
  seamless: forSeamlessAacConcatenation,
20299
- assetDuration
20470
+ assetDuration,
20471
+ audioStartFrame: asset.audioStartFrame,
20472
+ playbackRate: asset.playbackRate
20300
20473
  });
20301
20474
  if (maxTrim && trimLeft >= maxTrim) {
20302
20475
  return null;
@@ -20386,11 +20559,11 @@ var preprocessAudioTrackUnlimited = async ({
20386
20559
  ["-i", resolveAssetSrc(asset.src)],
20387
20560
  audioStreamIndex ? ["-map", `0:a:${audioStreamIndex}`] : [],
20388
20561
  ["-ac", "2"],
20389
- ["-filter_script:a", file],
20562
+ file ? ["-filter_script:a", file] : null,
20390
20563
  ["-c:a", "pcm_s16le"],
20391
20564
  ["-ar", String(DEFAULT_SAMPLE_RATE)],
20392
20565
  ["-y", outName]
20393
- ].flat(2);
20566
+ ].flat(2).filter(truthy);
20394
20567
  Log.verbose({ indent, logLevel }, "Preprocessing audio track:", JSON.stringify(args.join(" ")), "Filter:", filter.filter);
20395
20568
  const startTimestamp = Date.now();
20396
20569
  const task = callFf({
@@ -20459,7 +20632,7 @@ var createAudio = async ({
20459
20632
  onProgress(totalProgress);
20460
20633
  };
20461
20634
  const audioTracks = await Promise.all(assetPositions.map(async (asset, index) => {
20462
- const filterFile = path23.join(downloadMap.audioMixing, `${index}.wav`);
20635
+ const filterFile = path24.join(downloadMap.audioMixing, `${index}.wav`);
20463
20636
  const result = await preprocessAudioTrack({
20464
20637
  outName: filterFile,
20465
20638
  asset,
@@ -20483,10 +20656,21 @@ var createAudio = async ({
20483
20656
  updateProgress();
20484
20657
  return result;
20485
20658
  }));
20486
- const preprocessed = audioTracks.filter(truthy);
20487
- const merged = path23.join(downloadMap.audioPreprocessing, "merged.wav");
20659
+ const inlinedAudio = downloadMap.inlineAudioMixing.getListOfAssets();
20660
+ const preprocessed = [
20661
+ ...audioTracks.filter(truthy),
20662
+ ...inlinedAudio.map((asset) => ({
20663
+ outName: asset,
20664
+ filter: {
20665
+ filter: null,
20666
+ pad_start: null,
20667
+ pad_end: null
20668
+ }
20669
+ }))
20670
+ ];
20671
+ const merged = path24.join(downloadMap.audioPreprocessing, "merged.wav");
20488
20672
  const extension = getExtensionFromAudioCodec(audioCodec);
20489
- const outName = path23.join(downloadMap.audioPreprocessing, `audio.${extension}`);
20673
+ const outName = path24.join(downloadMap.audioPreprocessing, `audio.${extension}`);
20490
20674
  await mergeAudioTrack({
20491
20675
  files: preprocessed,
20492
20676
  outName: merged,
@@ -20662,7 +20846,7 @@ var innerStitchFramesToVideo = async ({
20662
20846
  setting: audioCodecSetting,
20663
20847
  separateAudioTo
20664
20848
  });
20665
- const tempFile = outputLocation ? null : path24.join(assetsInfo.downloadMap.stitchFrames, `out.${getFileExtensionFromCodec(codec, resolvedAudioCodec)}`);
20849
+ const tempFile = outputLocation ? null : path25.join(assetsInfo.downloadMap.stitchFrames, `out.${getFileExtensionFromCodec(codec, resolvedAudioCodec)}`);
20666
20850
  Log.verbose({
20667
20851
  indent,
20668
20852
  logLevel,
@@ -20736,7 +20920,7 @@ var innerStitchFramesToVideo = async ({
20736
20920
  }
20737
20921
  cpSync2(audio, outputLocation ?? tempFile);
20738
20922
  onProgress?.(Math.round(assetsInfo.chunkLengthInSeconds * fps));
20739
- deleteDirectory(path24.dirname(audio));
20923
+ deleteDirectory(path25.dirname(audio));
20740
20924
  const file = await new Promise((resolve2, reject) => {
20741
20925
  if (tempFile) {
20742
20926
  promises3.readFile(tempFile).then((f) => {
@@ -20747,6 +20931,7 @@ var innerStitchFramesToVideo = async ({
20747
20931
  }
20748
20932
  });
20749
20933
  deleteDirectory(assetsInfo.downloadMap.stitchFrames);
20934
+ assetsInfo.downloadMap.allowCleanup();
20750
20935
  return Promise.resolve(file);
20751
20936
  }
20752
20937
  const ffmpegArgs = [
@@ -20824,14 +21009,13 @@ var innerStitchFramesToVideo = async ({
20824
21009
  if (!audio) {
20825
21010
  throw new Error(`\`separateAudioTo\` was set to ${JSON.stringify(separateAudioTo)}, but this render included no audio`);
20826
21011
  }
20827
- const finalDestination = path24.resolve(remotionRoot, separateAudioTo);
21012
+ const finalDestination = path25.resolve(remotionRoot, separateAudioTo);
20828
21013
  cpSync2(audio, finalDestination);
20829
21014
  rmSync3(audio);
20830
21015
  }
20831
- return new Promise((resolve2, reject) => {
21016
+ const result = await new Promise((resolve2, reject) => {
20832
21017
  task.once("close", (code, signal) => {
20833
21018
  if (code === 0) {
20834
- assetsInfo.downloadMap.allowCleanup();
20835
21019
  if (tempFile === null) {
20836
21020
  cleanDownloadMap(assetsInfo.downloadMap);
20837
21021
  return resolve2(null);
@@ -20848,6 +21032,8 @@ var innerStitchFramesToVideo = async ({
20848
21032
  }
20849
21033
  });
20850
21034
  });
21035
+ assetsInfo.downloadMap.allowCleanup();
21036
+ return result;
20851
21037
  };
20852
21038
  var internalStitchFramesToVideo = (options) => {
20853
21039
  const remotionRoot = findRemotionRoot();
@@ -21145,7 +21331,7 @@ var internalRenderMediaRaw = ({
21145
21331
  separateAudioTo
21146
21332
  });
21147
21333
  }
21148
- const absoluteOutputLocation = outputLocation ? path25.resolve(process.cwd(), outputLocation) : null;
21334
+ const absoluteOutputLocation = outputLocation ? path26.resolve(process.cwd(), outputLocation) : null;
21149
21335
  validateScale(scale);
21150
21336
  validateFfmpegOverride(ffmpegOverride);
21151
21337
  validateEveryNthFrame(everyNthFrame);
@@ -21211,8 +21397,8 @@ var internalRenderMediaRaw = ({
21211
21397
  }
21212
21398
  const imageFormat = isAudioCodec(codec) ? "none" : provisionalImageFormat ?? compositionWithPossibleUnevenDimensions.defaultVideoImageFormat ?? DEFAULT_VIDEO_IMAGE_FORMAT;
21213
21399
  validateSelectedPixelFormatAndImageFormatCombination(pixelFormat, imageFormat);
21214
- const workingDir = fs15.mkdtempSync(path25.join(os6.tmpdir(), "react-motion-render"));
21215
- const preEncodedFileLocation = parallelEncoding ? path25.join(workingDir, "pre-encode." + getFileExtensionFromCodec(codec, audioCodec)) : null;
21400
+ const workingDir = fs16.mkdtempSync(path26.join(os6.tmpdir(), "react-motion-render"));
21401
+ const preEncodedFileLocation = parallelEncoding ? path26.join(workingDir, "pre-encode." + getFileExtensionFromCodec(codec, audioCodec)) : null;
21216
21402
  if (onCtrlCExit && workingDir) {
21217
21403
  onCtrlCExit(`Delete ${workingDir}`, () => deleteDirectory(workingDir));
21218
21404
  }
@@ -21515,10 +21701,10 @@ var internalRenderMediaRaw = ({
21515
21701
  }
21516
21702
  reject(err);
21517
21703
  }).finally(() => {
21518
- if (preEncodedFileLocation !== null && fs15.existsSync(preEncodedFileLocation)) {
21519
- deleteDirectory(path25.dirname(preEncodedFileLocation));
21704
+ if (preEncodedFileLocation !== null && fs16.existsSync(preEncodedFileLocation)) {
21705
+ deleteDirectory(path26.dirname(preEncodedFileLocation));
21520
21706
  }
21521
- if (workingDir && fs15.existsSync(workingDir)) {
21707
+ if (workingDir && fs16.existsSync(workingDir)) {
21522
21708
  deleteDirectory(workingDir);
21523
21709
  }
21524
21710
  cleanupServerFn?.(false).catch((err) => {
@@ -21676,8 +21862,8 @@ var renderMedia = ({
21676
21862
  };
21677
21863
 
21678
21864
  // src/render-still.ts
21679
- import fs16, { statSync as statSync2 } from "node:fs";
21680
- import path26 from "node:path";
21865
+ import fs17, { statSync as statSync2 } from "node:fs";
21866
+ import path27 from "node:path";
21681
21867
  import { NoReactInternals as NoReactInternals15 } from "remotion/no-react";
21682
21868
  var innerRenderStill = async ({
21683
21869
  composition,
@@ -21725,10 +21911,10 @@ var innerRenderStill = async ({
21725
21911
  });
21726
21912
  validatePuppeteerTimeout(timeoutInMilliseconds);
21727
21913
  validateScale(scale);
21728
- output = typeof output === "string" ? path26.resolve(process.cwd(), output) : null;
21914
+ output = typeof output === "string" ? path27.resolve(process.cwd(), output) : null;
21729
21915
  validateJpegQuality(jpegQuality);
21730
21916
  if (output) {
21731
- if (fs16.existsSync(output)) {
21917
+ if (fs17.existsSync(output)) {
21732
21918
  if (!overwrite) {
21733
21919
  throw new Error(`Cannot render still - "overwrite" option was set to false, but the output destination ${output} already exists.`);
21734
21920
  }
@@ -21843,18 +22029,24 @@ var innerRenderStill = async ({
21843
22029
  logLevel,
21844
22030
  attempt: 0
21845
22031
  });
21846
- const { buffer, collectedAssets } = await takeFrame({
21847
- frame: stillFrame,
21848
- freePage: page,
21849
- height: composition.height,
21850
- width: composition.width,
21851
- imageFormat,
21852
- scale,
21853
- output,
21854
- jpegQuality,
21855
- wantsBuffer: !output,
21856
- timeoutInMilliseconds
21857
- });
22032
+ const [buffer, collectedAssets] = await Promise.all([
22033
+ takeFrame({
22034
+ freePage: page,
22035
+ height: composition.height,
22036
+ width: composition.width,
22037
+ imageFormat,
22038
+ scale,
22039
+ output,
22040
+ jpegQuality,
22041
+ wantsBuffer: !output,
22042
+ timeoutInMilliseconds
22043
+ }),
22044
+ collectAssets({
22045
+ frame,
22046
+ freePage: page,
22047
+ timeoutInMilliseconds
22048
+ })
22049
+ ]);
21858
22050
  const artifactAssets = onlyArtifact({
21859
22051
  assets: collectedAssets,
21860
22052
  frameBuffer: buffer