@remotion/renderer 3.3.1 → 3.3.2

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 (34) hide show
  1. package/dist/assets/download-map.d.ts +3 -2
  2. package/dist/assets/get-video-stream-duration.d.ts +5 -0
  3. package/dist/assets/get-video-stream-duration.js +17 -6
  4. package/dist/assets/read-file.js +2 -4
  5. package/dist/determine-resize-params.d.ts +4 -0
  6. package/dist/determine-resize-params.js +10 -0
  7. package/dist/determine-vcodec-ffmepg-flags.d.ts +2 -0
  8. package/dist/determine-vcodec-ffmepg-flags.js +13 -0
  9. package/dist/ensure-presentation-timestamp.d.ts +6 -0
  10. package/dist/ensure-presentation-timestamp.js +25 -15
  11. package/dist/extract-frame-from-video.d.ts +0 -1
  12. package/dist/extract-frame-from-video.js +18 -117
  13. package/dist/get-can-extract-frames-fast.d.ts +10 -0
  14. package/dist/get-can-extract-frames-fast.js +67 -0
  15. package/dist/get-extension-from-codec.d.ts +1 -1
  16. package/dist/get-frame-of-video-slow.d.ts +17 -0
  17. package/dist/get-frame-of-video-slow.js +72 -0
  18. package/dist/get-video-info.d.ts +5 -0
  19. package/dist/get-video-info.js +15 -6
  20. package/dist/guess-extension-for-media.d.ts +1 -1
  21. package/dist/index.d.ts +3 -2
  22. package/dist/index.js +3 -1
  23. package/dist/last-frame-from-video-cache.d.ts +0 -1
  24. package/dist/provide-screenshot.d.ts +0 -1
  25. package/dist/puppeteer-screenshot.d.ts +0 -1
  26. package/dist/redirect-status-codes.d.ts +1 -0
  27. package/dist/redirect-status-codes.js +4 -0
  28. package/dist/render-media.d.ts +0 -1
  29. package/dist/screenshot-dom-element.d.ts +0 -1
  30. package/dist/screenshot-task.d.ts +0 -1
  31. package/dist/set-props-and-env.js +2 -7
  32. package/dist/try-to-extract-frame-of-video-fast.d.ts +12 -0
  33. package/dist/try-to-extract-frame-of-video-fast.js +55 -0
  34. package/package.json +3 -3
@@ -7,9 +7,10 @@ declare type EncodingStatus = {
7
7
  src: string;
8
8
  } | undefined;
9
9
  export declare type SpecialVCodecForTransparency = 'vp9' | 'vp8' | 'none';
10
+ export declare type NeedsResize = [number, number] | null;
10
11
  export declare type Vp9Result = {
11
- specialVcodec: SpecialVCodecForTransparency;
12
- needsResize: [number, number] | null;
12
+ specialVcodecForTransparency: SpecialVCodecForTransparency;
13
+ needsResize: NeedsResize;
13
14
  };
14
15
  export declare type VideoDurationResult = {
15
16
  duration: number | null;
@@ -1,4 +1,9 @@
1
1
  import type { FfmpegExecutable } from '../ffmpeg-executable';
2
2
  import type { DownloadMap, VideoDurationResult } from './download-map';
3
3
  export declare const parseVideoStreamDuration: (stdout: string) => VideoDurationResult;
4
+ export declare function getVideoStreamDurationwithoutCache({ src, ffprobeExecutable, remotionRoot, }: {
5
+ src: string;
6
+ ffprobeExecutable: FfmpegExecutable;
7
+ remotionRoot: string;
8
+ }): Promise<VideoDurationResult>;
4
9
  export declare const getVideoStreamDuration: (downloadMap: DownloadMap, src: string, ffprobeExecutable: FfmpegExecutable, remotionRoot: string) => Promise<VideoDurationResult>;
@@ -3,7 +3,7 @@ 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.getVideoStreamDuration = exports.parseVideoStreamDuration = void 0;
6
+ exports.getVideoStreamDuration = exports.getVideoStreamDurationwithoutCache = exports.parseVideoStreamDuration = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const ffmpeg_flags_1 = require("../ffmpeg-flags");
9
9
  const p_limit_1 = require("../p-limit");
@@ -39,10 +39,7 @@ const parseVideoStreamDuration = (stdout) => {
39
39
  return result;
40
40
  };
41
41
  exports.parseVideoStreamDuration = parseVideoStreamDuration;
42
- async function getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot) {
43
- if (downloadMap.videoDurationResultCache[src]) {
44
- return downloadMap.videoDurationResultCache[src];
45
- }
42
+ async function getVideoStreamDurationwithoutCache({ src, ffprobeExecutable, remotionRoot, }) {
46
43
  const args = [
47
44
  ['-v', 'error'],
48
45
  ['-select_streams', 'v:0'],
@@ -52,7 +49,21 @@ async function getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutab
52
49
  .reduce((acc, val) => acc.concat(val), [])
53
50
  .filter(Boolean);
54
51
  const task = await (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffprobeExecutable, remotionRoot, 'ffprobe'), args);
55
- return (0, exports.parseVideoStreamDuration)(task.stdout);
52
+ const result = (0, exports.parseVideoStreamDuration)(task.stdout);
53
+ return result;
54
+ }
55
+ exports.getVideoStreamDurationwithoutCache = getVideoStreamDurationwithoutCache;
56
+ async function getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot) {
57
+ if (downloadMap.videoDurationResultCache[src]) {
58
+ return downloadMap.videoDurationResultCache[src];
59
+ }
60
+ const result = await getVideoStreamDurationwithoutCache({
61
+ src,
62
+ ffprobeExecutable,
63
+ remotionRoot,
64
+ });
65
+ downloadMap.videoDurationResultCache[src] = result;
66
+ return result;
56
67
  }
57
68
  const getVideoStreamDuration = (downloadMap, src, ffprobeExecutable, remotionRoot) => {
58
69
  return limit(() => getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot));
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.readFile = void 0;
7
7
  const http_1 = __importDefault(require("http"));
8
8
  const https_1 = __importDefault(require("https"));
9
+ const redirect_status_codes_1 = require("../redirect-status-codes");
9
10
  const getClient = (url) => {
10
11
  if (url.startsWith('https://')) {
11
12
  return https_1.default.get;
@@ -29,10 +30,7 @@ const readFile = async (url, redirectsSoFar = 0) => {
29
30
  throw new Error(`Too many redirects while downloading ${url}`);
30
31
  }
31
32
  const file = await readFileWithoutRedirect(url);
32
- if (file.statusCode === 302 ||
33
- file.statusCode === 301 ||
34
- file.statusCode === 307 ||
35
- file.statusCode === 308) {
33
+ if (redirect_status_codes_1.redirectStatusCodes.includes(file.statusCode)) {
36
34
  if (!file.headers.location) {
37
35
  throw new Error(`Received a status code ${file.statusCode} but no "Location" header while calling ${file.headers.location}`);
38
36
  }
@@ -0,0 +1,4 @@
1
+ export declare const determineResizeParams: (needsResize: [
2
+ number,
3
+ number
4
+ ] | null) => string[];
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.determineResizeParams = void 0;
4
+ const determineResizeParams = (needsResize) => {
5
+ if (needsResize === null) {
6
+ return [];
7
+ }
8
+ return ['-s', `${needsResize[0]}x${needsResize[1]}`];
9
+ };
10
+ exports.determineResizeParams = determineResizeParams;
@@ -0,0 +1,2 @@
1
+ import type { SpecialVCodecForTransparency } from './assets/download-map';
2
+ export declare const determineVcodecFfmepgFlags: (vcodecFlag: SpecialVCodecForTransparency) => string[];
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.determineVcodecFfmepgFlags = void 0;
4
+ const truthy_1 = require("./truthy");
5
+ const determineVcodecFfmepgFlags = (vcodecFlag) => {
6
+ return [
7
+ vcodecFlag === 'vp9' ? '-vcodec' : null,
8
+ vcodecFlag === 'vp9' ? 'libvpx-vp9' : null,
9
+ vcodecFlag === 'vp8' ? '-vcodec' : null,
10
+ vcodecFlag === 'vp8' ? 'libvpx' : null,
11
+ ].filter(truthy_1.truthy);
12
+ };
13
+ exports.determineVcodecFfmepgFlags = determineVcodecFfmepgFlags;
@@ -1,5 +1,11 @@
1
1
  import type { DownloadMap } from './assets/download-map';
2
2
  import type { FfmpegExecutable } from './ffmpeg-executable';
3
+ export declare const ensurePresentationTimestampWithoutCache: ({ src, remotionRoot, ffmpegExecutable, ffprobeExecutable, }: {
4
+ src: string;
5
+ remotionRoot: string;
6
+ ffmpegExecutable: FfmpegExecutable;
7
+ ffprobeExecutable: FfmpegExecutable;
8
+ }) => Promise<string>;
3
9
  export declare const ensurePresentationTimestamps: ({ downloadMap, src, remotionRoot, ffmpegExecutable, ffprobeExecutable, }: {
4
10
  downloadMap: DownloadMap;
5
11
  src: string;
@@ -3,7 +3,7 @@ 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.ensurePresentationTimestamps = void 0;
6
+ exports.ensurePresentationTimestamps = exports.ensurePresentationTimestampWithoutCache = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const ffmpeg_flags_1 = require("./ffmpeg-flags");
@@ -30,20 +30,7 @@ const getTemporaryOutputName = async ({ src, remotionRoot, ffprobeBinary, }) =>
30
30
  })
31
31
  .join(path_1.default.sep);
32
32
  };
33
- const ensurePresentationTimestamps = async ({ downloadMap, src, remotionRoot, ffmpegExecutable, ffprobeExecutable, }) => {
34
- const elem = downloadMap.ensureFileHasPresentationTimestamp[src];
35
- if ((elem === null || elem === void 0 ? void 0 : elem.type) === 'encoding') {
36
- return new Promise((resolve) => {
37
- callbacks.push({
38
- src,
39
- fn: (newSrc) => resolve(newSrc),
40
- });
41
- });
42
- }
43
- if ((elem === null || elem === void 0 ? void 0 : elem.type) === 'done') {
44
- return elem.src;
45
- }
46
- downloadMap.ensureFileHasPresentationTimestamp[src] = { type: 'encoding' };
33
+ const ensurePresentationTimestampWithoutCache = async ({ src, remotionRoot, ffmpegExecutable, ffprobeExecutable, }) => {
47
34
  // If there is no file extension for the video, then we need to tempoa
48
35
  const output = await getTemporaryOutputName({
49
36
  src,
@@ -62,6 +49,29 @@ const ensurePresentationTimestamps = async ({ downloadMap, src, remotionRoot, ff
62
49
  output,
63
50
  '-y',
64
51
  ]);
52
+ return output;
53
+ };
54
+ exports.ensurePresentationTimestampWithoutCache = ensurePresentationTimestampWithoutCache;
55
+ const ensurePresentationTimestamps = async ({ downloadMap, src, remotionRoot, ffmpegExecutable, ffprobeExecutable, }) => {
56
+ const elem = downloadMap.ensureFileHasPresentationTimestamp[src];
57
+ if ((elem === null || elem === void 0 ? void 0 : elem.type) === 'encoding') {
58
+ return new Promise((resolve) => {
59
+ callbacks.push({
60
+ src,
61
+ fn: (newSrc) => resolve(newSrc),
62
+ });
63
+ });
64
+ }
65
+ if ((elem === null || elem === void 0 ? void 0 : elem.type) === 'done') {
66
+ return elem.src;
67
+ }
68
+ downloadMap.ensureFileHasPresentationTimestamp[src] = { type: 'encoding' };
69
+ const output = await (0, exports.ensurePresentationTimestampWithoutCache)({
70
+ ffmpegExecutable,
71
+ ffprobeExecutable,
72
+ remotionRoot,
73
+ src,
74
+ });
65
75
  callbacks = callbacks.filter((c) => {
66
76
  if (c.src === src) {
67
77
  c.fn(output);
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { OffthreadVideoImageFormat } from 'remotion';
3
2
  import type { DownloadMap } from './assets/download-map';
4
3
  import type { FfmpegExecutable } from './ffmpeg-executable';
@@ -6,91 +6,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.extractFrameFromVideo = exports.getLastFrameOfVideo = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const get_video_stream_duration_1 = require("./assets/get-video-stream-duration");
9
+ const determine_resize_params_1 = require("./determine-resize-params");
10
+ const determine_vcodec_ffmepg_flags_1 = require("./determine-vcodec-ffmepg-flags");
9
11
  const ensure_presentation_timestamp_1 = require("./ensure-presentation-timestamp");
10
12
  const ffmpeg_flags_1 = require("./ffmpeg-flags");
11
13
  const frame_to_ffmpeg_timestamp_1 = require("./frame-to-ffmpeg-timestamp");
14
+ const get_can_extract_frames_fast_1 = require("./get-can-extract-frames-fast");
15
+ const get_frame_of_video_slow_1 = require("./get-frame-of-video-slow");
12
16
  const get_video_info_1 = require("./get-video-info");
13
17
  const is_beyond_last_frame_1 = require("./is-beyond-last-frame");
14
18
  const last_frame_from_video_cache_1 = require("./last-frame-from-video-cache");
15
19
  const p_limit_1 = require("./p-limit");
16
20
  const perf_1 = require("./perf");
17
21
  const truthy_1 = require("./truthy");
22
+ const try_to_extract_frame_of_video_fast_1 = require("./try-to-extract-frame-of-video-fast");
18
23
  const lastFrameLimit = (0, p_limit_1.pLimit)(1);
19
24
  const mainLimit = (0, p_limit_1.pLimit)(5);
20
- const determineVcodecFfmepgFlags = (vcodecFlag) => {
21
- return [
22
- vcodecFlag === 'vp9' ? '-vcodec' : null,
23
- vcodecFlag === 'vp9' ? 'libvpx-vp9' : null,
24
- vcodecFlag === 'vp8' ? '-vcodec' : null,
25
- vcodecFlag === 'vp8' ? 'libvpx' : null,
26
- ].filter(truthy_1.truthy);
27
- };
28
- const determineResizeParams = (needsResize) => {
29
- if (needsResize === null) {
30
- return [];
31
- }
32
- return ['-s', `${needsResize[0]}x${needsResize[1]}`];
33
- };
34
- // Uses no seeking, therefore the whole video has to be decoded. This is a last resort and should only happen
35
- // if the video is corrupted
36
- const getFrameOfVideoSlow = async ({ src, duration, ffmpegExecutable, imageFormat, specialVCodecForTransparency, needsResize, offset, fps, remotionRoot, }) => {
37
- console.warn(`\nUsing a slow method to extract the frame at ${duration}ms of ${src}. See https://remotion.dev/docs/slow-method-to-extract-frame for advice`);
38
- const actualOffset = `-${duration * 1000 - offset}ms`;
39
- const command = [
40
- '-itsoffset',
41
- actualOffset,
42
- ...determineVcodecFfmepgFlags(specialVCodecForTransparency),
43
- '-i',
44
- src,
45
- '-frames:v',
46
- '1',
47
- '-c:v',
48
- imageFormat === 'jpeg' ? 'mjpeg' : 'png',
49
- '-f',
50
- 'image2pipe',
51
- ...determineResizeParams(needsResize),
52
- '-',
53
- ].filter(truthy_1.truthy);
54
- const { stdout, stderr } = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), command);
55
- if (!stderr) {
56
- throw new Error('unexpectedly did not get stderr');
57
- }
58
- if (!stdout) {
59
- throw new Error('unexpectedly did not get stdout');
60
- }
61
- const stderrChunks = [];
62
- const stdoutChunks = [];
63
- const stdErrString = new Promise((resolve, reject) => {
64
- stderr.on('data', (d) => stderrChunks.push(d));
65
- stderr.on('error', (err) => reject(err));
66
- stderr.on('end', () => resolve(Buffer.concat(stderrChunks).toString('utf-8')));
67
- });
68
- const stdoutChunk = new Promise((resolve, reject) => {
69
- stdout.on('data', (d) => stdoutChunks.push(d));
70
- stdout.on('error', (err) => reject(err));
71
- stdout.on('end', () => resolve(Buffer.concat(stdoutChunks)));
72
- });
73
- const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
74
- const isEmpty = stdErr.includes('Output file is empty');
75
- if (isEmpty) {
76
- if (offset > 70) {
77
- throw new Error(`Could not get last frame of ${src}. Tried to seek to the end using the command "ffmpeg ${command.join(' ')}" but got no frame. Most likely this video is corrupted.`);
78
- }
79
- return getFrameOfVideoSlow({
80
- ffmpegExecutable,
81
- duration,
82
- // Decrement in 10ms increments, or 1 frame (e.g. fps = 25 --> 40ms)
83
- offset: offset + (fps === null ? 10 : 1000 / fps),
84
- src,
85
- imageFormat,
86
- specialVCodecForTransparency,
87
- needsResize,
88
- fps,
89
- remotionRoot,
90
- });
91
- }
92
- return stdoutBuffer;
93
- };
94
25
  const getLastFrameOfVideoFastUnlimited = async (options) => {
95
26
  const { ffmpegExecutable, ffprobeExecutable, offset, src, downloadMap } = options;
96
27
  const fromCache = (0, last_frame_from_video_cache_1.getLastFrameFromCache)({ ...options, offset: 0 });
@@ -101,8 +32,9 @@ const getLastFrameOfVideoFastUnlimited = async (options) => {
101
32
  if (duration === null) {
102
33
  throw new Error(`Could not determine the duration of ${src} using FFMPEG. The file is not supported.`);
103
34
  }
104
- if (options.specialVCodecForTransparency === 'vp8' || offset > 40) {
105
- const last = await getFrameOfVideoSlow({
35
+ if (options.specialVCodecForTransparency === 'vp8' ||
36
+ offset > get_can_extract_frames_fast_1.ACCEPTABLE_OFFSET_THRESHOLD) {
37
+ const last = await (0, get_frame_of_video_slow_1.getFrameOfVideoSlow)({
106
38
  duration,
107
39
  ffmpegExecutable,
108
40
  src,
@@ -116,46 +48,15 @@ const getLastFrameOfVideoFastUnlimited = async (options) => {
116
48
  return last;
117
49
  }
118
50
  const actualOffset = `${duration * 1000 - offset}ms`;
119
- const { stdout, stderr } = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, options.remotionRoot, 'ffmpeg'), [
120
- '-ss',
51
+ const [stdErr, stdoutBuffer] = await (0, try_to_extract_frame_of_video_fast_1.tryToExtractFrameOfVideoFast)({
121
52
  actualOffset,
122
- ...determineVcodecFfmepgFlags(options.specialVCodecForTransparency),
123
- '-i',
53
+ ffmpegExecutable,
54
+ imageFormat: options.imageFormat,
55
+ needsResize: options.needsResize,
56
+ remotionRoot: options.remotionRoot,
57
+ specialVCodecForTransparency: options.specialVCodecForTransparency,
124
58
  src,
125
- '-frames:v',
126
- '1',
127
- '-c:v',
128
- options.imageFormat === 'jpeg' ? 'mjpeg' : 'png',
129
- '-f',
130
- 'image2pipe',
131
- ...determineResizeParams(options.needsResize),
132
- '-',
133
- ].filter(truthy_1.truthy));
134
- if (!stderr) {
135
- throw new Error('unexpectedly did not get stderr');
136
- }
137
- if (!stdout) {
138
- throw new Error('unexpectedly did not get stdout');
139
- }
140
- const stderrChunks = [];
141
- const stdoutChunks = [];
142
- const stdErrString = new Promise((resolve, reject) => {
143
- stderr.on('data', (d) => stderrChunks.push(d));
144
- stderr.on('error', (err) => reject(err));
145
- stderr.on('end', () => resolve(Buffer.concat(stderrChunks).toString('utf-8')));
146
- });
147
- const stdoutChunk = new Promise((resolve, reject) => {
148
- stdout.on('data', (d) => {
149
- stdoutChunks.push(d);
150
- });
151
- stdout.on('error', (err) => {
152
- reject(err);
153
- });
154
- stdout.on('end', () => {
155
- resolve(Buffer.concat(stdoutChunks));
156
- });
157
59
  });
158
- const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
159
60
  const isEmpty = stdErr.includes('Output file is empty');
160
61
  if (isEmpty) {
161
62
  const unlimited = await getLastFrameOfVideoFastUnlimited({
@@ -190,10 +91,10 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
190
91
  ffmpegExecutable,
191
92
  ffprobeExecutable,
192
93
  });
193
- const { specialVcodec, needsResize } = await (0, get_video_info_1.getVideoInfo)(downloadMap, src, ffprobeExecutable, remotionRoot);
94
+ const { specialVcodecForTransparency: specialVcodec, needsResize } = await (0, get_video_info_1.getVideoInfo)(downloadMap, src, ffprobeExecutable, remotionRoot);
194
95
  if (specialVcodec === 'vp8') {
195
96
  const { fps } = await (0, get_video_stream_duration_1.getVideoStreamDuration)(downloadMap, src, ffprobeExecutable, remotionRoot);
196
- return getFrameOfVideoSlow({
97
+ return (0, get_frame_of_video_slow_1.getFrameOfVideoSlow)({
197
98
  ffmpegExecutable,
198
99
  imageFormat,
199
100
  specialVCodecForTransparency: specialVcodec,
@@ -223,7 +124,7 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
223
124
  const { stdout, stderr } = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), [
224
125
  '-ss',
225
126
  ffmpegTimestamp,
226
- ...determineVcodecFfmepgFlags(specialVcodec),
127
+ ...(0, determine_vcodec_ffmepg_flags_1.determineVcodecFfmepgFlags)(specialVcodec),
227
128
  '-i',
228
129
  src,
229
130
  '-frames:v',
@@ -232,7 +133,7 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
232
133
  'image2pipe',
233
134
  '-vcodec',
234
135
  imageFormat === 'jpeg' ? 'mjpeg' : 'png',
235
- ...determineResizeParams(needsResize),
136
+ ...(0, determine_resize_params_1.determineResizeParams)(needsResize),
236
137
  '-',
237
138
  ].filter(truthy_1.truthy), {
238
139
  buffer: false,
@@ -0,0 +1,10 @@
1
+ import type { FfmpegExecutable } from './ffmpeg-executable';
2
+ export declare const ACCEPTABLE_OFFSET_THRESHOLD = 40;
3
+ export declare const getCanExtractFramesFast: ({ src, ffmpegExecutable, ffprobeExecutable, }: {
4
+ src: string;
5
+ ffmpegExecutable?: FfmpegExecutable | undefined;
6
+ ffprobeExecutable?: FfmpegExecutable | undefined;
7
+ }) => Promise<{
8
+ canExtractFramesFast: boolean;
9
+ shouldReencode: boolean;
10
+ }>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getCanExtractFramesFast = exports.ACCEPTABLE_OFFSET_THRESHOLD = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const get_video_stream_duration_1 = require("./assets/get-video-stream-duration");
9
+ const ensure_presentation_timestamp_1 = require("./ensure-presentation-timestamp");
10
+ const find_closest_package_json_1 = require("./find-closest-package-json");
11
+ const get_video_info_1 = require("./get-video-info");
12
+ const try_to_extract_frame_of_video_fast_1 = require("./try-to-extract-frame-of-video-fast");
13
+ exports.ACCEPTABLE_OFFSET_THRESHOLD = 40;
14
+ const getCanExtractFramesFast = async ({ src, ffmpegExecutable, ffprobeExecutable, }) => {
15
+ const remotionRoot = (0, find_closest_package_json_1.findRemotionRoot)();
16
+ const out = await (0, ensure_presentation_timestamp_1.ensurePresentationTimestampWithoutCache)({
17
+ ffmpegExecutable: ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null,
18
+ ffprobeExecutable: ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : null,
19
+ remotionRoot,
20
+ src,
21
+ });
22
+ const { specialVcodecForTransparency: specialVcodec } = await (0, get_video_info_1.getVideoInfoUncached)({
23
+ src: out,
24
+ ffprobeExecutable: ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : null,
25
+ remotionRoot,
26
+ });
27
+ if (specialVcodec === 'vp8') {
28
+ fs_1.default.unlinkSync(out);
29
+ return {
30
+ canExtractFramesFast: false,
31
+ shouldReencode: false,
32
+ };
33
+ }
34
+ const { duration } = await (0, get_video_stream_duration_1.getVideoStreamDurationwithoutCache)({
35
+ ffprobeExecutable: ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : null,
36
+ remotionRoot,
37
+ src: out,
38
+ });
39
+ if (duration === null) {
40
+ fs_1.default.unlinkSync(out);
41
+ throw new Error(`Could not determine the duration of ${src} using FFMPEG. The file is not supported.`);
42
+ }
43
+ const actualOffset = `${duration * 1000 - exports.ACCEPTABLE_OFFSET_THRESHOLD}ms`;
44
+ const [stdErr] = await (0, try_to_extract_frame_of_video_fast_1.tryToExtractFrameOfVideoFast)({
45
+ actualOffset,
46
+ ffmpegExecutable: ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null,
47
+ imageFormat: 'jpeg',
48
+ // Intentionally leaving needsResize as null, because we don't need to resize
49
+ needsResize: null,
50
+ remotionRoot,
51
+ specialVCodecForTransparency: specialVcodec,
52
+ src: out,
53
+ });
54
+ fs_1.default.unlinkSync(out);
55
+ const isEmpty = stdErr.includes('Output file is empty');
56
+ if (isEmpty) {
57
+ return {
58
+ canExtractFramesFast: false,
59
+ shouldReencode: true,
60
+ };
61
+ }
62
+ return {
63
+ canExtractFramesFast: true,
64
+ shouldReencode: false,
65
+ };
66
+ };
67
+ exports.getCanExtractFramesFast = getCanExtractFramesFast;
@@ -1,2 +1,2 @@
1
1
  import type { Codec } from './codec';
2
- export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "webm" | "mp4" | "mov" | "mkv";
2
+ export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "mp4" | "mkv" | "mov" | "webm";
@@ -0,0 +1,17 @@
1
+ import type { OffthreadVideoImageFormat } from 'remotion';
2
+ import type { SpecialVCodecForTransparency } from './assets/download-map';
3
+ import type { FfmpegExecutable } from './ffmpeg-executable';
4
+ export declare const getFrameOfVideoSlow: ({ src, duration, ffmpegExecutable, imageFormat, specialVCodecForTransparency, needsResize, offset, fps, remotionRoot, }: {
5
+ ffmpegExecutable: FfmpegExecutable;
6
+ src: string;
7
+ duration: number;
8
+ imageFormat: OffthreadVideoImageFormat;
9
+ specialVCodecForTransparency: SpecialVCodecForTransparency;
10
+ needsResize: [
11
+ number,
12
+ number
13
+ ] | null;
14
+ offset: number;
15
+ fps: number | null;
16
+ remotionRoot: string;
17
+ }) => Promise<Buffer>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getFrameOfVideoSlow = void 0;
7
+ // Uses no seeking, therefore the whole video has to be decoded. This is a last resort and should only happen
8
+ // if the video is corrupted
9
+ const execa_1 = __importDefault(require("execa"));
10
+ const determine_resize_params_1 = require("./determine-resize-params");
11
+ const determine_vcodec_ffmepg_flags_1 = require("./determine-vcodec-ffmepg-flags");
12
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
13
+ const truthy_1 = require("./truthy");
14
+ const getFrameOfVideoSlow = async ({ src, duration, ffmpegExecutable, imageFormat, specialVCodecForTransparency, needsResize, offset, fps, remotionRoot, }) => {
15
+ console.warn(`\nUsing a slow method to extract the frame at ${duration}ms of ${src}. See https://remotion.dev/docs/slow-method-to-extract-frame for advice`);
16
+ const actualOffset = `-${duration * 1000 - offset}ms`;
17
+ const command = [
18
+ '-itsoffset',
19
+ actualOffset,
20
+ ...(0, determine_vcodec_ffmepg_flags_1.determineVcodecFfmepgFlags)(specialVCodecForTransparency),
21
+ '-i',
22
+ src,
23
+ '-frames:v',
24
+ '1',
25
+ '-c:v',
26
+ imageFormat === 'jpeg' ? 'mjpeg' : 'png',
27
+ '-f',
28
+ 'image2pipe',
29
+ ...(0, determine_resize_params_1.determineResizeParams)(needsResize),
30
+ '-',
31
+ ].filter(truthy_1.truthy);
32
+ const { stdout, stderr } = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), command);
33
+ if (!stderr) {
34
+ throw new Error('unexpectedly did not get stderr');
35
+ }
36
+ if (!stdout) {
37
+ throw new Error('unexpectedly did not get stdout');
38
+ }
39
+ const stderrChunks = [];
40
+ const stdoutChunks = [];
41
+ const stdErrString = new Promise((resolve, reject) => {
42
+ stderr.on('data', (d) => stderrChunks.push(d));
43
+ stderr.on('error', (err) => reject(err));
44
+ stderr.on('end', () => resolve(Buffer.concat(stderrChunks).toString('utf-8')));
45
+ });
46
+ const stdoutChunk = new Promise((resolve, reject) => {
47
+ stdout.on('data', (d) => stdoutChunks.push(d));
48
+ stdout.on('error', (err) => reject(err));
49
+ stdout.on('end', () => resolve(Buffer.concat(stdoutChunks)));
50
+ });
51
+ const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
52
+ const isEmpty = stdErr.includes('Output file is empty');
53
+ if (isEmpty) {
54
+ if (offset > 70) {
55
+ throw new Error(`Could not get last frame of ${src}. Tried to seek to the end using the command "ffmpeg ${command.join(' ')}" but got no frame. Most likely this video is corrupted.`);
56
+ }
57
+ return (0, exports.getFrameOfVideoSlow)({
58
+ ffmpegExecutable,
59
+ duration,
60
+ // Decrement in 10ms increments, or 1 frame (e.g. fps = 25 --> 40ms)
61
+ offset: offset + (fps === null ? 10 : 1000 / fps),
62
+ src,
63
+ imageFormat,
64
+ specialVCodecForTransparency,
65
+ needsResize,
66
+ fps,
67
+ remotionRoot,
68
+ });
69
+ }
70
+ return stdoutBuffer;
71
+ };
72
+ exports.getFrameOfVideoSlow = getFrameOfVideoSlow;
@@ -1,3 +1,8 @@
1
1
  import type { DownloadMap, Vp9Result } from './assets/download-map';
2
2
  import type { FfmpegExecutable } from './ffmpeg-executable';
3
+ export declare function getVideoInfoUncached({ src, ffprobeExecutable, remotionRoot, }: {
4
+ src: string;
5
+ ffprobeExecutable: FfmpegExecutable;
6
+ remotionRoot: string;
7
+ }): Promise<Vp9Result>;
3
8
  export declare const getVideoInfo: (downloadMap: DownloadMap, src: string, ffprobeExecutable: FfmpegExecutable, remotionRoot: string) => Promise<Vp9Result>;
@@ -3,17 +3,14 @@ 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.getVideoInfo = void 0;
6
+ exports.getVideoInfo = exports.getVideoInfoUncached = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const calculate_sar_dar_pixels_1 = require("./calculate-sar-dar-pixels");
9
9
  const ffmpeg_flags_1 = require("./ffmpeg-flags");
10
10
  const p_limit_1 = require("./p-limit");
11
11
  const limit = (0, p_limit_1.pLimit)(1);
12
- async function getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot) {
12
+ async function getVideoInfoUncached({ src, ffprobeExecutable, remotionRoot, }) {
13
13
  var _a;
14
- if (typeof downloadMap.isVp9VideoCache[src] !== 'undefined') {
15
- return downloadMap.isVp9VideoCache[src];
16
- }
17
14
  const task = await (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffprobeExecutable, remotionRoot, 'ffprobe'), [src]);
18
15
  const isVp9 = task.stderr.includes('Video: vp9');
19
16
  const isVp8 = task.stderr.includes('Video: vp8');
@@ -38,9 +35,21 @@ async function getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable, remoti
38
35
  }
39
36
  }
40
37
  const result = {
41
- specialVcodec: isVp9 ? 'vp9' : isVp8 ? 'vp8' : 'none',
38
+ specialVcodecForTransparency: isVp9 ? 'vp9' : isVp8 ? 'vp8' : 'none',
42
39
  needsResize,
43
40
  };
41
+ return result;
42
+ }
43
+ exports.getVideoInfoUncached = getVideoInfoUncached;
44
+ async function getVideoInfoUnlimited(downloadMap, src, ffprobeExecutable, remotionRoot) {
45
+ if (typeof downloadMap.isVp9VideoCache[src] !== 'undefined') {
46
+ return downloadMap.isVp9VideoCache[src];
47
+ }
48
+ const result = await getVideoInfoUncached({
49
+ ffprobeExecutable,
50
+ remotionRoot,
51
+ src,
52
+ });
44
53
  downloadMap.isVp9VideoCache[src] = result;
45
54
  return downloadMap.isVp9VideoCache[src];
46
55
  }
@@ -2,4 +2,4 @@ export declare const guessExtensionForVideo: ({ src, remotionRoot, ffprobeBinary
2
2
  src: string;
3
3
  remotionRoot: string;
4
4
  ffprobeBinary: string | null;
5
- }) => Promise<"mp3" | "wav" | "webm" | "mp4">;
5
+ }) => Promise<"mp3" | "wav" | "mp4" | "webm">;
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { FfmpegExecutable } from './ffmpeg-executable';
16
16
  export { FfmpegVersion } from './ffmpeg-flags';
17
17
  export type { FfmpegOverrideFn } from './ffmpeg-override';
18
18
  export { FrameRange } from './frame-range';
19
+ export { getCanExtractFramesFast } from './get-can-extract-frames-fast';
19
20
  export { getCompositions } from './get-compositions';
20
21
  export { ImageFormat, StillImageFormat, validateSelectedPixelFormatAndImageFormatCombination, validImageFormats, } from './image-format';
21
22
  export type { LogLevel } from './log-level';
@@ -113,8 +114,8 @@ export declare const RenderInternals: {
113
114
  validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
114
115
  DEFAULT_BROWSER: import("./browser").Browser;
115
116
  validateFrameRange: (frameRange: import("./frame-range").FrameRange | null) => void;
116
- DEFAULT_OPENGL_RENDERER: "swangle" | "angle" | "egl" | "swiftshader" | null;
117
- validateOpenGlRenderer: (option: "swangle" | "angle" | "egl" | "swiftshader" | null) => "swangle" | "angle" | "egl" | "swiftshader" | null;
117
+ DEFAULT_OPENGL_RENDERER: "angle" | "swangle" | "egl" | "swiftshader" | null;
118
+ validateOpenGlRenderer: (option: "angle" | "swangle" | "egl" | "swiftshader" | null) => "angle" | "swangle" | "egl" | "swiftshader" | null;
118
119
  validImageFormats: readonly ["png", "jpeg", "none"];
119
120
  validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
120
121
  DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.RenderInternals = exports.validateOutputFilename = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validImageFormats = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getCompositions = exports.ErrorWithStackFrame = exports.ensureFfprobe = exports.ensureFfmpeg = exports.combineVideos = void 0;
29
+ exports.RenderInternals = exports.validateOutputFilename = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validImageFormats = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getCompositions = exports.getCanExtractFramesFast = exports.ErrorWithStackFrame = exports.ensureFfprobe = exports.ensureFfmpeg = exports.combineVideos = void 0;
30
30
  const execa_1 = __importDefault(require("execa"));
31
31
  const download_file_1 = require("./assets/download-file");
32
32
  const download_map_1 = require("./assets/download-map");
@@ -78,6 +78,8 @@ Object.defineProperty(exports, "ensureFfmpeg", { enumerable: true, get: function
78
78
  Object.defineProperty(exports, "ensureFfprobe", { enumerable: true, get: function () { return ensure_ffmpeg_1.ensureFfprobe; } });
79
79
  var handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
80
80
  Object.defineProperty(exports, "ErrorWithStackFrame", { enumerable: true, get: function () { return handle_javascript_exception_1.ErrorWithStackFrame; } });
81
+ var get_can_extract_frames_fast_1 = require("./get-can-extract-frames-fast");
82
+ Object.defineProperty(exports, "getCanExtractFramesFast", { enumerable: true, get: function () { return get_can_extract_frames_fast_1.getCanExtractFramesFast; } });
81
83
  var get_compositions_1 = require("./get-compositions");
82
84
  Object.defineProperty(exports, "getCompositions", { enumerable: true, get: function () { return get_compositions_1.getCompositions; } });
83
85
  var image_format_2 = require("./image-format");
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { OffthreadVideoImageFormat } from 'remotion';
3
2
  import type { DownloadMap, SpecialVCodecForTransparency } from './assets/download-map';
4
3
  import type { FfmpegExecutable } from './ffmpeg-executable';
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ImageFormat } from './image-format';
4
3
  export declare const provideScreenshot: ({ page, imageFormat, options, quality, }: {
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
4
3
  export declare const screenshot: (page: Page, options: ScreenshotOptions) => Promise<Buffer | string | void>;
@@ -0,0 +1 @@
1
+ export declare const redirectStatusCodes: number[];
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redirectStatusCodes = void 0;
4
+ exports.redirectStatusCodes = [301, 302, 303, 304, 307, 308];
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { SmallTCompMetadata } from 'remotion';
3
2
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
4
3
  import type { DownloadMap } from './assets/download-map';
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ImageFormat } from './image-format';
4
3
  export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts, }: {
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
4
3
  import type { StillImageFormat } from './image-format';
@@ -5,6 +5,7 @@ const version_1 = require("remotion/version");
5
5
  const TimeoutSettings_1 = require("./browser/TimeoutSettings");
6
6
  const normalize_serve_url_1 = require("./normalize-serve-url");
7
7
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
8
+ const redirect_status_codes_1 = require("./redirect-status-codes");
8
9
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
9
10
  const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, audioEnabled, videoEnabled, }) => {
10
11
  (0, validate_puppeteer_timeout_1.validatePuppeteerTimeout)(timeoutInMilliseconds);
@@ -63,13 +64,7 @@ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initia
63
64
  videoEnabled,
64
65
  });
65
66
  }
66
- if (status !== 200 &&
67
- status !== 301 &&
68
- status !== 302 &&
69
- status !== 303 &&
70
- status !== 304 &&
71
- status !== 307 &&
72
- status !== 308) {
67
+ if (!redirect_status_codes_1.redirectStatusCodes.every((code) => code !== status)) {
73
68
  throw new Error(`Error while getting compositions: Tried to go to ${urlToVisit} but the status code was ${status} instead of 200. Does the site you specified exist?`);
74
69
  }
75
70
  const isRemotionFn = await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
@@ -0,0 +1,12 @@
1
+ import type { OffthreadVideoImageFormat } from 'remotion';
2
+ import type { NeedsResize, SpecialVCodecForTransparency } from './assets/download-map';
3
+ import type { FfmpegExecutable } from './ffmpeg-executable';
4
+ export declare const tryToExtractFrameOfVideoFast: ({ ffmpegExecutable, remotionRoot, specialVCodecForTransparency, imageFormat, needsResize, src, actualOffset, }: {
5
+ ffmpegExecutable: FfmpegExecutable;
6
+ remotionRoot: string;
7
+ imageFormat: OffthreadVideoImageFormat;
8
+ needsResize: NeedsResize;
9
+ src: string;
10
+ specialVCodecForTransparency: SpecialVCodecForTransparency;
11
+ actualOffset: string;
12
+ }) => Promise<readonly [string, Buffer]>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.tryToExtractFrameOfVideoFast = void 0;
7
+ const execa_1 = __importDefault(require("execa"));
8
+ const determine_resize_params_1 = require("./determine-resize-params");
9
+ const determine_vcodec_ffmepg_flags_1 = require("./determine-vcodec-ffmepg-flags");
10
+ const ffmpeg_flags_1 = require("./ffmpeg-flags");
11
+ const truthy_1 = require("./truthy");
12
+ const tryToExtractFrameOfVideoFast = async ({ ffmpegExecutable, remotionRoot, specialVCodecForTransparency, imageFormat, needsResize, src, actualOffset, }) => {
13
+ const { stdout, stderr } = (0, execa_1.default)(await (0, ffmpeg_flags_1.getExecutableBinary)(ffmpegExecutable, remotionRoot, 'ffmpeg'), [
14
+ '-ss',
15
+ actualOffset,
16
+ ...(0, determine_vcodec_ffmepg_flags_1.determineVcodecFfmepgFlags)(specialVCodecForTransparency),
17
+ '-i',
18
+ src,
19
+ '-frames:v',
20
+ '1',
21
+ '-c:v',
22
+ imageFormat === 'jpeg' ? 'mjpeg' : 'png',
23
+ '-f',
24
+ 'image2pipe',
25
+ ...(0, determine_resize_params_1.determineResizeParams)(needsResize),
26
+ '-',
27
+ ].filter(truthy_1.truthy));
28
+ if (!stderr) {
29
+ throw new Error('unexpectedly did not get stderr');
30
+ }
31
+ if (!stdout) {
32
+ throw new Error('unexpectedly did not get stdout');
33
+ }
34
+ const stderrChunks = [];
35
+ const stdoutChunks = [];
36
+ const stdErrString = new Promise((resolve, reject) => {
37
+ stderr.on('data', (d) => stderrChunks.push(d));
38
+ stderr.on('error', (err) => reject(err));
39
+ stderr.on('end', () => resolve(Buffer.concat(stderrChunks).toString('utf-8')));
40
+ });
41
+ const stdoutChunk = new Promise((resolve, reject) => {
42
+ stdout.on('data', (d) => {
43
+ stdoutChunks.push(d);
44
+ });
45
+ stdout.on('error', (err) => {
46
+ reject(err);
47
+ });
48
+ stdout.on('end', () => {
49
+ resolve(Buffer.concat(stdoutChunks));
50
+ });
51
+ });
52
+ const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
53
+ return [stdErr, stdoutBuffer];
54
+ };
55
+ exports.tryToExtractFrameOfVideoFast = tryToExtractFrameOfVideoFast;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "execa": "5.1.1",
24
24
  "extract-zip": "2.0.1",
25
- "remotion": "3.3.1",
25
+ "remotion": "3.3.2",
26
26
  "source-map": "^0.8.0-beta.0",
27
27
  "ws": "8.7.0"
28
28
  },
@@ -57,5 +57,5 @@
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  },
60
- "gitHead": "f56a29f8ab19e279e1a9950d3a3ccbb3c8ae42e0"
60
+ "gitHead": "d7422b5d86e4766a4cdb0bc4e291e462a6bf8bb6"
61
61
  }