@remotion/renderer 4.0.346 → 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.
@@ -1,6 +1,7 @@
1
1
  import { OffthreadVideoServerEmitter } from '../offthread-video-server';
2
2
  import type { FrameAndAssets } from '../render-frames';
3
3
  import type { RenderMediaOnDownload } from './download-and-map-assets-to-file';
4
+ import { type InlineAudioMixing } from './inline-audio-mixing';
4
5
  export type AudioChannelsAndDurationResultCache = {
5
6
  channels: number;
6
7
  duration: number | null;
@@ -37,6 +38,7 @@ export type DownloadMap = {
37
38
  preventCleanup: () => void;
38
39
  allowCleanup: () => void;
39
40
  isPreventedFromCleanup: () => boolean;
41
+ inlineAudioMixing: InlineAudioMixing;
40
42
  };
41
43
  export type RenderAssetInfo = {
42
44
  assets: FrameAndAssets[];
@@ -48,5 +50,6 @@ export type RenderAssetInfo = {
48
50
  trimRightOffset: number;
49
51
  forSeamlessAacConcatenation: boolean;
50
52
  };
53
+ export declare const makeAndReturn: (dir: string, name: string) => string;
51
54
  export declare const makeDownloadMap: () => DownloadMap;
52
55
  export declare const cleanDownloadMap: (downloadMap: DownloadMap) => void;
@@ -3,18 +3,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.cleanDownloadMap = exports.makeDownloadMap = void 0;
6
+ exports.cleanDownloadMap = exports.makeDownloadMap = exports.makeAndReturn = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const version_1 = require("remotion/version");
10
10
  const delete_directory_1 = require("../delete-directory");
11
11
  const offthread_video_server_1 = require("../offthread-video-server");
12
12
  const tmp_dir_1 = require("../tmp-dir");
13
+ const inline_audio_mixing_1 = require("./inline-audio-mixing");
13
14
  const makeAndReturn = (dir, name) => {
14
15
  const p = node_path_1.default.join(dir, name);
15
16
  (0, node_fs_1.mkdirSync)(p);
16
17
  return p;
17
18
  };
19
+ exports.makeAndReturn = makeAndReturn;
18
20
  const makeDownloadMap = () => {
19
21
  const dir = (0, tmp_dir_1.tmpDir)(`remotion-v${version_1.VERSION}-assets`);
20
22
  let prevented = false;
@@ -26,13 +28,13 @@ const makeDownloadMap = () => {
26
28
  id: String(Math.random()),
27
29
  assetDir: dir,
28
30
  downloadListeners: [],
29
- downloadDir: makeAndReturn(dir, 'remotion-assets-dir'),
30
- complexFilter: makeAndReturn(dir, 'remotion-complex-filter'),
31
- preEncode: makeAndReturn(dir, 'pre-encode'),
32
- audioMixing: makeAndReturn(dir, 'remotion-audio-mixing'),
33
- audioPreprocessing: makeAndReturn(dir, 'remotion-audio-preprocessing'),
34
- stitchFrames: makeAndReturn(dir, 'remotion-stitch-temp-dir'),
35
- compositingDir: makeAndReturn(dir, 'remotion-compositing-temp-dir'),
31
+ downloadDir: (0, exports.makeAndReturn)(dir, 'remotion-assets-dir'),
32
+ complexFilter: (0, exports.makeAndReturn)(dir, 'remotion-complex-filter'),
33
+ preEncode: (0, exports.makeAndReturn)(dir, 'pre-encode'),
34
+ audioMixing: (0, exports.makeAndReturn)(dir, 'remotion-audio-mixing'),
35
+ audioPreprocessing: (0, exports.makeAndReturn)(dir, 'remotion-audio-preprocessing'),
36
+ stitchFrames: (0, exports.makeAndReturn)(dir, 'remotion-stitch-temp-dir'),
37
+ compositingDir: (0, exports.makeAndReturn)(dir, 'remotion-compositing-temp-dir'),
36
38
  emitter: new offthread_video_server_1.OffthreadVideoServerEmitter(),
37
39
  preventCleanup: () => {
38
40
  prevented = true;
@@ -43,6 +45,7 @@ const makeDownloadMap = () => {
43
45
  isPreventedFromCleanup: () => {
44
46
  return prevented;
45
47
  },
48
+ inlineAudioMixing: (0, inline_audio_mixing_1.makeInlineAudioMixing)(dir),
46
49
  };
47
50
  };
48
51
  exports.makeDownloadMap = makeDownloadMap;
@@ -53,6 +56,7 @@ const cleanDownloadMap = (downloadMap) => {
53
56
  (0, delete_directory_1.deleteDirectory)(downloadMap.downloadDir);
54
57
  (0, delete_directory_1.deleteDirectory)(downloadMap.complexFilter);
55
58
  (0, delete_directory_1.deleteDirectory)(downloadMap.compositingDir);
59
+ downloadMap.inlineAudioMixing.cleanup();
56
60
  // Assets dir must be last since the others are contained
57
61
  (0, delete_directory_1.deleteDirectory)(downloadMap.assetDir);
58
62
  };
@@ -1,7 +1,14 @@
1
1
  import type { InlineAudioAsset } from 'remotion/no-react';
2
2
  export declare const makeInlineAudioMixing: (dir: string) => {
3
3
  cleanup: () => void;
4
- addAsset: (asset: InlineAudioAsset, fps: number, totalNumberOfFrames: number) => void;
5
- folder: string;
4
+ addAsset: ({ asset, fps, totalNumberOfFrames, firstFrame, trimLeftOffset, trimRightOffset, }: {
5
+ asset: InlineAudioAsset;
6
+ fps: number;
7
+ totalNumberOfFrames: number;
8
+ firstFrame: number;
9
+ trimLeftOffset: number;
10
+ trimRightOffset: number;
11
+ }) => void;
12
+ getListOfAssets: () => string[];
6
13
  };
7
14
  export type InlineAudioMixing = ReturnType<typeof makeInlineAudioMixing>;
@@ -59,25 +59,38 @@ const makeInlineAudioMixing = (dir) => {
59
59
  const folderToAdd = (0, download_map_1.makeAndReturn)(dir, 'remotion-inline-audio-mixing');
60
60
  // asset id -> file descriptor
61
61
  const openFiles = {};
62
+ const writtenHeaders = {};
62
63
  const cleanup = () => {
63
64
  for (const fd of Object.values(openFiles)) {
64
- node_fs_1.default.closeSync(fd);
65
+ try {
66
+ node_fs_1.default.closeSync(fd);
67
+ }
68
+ catch (_a) { }
65
69
  }
66
70
  (0, delete_directory_1.deleteDirectory)(folderToAdd);
67
71
  };
68
- const ensureAsset = (asset, fps, totalNumberOfFrames) => {
69
- const filePath = node_path_1.default.join(folderToAdd, `${asset.id}.wav`);
70
- if (!openFiles[asset.id]) {
71
- openFiles[asset.id] = node_fs_1.default.openSync(filePath, 'w');
72
+ const getListOfAssets = () => {
73
+ return Object.keys(openFiles);
74
+ };
75
+ const getFilePath = (asset) => {
76
+ return node_path_1.default.join(folderToAdd, `${asset.id}.wav`);
77
+ };
78
+ const ensureAsset = ({ asset, fps, totalNumberOfFrames, trimLeftOffset, trimRightOffset, }) => {
79
+ const filePath = getFilePath(asset);
80
+ if (!openFiles[filePath]) {
81
+ openFiles[filePath] = node_fs_1.default.openSync(filePath, 'w');
82
+ }
83
+ if (writtenHeaders[filePath]) {
84
+ return;
72
85
  }
73
- const expectedDataSize = Math.round((totalNumberOfFrames / fps) *
86
+ writtenHeaders[filePath] = true;
87
+ const expectedDataSize = Math.round((totalNumberOfFrames / fps - trimLeftOffset + trimRightOffset) *
74
88
  asset.numberOfChannels *
75
89
  sample_rate_1.DEFAULT_SAMPLE_RATE *
76
90
  BYTES_PER_SAMPLE);
77
- console.log({ totalNumberOfFrames, fps });
78
91
  const expectedSize = 40 + expectedDataSize;
79
92
  const { numberOfChannels } = asset;
80
- const fd = openFiles[asset.id];
93
+ const fd = openFiles[filePath];
81
94
  (0, node_fs_1.writeSync)(fd, new Uint8Array([0x52, 0x49, 0x46, 0x46]), 0, 4, 0); // "RIFF"
82
95
  (0, node_fs_1.writeSync)(fd, new Uint8Array(numberTo32BiIntLittleEndian(expectedSize)), 0, 4, 4); // Remaining size
83
96
  (0, node_fs_1.writeSync)(fd, new Uint8Array([0x57, 0x41, 0x56, 0x45]), 0, 4, 8); // "WAVE"
@@ -92,34 +105,56 @@ const makeInlineAudioMixing = (dir) => {
92
105
  (0, node_fs_1.writeSync)(fd, new Uint8Array([0x64, 0x61, 0x74, 0x61]), 0, 4, 36); // "data"
93
106
  (0, node_fs_1.writeSync)(fd, new Uint8Array(numberTo32BiIntLittleEndian(expectedDataSize)), 0, 4, 40); // Remaining size
94
107
  };
95
- const addAsset = (asset, fps, totalNumberOfFrames) => {
96
- ensureAsset(asset, fps, totalNumberOfFrames);
97
- const fileDescriptor = openFiles[asset.id];
98
- const arr = new Int16Array(asset.audio);
108
+ const addAsset = ({ asset, fps, totalNumberOfFrames, firstFrame, trimLeftOffset, trimRightOffset, }) => {
109
+ ensureAsset({
110
+ asset,
111
+ fps,
112
+ totalNumberOfFrames,
113
+ trimLeftOffset,
114
+ trimRightOffset,
115
+ });
116
+ const filePath = getFilePath(asset);
117
+ const fileDescriptor = openFiles[filePath];
118
+ let arr = new Int16Array(asset.audio);
119
+ const isFirst = asset.frame === firstFrame;
120
+ const isLast = asset.frame === totalNumberOfFrames + firstFrame - 1;
121
+ const samplesToShaveFromStart = trimLeftOffset * sample_rate_1.DEFAULT_SAMPLE_RATE;
122
+ const samplesToShaveFromEnd = trimRightOffset * sample_rate_1.DEFAULT_SAMPLE_RATE;
123
+ if (Math.abs(Math.round(samplesToShaveFromEnd) - samplesToShaveFromEnd) >
124
+ 0.00000001) {
125
+ throw new Error('samplesToShaveFromEnd should be approximately an integer');
126
+ }
127
+ if (Math.abs(Math.round(samplesToShaveFromStart) - samplesToShaveFromStart) >
128
+ 0.00000001) {
129
+ throw new Error('samplesToShaveFromStart should be approximately an integer');
130
+ }
131
+ if (isFirst) {
132
+ arr = arr.slice(Math.round(samplesToShaveFromStart) * asset.numberOfChannels);
133
+ }
134
+ if (isLast) {
135
+ arr = arr.slice(0, arr.length + Math.round(samplesToShaveFromEnd) * asset.numberOfChannels);
136
+ }
137
+ const positionInSeconds = (asset.frame - firstFrame) / fps - (isFirst ? 0 : trimLeftOffset);
138
+ const position = Math.round(positionInSeconds *
139
+ asset.numberOfChannels *
140
+ sample_rate_1.DEFAULT_SAMPLE_RATE *
141
+ BYTES_PER_SAMPLE);
99
142
  (0, node_fs_1.writeSync)(
100
143
  // fs
101
144
  fileDescriptor,
102
145
  // data
103
146
  arr,
104
- // offset of dats
147
+ // offset of data
105
148
  0,
106
149
  // length
107
150
  arr.byteLength,
108
151
  // position
109
- 44 +
110
- Math.round((asset.frame / fps) *
111
- asset.numberOfChannels *
112
- sample_rate_1.DEFAULT_SAMPLE_RATE *
113
- BYTES_PER_SAMPLE));
114
- console.log('wrote', arr.byteLength, 'bytes to', node_path_1.default.join(folderToAdd, `${asset.id}.wav`), Math.round((asset.frame / fps) *
115
- asset.numberOfChannels *
116
- sample_rate_1.DEFAULT_SAMPLE_RATE *
117
- BYTES_PER_SAMPLE));
152
+ 44 + position);
118
153
  };
119
154
  return {
120
155
  cleanup,
121
156
  addAsset,
122
- folder: folderToAdd,
157
+ getListOfAssets,
123
158
  };
124
159
  };
125
160
  exports.makeInlineAudioMixing = makeInlineAudioMixing;
@@ -4,4 +4,4 @@ export declare const collectAssets: ({ frame, freePage, timeoutInMilliseconds, }
4
4
  frame: number;
5
5
  freePage: Page;
6
6
  timeoutInMilliseconds: number;
7
- }) => Promise<(import("remotion/no-react").AudioOrVideoAsset | ArtifactAsset)[]>;
7
+ }) => Promise<(import("remotion/no-react").InlineAudioAsset | import("remotion/no-react").AudioOrVideoAsset | ArtifactAsset)[]>;
@@ -64,7 +64,18 @@ const createAudio = async ({ assets, onDownload, fps, logLevel, onProgress, down
64
64
  updateProgress();
65
65
  return result;
66
66
  }));
67
- const preprocessed = audioTracks.filter(truthy_1.truthy);
67
+ const inlinedAudio = downloadMap.inlineAudioMixing.getListOfAssets();
68
+ const preprocessed = [
69
+ ...audioTracks.filter(truthy_1.truthy),
70
+ ...inlinedAudio.map((asset) => ({
71
+ outName: asset,
72
+ filter: {
73
+ filter: null,
74
+ pad_start: null,
75
+ pad_end: null,
76
+ },
77
+ })),
78
+ ];
68
79
  const merged = path_1.default.join(downloadMap.audioPreprocessing, 'merged.wav');
69
80
  const extension = (0, audio_codec_1.getExtensionFromAudioCodec)(audioCodec);
70
81
  const outName = path_1.default.join(downloadMap.audioPreprocessing, `audio.${extension}`);