@remotion/renderer 4.0.516 → 4.0.517
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/assets/inline-audio-mixing.d.ts +6 -1
- package/dist/assets/inline-audio-mixing.js +42 -39
- package/dist/combine-chunks.js +0 -15
- package/dist/create-audio.js +22 -8
- package/dist/esm/index.mjs +295 -99
- package/dist/ffmpeg-args.js +1 -0
- package/dist/finalize-fast-start.d.ts +12 -0
- package/dist/finalize-fast-start.js +70 -0
- package/dist/get-codec-name.d.ts +3 -1
- package/dist/get-codec-name.js +11 -2
- package/dist/get-fast-start-muxer.d.ts +2 -0
- package/dist/get-fast-start-muxer.js +11 -0
- package/dist/merge-inline-audio-tracks.d.ts +21 -0
- package/dist/merge-inline-audio-tracks.js +74 -0
- package/dist/mux-video-and-audio.d.ts +1 -2
- package/dist/mux-video-and-audio.js +9 -3
- package/dist/prespawn-ffmpeg.d.ts +2 -0
- package/dist/prespawn-ffmpeg.js +1 -0
- package/dist/probe-encoder.d.ts +3 -1
- package/dist/probe-encoder.js +10 -1
- package/dist/render-media.js +2 -0
- package/dist/stitch-frames-to-video.d.ts +2 -0
- package/dist/stitch-frames-to-video.js +51 -30
- package/package.json +13 -13
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { InlineAudioAsset } from 'remotion/no-react';
|
|
2
2
|
import type { CancelSignal } from '../make-cancel-signal';
|
|
3
|
+
export type InlineAudioTrack = {
|
|
4
|
+
outName: string;
|
|
5
|
+
startInSamples: number;
|
|
6
|
+
durationInSamples: number;
|
|
7
|
+
};
|
|
3
8
|
export declare const makeInlineAudioMixing: (dir: string, sampleRate: number) => {
|
|
4
9
|
cleanup: () => void;
|
|
5
10
|
addAsset: ({ asset, fps, totalNumberOfFrames, firstFrame, trimLeftOffset, trimRightOffset, }: {
|
|
@@ -10,7 +15,7 @@ export declare const makeInlineAudioMixing: (dir: string, sampleRate: number) =>
|
|
|
10
15
|
trimLeftOffset: number;
|
|
11
16
|
trimRightOffset: number;
|
|
12
17
|
}) => void;
|
|
13
|
-
getListOfAssets: () =>
|
|
18
|
+
getListOfAssets: () => InlineAudioTrack[];
|
|
14
19
|
finish: ({ binariesDirectory, indent, logLevel, cancelSignal, sampleRate: finishSampleRate, }: {
|
|
15
20
|
indent: boolean;
|
|
16
21
|
logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
@@ -69,12 +69,14 @@ const correctFloatingPointError = (value) => {
|
|
|
69
69
|
const BIT_DEPTH = 16;
|
|
70
70
|
const BYTES_PER_SAMPLE = BIT_DEPTH / 8;
|
|
71
71
|
const NUMBER_OF_CHANNELS = 2;
|
|
72
|
+
const WAV_HEADER_SIZE = 44;
|
|
72
73
|
const makeInlineAudioMixing = (dir, sampleRate) => {
|
|
73
74
|
const folderToAdd = (0, download_map_1.makeAndReturn)(dir, 'remotion-inline-audio-mixing');
|
|
74
|
-
// asset id -> file descriptor
|
|
75
75
|
const openFiles = {};
|
|
76
76
|
const writtenHeaders = {};
|
|
77
77
|
const toneFrequencies = {};
|
|
78
|
+
const startTimesInSamples = {};
|
|
79
|
+
const writtenDataSizes = {};
|
|
78
80
|
const cleanup = () => {
|
|
79
81
|
for (const fileName of Object.keys(openFiles)) {
|
|
80
82
|
try {
|
|
@@ -86,42 +88,51 @@ const makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
86
88
|
(0, delete_directory_1.deleteDirectory)(folderToAdd);
|
|
87
89
|
};
|
|
88
90
|
const getListOfAssets = () => {
|
|
89
|
-
return Object.keys(
|
|
91
|
+
return Object.keys(writtenHeaders)
|
|
92
|
+
.map((outName) => ({
|
|
93
|
+
outName,
|
|
94
|
+
startInSamples: startTimesInSamples[outName],
|
|
95
|
+
durationInSamples: writtenDataSizes[outName] / (NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE),
|
|
96
|
+
}))
|
|
97
|
+
.sort((a, b) => a.startInSamples - b.startInSamples);
|
|
90
98
|
};
|
|
91
99
|
const getFilePath = (asset) => {
|
|
92
100
|
return node_path_1.default.join(folderToAdd, `${asset.id}.wav`);
|
|
93
101
|
};
|
|
94
|
-
const ensureAsset = (
|
|
102
|
+
const ensureAsset = (asset) => {
|
|
95
103
|
const filePath = getFilePath(asset);
|
|
96
|
-
if (
|
|
104
|
+
if (openFiles[filePath] === undefined) {
|
|
97
105
|
openFiles[filePath] = node_fs_1.default.openSync(filePath, 'w');
|
|
98
106
|
}
|
|
99
107
|
if (writtenHeaders[filePath]) {
|
|
100
108
|
return;
|
|
101
109
|
}
|
|
102
110
|
writtenHeaders[filePath] = true;
|
|
103
|
-
|
|
104
|
-
NUMBER_OF_CHANNELS *
|
|
105
|
-
sampleRate *
|
|
106
|
-
BYTES_PER_SAMPLE);
|
|
107
|
-
const expectedSize = 40 + expectedDataSize;
|
|
111
|
+
writtenDataSizes[filePath] = 0;
|
|
108
112
|
const fd = openFiles[filePath];
|
|
109
113
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([0x52, 0x49, 0x46, 0x46]), 0, 4, 0); // "RIFF"
|
|
110
|
-
(0, node_fs_1.writeSync)(fd,
|
|
114
|
+
(0, node_fs_1.writeSync)(fd, numberTo32BiIntLittleEndian(36), 0, 4, 4); // Remaining size
|
|
111
115
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([0x57, 0x41, 0x56, 0x45]), 0, 4, 8); // "WAVE"
|
|
112
116
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([0x66, 0x6d, 0x74, 0x20]), 0, 4, 12); // "fmt "
|
|
113
117
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([BIT_DEPTH, 0x00, 0x00, 0x00]), 0, 4, 16); // fmt chunk size = 16
|
|
114
118
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([0x01, 0x00]), 0, 2, 20); // Audio format (PCM) = 1, set 3 if float32 would be true
|
|
115
119
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([NUMBER_OF_CHANNELS, 0x00]), 0, 2, 22); // Number of channels
|
|
116
|
-
(0, node_fs_1.writeSync)(fd,
|
|
117
|
-
(0, node_fs_1.writeSync)(fd,
|
|
118
|
-
(0, node_fs_1.writeSync)(fd,
|
|
120
|
+
(0, node_fs_1.writeSync)(fd, numberTo32BiIntLittleEndian(sampleRate), 0, 4, 24); // Sample rate
|
|
121
|
+
(0, node_fs_1.writeSync)(fd, numberTo32BiIntLittleEndian(sampleRate * NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE), 0, 4, 28); // Byte rate
|
|
122
|
+
(0, node_fs_1.writeSync)(fd, numberTo16BitLittleEndian(NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE), 0, 2, 32); // Block align
|
|
119
123
|
(0, node_fs_1.writeSync)(fd, numberTo16BitLittleEndian(BIT_DEPTH), 0, 2, 34); // Bits per sample
|
|
120
124
|
(0, node_fs_1.writeSync)(fd, new Uint8Array([0x64, 0x61, 0x74, 0x61]), 0, 4, 36); // "data"
|
|
121
|
-
(0, node_fs_1.writeSync)(fd,
|
|
125
|
+
(0, node_fs_1.writeSync)(fd, numberTo32BiIntLittleEndian(0), 0, 4, 40); // Data size
|
|
122
126
|
};
|
|
123
127
|
const finish = async ({ binariesDirectory, indent, logLevel, cancelSignal, sampleRate: finishSampleRate, }) => {
|
|
124
|
-
for (const fileName of Object.keys(
|
|
128
|
+
for (const fileName of Object.keys(writtenHeaders)) {
|
|
129
|
+
const fd = openFiles[fileName];
|
|
130
|
+
const dataSize = Math.max(0, node_fs_1.default.fstatSync(fd).size - WAV_HEADER_SIZE);
|
|
131
|
+
writtenDataSizes[fileName] = dataSize;
|
|
132
|
+
(0, node_fs_1.writeSync)(fd, numberTo32BiIntLittleEndian(36 + dataSize), 0, 4, 4);
|
|
133
|
+
(0, node_fs_1.writeSync)(fd, numberTo32BiIntLittleEndian(dataSize), 0, 4, 40);
|
|
134
|
+
node_fs_1.default.closeSync(fd);
|
|
135
|
+
delete openFiles[fileName];
|
|
125
136
|
const frequency = toneFrequencies[fileName];
|
|
126
137
|
if (frequency === 1) {
|
|
127
138
|
continue;
|
|
@@ -137,21 +148,12 @@ const makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
137
148
|
cancelSignal,
|
|
138
149
|
sampleRate: finishSampleRate,
|
|
139
150
|
});
|
|
140
|
-
try {
|
|
141
|
-
node_fs_1.default.closeSync(openFiles[fileName]);
|
|
142
|
-
}
|
|
143
|
-
catch (_a) { }
|
|
144
151
|
node_fs_1.default.renameSync(tmpFile, fileName);
|
|
145
152
|
}
|
|
146
153
|
};
|
|
147
154
|
const addAsset = ({ asset, fps, totalNumberOfFrames, firstFrame, trimLeftOffset, trimRightOffset, }) => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
fps,
|
|
151
|
-
totalNumberOfFrames,
|
|
152
|
-
trimLeftOffset,
|
|
153
|
-
trimRightOffset,
|
|
154
|
-
});
|
|
155
|
+
var _a;
|
|
156
|
+
ensureAsset(asset);
|
|
155
157
|
const filePath = getFilePath(asset);
|
|
156
158
|
if (toneFrequencies[filePath] !== undefined &&
|
|
157
159
|
toneFrequencies[filePath] !== asset.toneFrequency) {
|
|
@@ -159,6 +161,15 @@ const makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
159
161
|
}
|
|
160
162
|
const fileDescriptor = openFiles[filePath];
|
|
161
163
|
toneFrequencies[filePath] = asset.toneFrequency;
|
|
164
|
+
const assetStartInVideo = (_a = asset.startInVideo) !== null && _a !== void 0 ? _a : firstFrame;
|
|
165
|
+
const firstFrameForAsset = Math.max(assetStartInVideo, firstFrame);
|
|
166
|
+
const startInSamples = Math.max(0, Math.floor(correctFloatingPointError(((firstFrameForAsset - firstFrame) / fps - trimLeftOffset) *
|
|
167
|
+
sampleRate)));
|
|
168
|
+
if (startTimesInSamples[filePath] !== undefined &&
|
|
169
|
+
startTimesInSamples[filePath] !== startInSamples) {
|
|
170
|
+
throw new Error(`The start time for inline audio asset ${asset.id} changed from ${startTimesInSamples[filePath]} to ${startInSamples} samples`);
|
|
171
|
+
}
|
|
172
|
+
startTimesInSamples[filePath] = startInSamples;
|
|
162
173
|
let arr = new Int16Array(asset.audio);
|
|
163
174
|
const isFirst = asset.frame === firstFrame;
|
|
164
175
|
const isLast = asset.frame === totalNumberOfFrames + firstFrame - 1;
|
|
@@ -176,25 +187,17 @@ const makeInlineAudioMixing = (dir, sampleRate) => {
|
|
|
176
187
|
Math.ceil(correctFloatingPointError(samplesToShaveFromEnd)) *
|
|
177
188
|
NUMBER_OF_CHANNELS);
|
|
178
189
|
}
|
|
179
|
-
const
|
|
190
|
+
const positionInRenderInSeconds = (asset.frame - firstFrame) / fps - (isFirst ? 0 : trimLeftOffset);
|
|
180
191
|
// Always rounding down to ensure there are no gaps when the samples don't align
|
|
181
192
|
// In @remotion/media, we also round down the sample start timestamp and round up the end timestamp
|
|
182
193
|
// This might lead to overlapping, hopefully aligning perfectly!
|
|
183
194
|
// Test case: https://github.com/remotion-dev/remotion/issues/5758
|
|
184
|
-
const position = Math.floor(correctFloatingPointError(
|
|
195
|
+
const position = (Math.floor(correctFloatingPointError(positionInRenderInSeconds * sampleRate)) -
|
|
196
|
+
startInSamples) *
|
|
185
197
|
NUMBER_OF_CHANNELS *
|
|
186
198
|
BYTES_PER_SAMPLE;
|
|
187
|
-
(0, node_fs_1.writeSync)(
|
|
188
|
-
|
|
189
|
-
fileDescriptor,
|
|
190
|
-
// data
|
|
191
|
-
arr,
|
|
192
|
-
// offset of data
|
|
193
|
-
0,
|
|
194
|
-
// length
|
|
195
|
-
arr.byteLength,
|
|
196
|
-
// position
|
|
197
|
-
44 + position);
|
|
199
|
+
(0, node_fs_1.writeSync)(fileDescriptor, arr, 0, arr.byteLength, WAV_HEADER_SIZE + position);
|
|
200
|
+
writtenDataSizes[filePath] = Math.max(writtenDataSizes[filePath], position + arr.byteLength);
|
|
198
201
|
};
|
|
199
202
|
return {
|
|
200
203
|
cleanup,
|
package/dist/combine-chunks.js
CHANGED
|
@@ -18,20 +18,6 @@ const audio_codec_1 = require("./options/audio-codec");
|
|
|
18
18
|
const tmp_dir_1 = require("./tmp-dir");
|
|
19
19
|
const truthy_1 = require("./truthy");
|
|
20
20
|
const validate_number_of_gif_loops_1 = require("./validate-number-of-gif-loops");
|
|
21
|
-
const codecSupportsFastStart = {
|
|
22
|
-
'h264-mkv': false,
|
|
23
|
-
'h264-ts': false,
|
|
24
|
-
h264: true,
|
|
25
|
-
h265: true,
|
|
26
|
-
av1: true,
|
|
27
|
-
aac: false,
|
|
28
|
-
gif: false,
|
|
29
|
-
mp3: false,
|
|
30
|
-
prores: false,
|
|
31
|
-
vp8: false,
|
|
32
|
-
vp9: false,
|
|
33
|
-
wav: false,
|
|
34
|
-
};
|
|
35
21
|
const REMOTION_FILELIST_TOKEN = 'remotion-filelist';
|
|
36
22
|
const internalCombineChunks = async ({ outputLocation: output, onProgress, codec, fps, numberOfGifLoops, audioBitrate, indent, logLevel, binariesDirectory, cancelSignal, metadata, audioFiles, videoFiles, framesPerChunk, audioCodec, preferLossless, everyNthFrame, frameRange, compositionDurationInFrames, sampleRate, }) => {
|
|
37
23
|
(0, validate_number_of_gif_loops_1.validateNumberOfGifLoops)(numberOfGifLoops, codec);
|
|
@@ -136,7 +122,6 @@ const internalCombineChunks = async ({ outputLocation: output, onProgress, codec
|
|
|
136
122
|
binariesDirectory,
|
|
137
123
|
fps,
|
|
138
124
|
cancelSignal,
|
|
139
|
-
addFaststart: codecSupportsFastStart[codec],
|
|
140
125
|
metadata,
|
|
141
126
|
numberOfGifLoops,
|
|
142
127
|
});
|
package/dist/create-audio.js
CHANGED
|
@@ -12,6 +12,7 @@ const compress_audio_1 = require("./compress-audio");
|
|
|
12
12
|
const delete_directory_1 = require("./delete-directory");
|
|
13
13
|
const logger_1 = require("./logger");
|
|
14
14
|
const merge_audio_track_1 = require("./merge-audio-track");
|
|
15
|
+
const merge_inline_audio_tracks_1 = require("./merge-inline-audio-tracks");
|
|
15
16
|
const audio_codec_1 = require("./options/audio-codec");
|
|
16
17
|
const preprocess_audio_track_1 = require("./preprocess-audio-track");
|
|
17
18
|
const truthy_1 = require("./truthy");
|
|
@@ -73,16 +74,29 @@ const createAudio = async ({ assets, onDownload, fps, logLevel, onProgress, down
|
|
|
73
74
|
sampleRate,
|
|
74
75
|
});
|
|
75
76
|
const inlinedAudio = downloadMap.inlineAudioMixing.getListOfAssets();
|
|
77
|
+
const mergedInlineAudio = await (0, merge_inline_audio_tracks_1.mergeInlineAudioTracks)({
|
|
78
|
+
tracks: inlinedAudio,
|
|
79
|
+
downloadMap,
|
|
80
|
+
remotionRoot,
|
|
81
|
+
indent,
|
|
82
|
+
logLevel,
|
|
83
|
+
binariesDirectory,
|
|
84
|
+
cancelSignal,
|
|
85
|
+
fps,
|
|
86
|
+
chunkLengthInSeconds,
|
|
87
|
+
sampleRate,
|
|
88
|
+
});
|
|
76
89
|
const preprocessed = [
|
|
77
90
|
...audioTracks.filter(truthy_1.truthy),
|
|
78
|
-
...
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
...(mergedInlineAudio
|
|
92
|
+
? [
|
|
93
|
+
(0, merge_inline_audio_tracks_1.inlineAudioTrackToPreprocessedAudioTrack)({
|
|
94
|
+
track: mergedInlineAudio,
|
|
95
|
+
relativeToInSamples: 0,
|
|
96
|
+
padToDurationInSamples: Math.round(chunkLengthInSeconds * sampleRate),
|
|
97
|
+
}),
|
|
98
|
+
]
|
|
99
|
+
: []),
|
|
86
100
|
];
|
|
87
101
|
const merged = path_1.default.join(downloadMap.audioPreprocessing, 'merged.wav');
|
|
88
102
|
const extension = (0, audio_codec_1.getExtensionFromAudioCodec)(audioCodec);
|