@remotion/renderer 3.3.0 → 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.
@@ -1,3 +1,7 @@
1
+ declare type Response = {
2
+ sizeInBytes: number;
3
+ to: string;
4
+ };
1
5
  export declare const downloadFile: ({ onProgress, url, to: toFn, }: {
2
6
  url: string;
3
7
  to: (contentDisposition: string | null, contentType: string | null) => string;
@@ -6,7 +10,5 @@ export declare const downloadFile: ({ onProgress, url, to: toFn, }: {
6
10
  downloaded: number;
7
11
  totalSize: number | null;
8
12
  }) => void) | undefined;
9
- }) => Promise<{
10
- sizeInBytes: number;
11
- to: string;
12
- }>;
13
+ }) => Promise<Response>;
14
+ export {};
@@ -6,6 +6,35 @@ const ensure_output_directory_1 = require("../ensure-output-directory");
6
6
  const read_file_1 = require("./read-file");
7
7
  const downloadFile = ({ onProgress, url, to: toFn, }) => {
8
8
  return new Promise((resolve, reject) => {
9
+ let rejected = false;
10
+ let resolved = false;
11
+ let timeout;
12
+ const resolveAndFlag = (val) => {
13
+ resolved = true;
14
+ resolve(val);
15
+ if (timeout) {
16
+ clearTimeout(timeout);
17
+ }
18
+ };
19
+ const rejectAndFlag = (err) => {
20
+ if (timeout) {
21
+ clearTimeout(timeout);
22
+ }
23
+ reject(err);
24
+ rejected = true;
25
+ };
26
+ const refreshTimeout = () => {
27
+ if (timeout) {
28
+ clearTimeout(timeout);
29
+ }
30
+ timeout = setTimeout(() => {
31
+ if (resolved) {
32
+ return;
33
+ }
34
+ rejectAndFlag(new Error(`Tried to download file ${url}, but the server sent no data for 20 seconds`));
35
+ }, 20000);
36
+ };
37
+ refreshTimeout();
9
38
  (0, read_file_1.readFile)(url)
10
39
  .then((res) => {
11
40
  var _a, _b;
@@ -21,16 +50,20 @@ const downloadFile = ({ onProgress, url, to: toFn, }) => {
21
50
  // concise method to avoid this problem
22
51
  // https://github.com/remotion-dev/remotion/issues/384#issuecomment-844398183
23
52
  writeStream.on('close', () => {
53
+ if (rejected) {
54
+ return;
55
+ }
24
56
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({
25
57
  downloaded,
26
58
  percent: 1,
27
59
  totalSize: downloaded,
28
60
  });
29
- return resolve({ sizeInBytes: downloaded, to });
61
+ refreshTimeout();
62
+ return resolveAndFlag({ sizeInBytes: downloaded, to });
30
63
  });
31
- writeStream.on('error', (err) => reject(err));
32
- res.on('error', (err) => reject(err));
33
- res.pipe(writeStream).on('error', (err) => reject(err));
64
+ writeStream.on('error', (err) => rejectAndFlag(err));
65
+ res.on('error', (err) => rejectAndFlag(err));
66
+ res.pipe(writeStream).on('error', (err) => rejectAndFlag(err));
34
67
  res.on('data', (d) => {
35
68
  downloaded += d.length;
36
69
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({
@@ -39,9 +72,15 @@ const downloadFile = ({ onProgress, url, to: toFn, }) => {
39
72
  totalSize,
40
73
  });
41
74
  });
75
+ res.on('close', () => {
76
+ if (totalSize !== null && downloaded !== totalSize) {
77
+ rejectAndFlag(new Error(`Download finished with ${downloaded} bytes, but expected ${totalSize} bytes from 'Content-Length'.`));
78
+ }
79
+ writeStream.close();
80
+ });
42
81
  })
43
82
  .catch((err) => {
44
- reject(err);
83
+ rejectAndFlag(err);
45
84
  });
46
85
  });
47
86
  };
@@ -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
  }
@@ -135,7 +135,6 @@ class Browser extends EventEmitter_1.EventEmitter {
135
135
  async close(silent) {
136
136
  await __classPrivateFieldGet(this, _Browser_closeCallback, "f").call(null);
137
137
  (await this.pages()).forEach((page) => {
138
- console.log('disposing', page.id);
139
138
  page.emit("disposed" /* PageEmittedEvents.Disposed */);
140
139
  page.closed = true;
141
140
  });
@@ -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);
@@ -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,
@@ -105,7 +105,7 @@ const waitForFfmpegToBeDownloaded = (url) => {
105
105
  });
106
106
  };
107
107
  const onProgress = (downloadedBytes, totalBytesToDownload, binary) => {
108
- console.log('Downloading ', [binary], `${toMegabytes(downloadedBytes)}/${toMegabytes(totalBytesToDownload)}`);
108
+ console.log('Downloading ', binary, `${toMegabytes(downloadedBytes)}/${toMegabytes(totalBytesToDownload)}`);
109
109
  };
110
110
  const downloadBinary = async (remotionRoot, url, binary) => {
111
111
  const destinationPath = getFfmpegAbsolutePath(remotionRoot, binary);
@@ -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
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import execa from 'execa';
3
2
  import { SymbolicateableError } from './error-handling/symbolicateable-error';
4
3
  import { mimeContentType, mimeLookup } from './mime-types';
@@ -17,6 +16,7 @@ export { FfmpegExecutable } from './ffmpeg-executable';
17
16
  export { FfmpegVersion } from './ffmpeg-flags';
18
17
  export type { FfmpegOverrideFn } from './ffmpeg-override';
19
18
  export { FrameRange } from './frame-range';
19
+ export { getCanExtractFramesFast } from './get-can-extract-frames-fast';
20
20
  export { getCompositions } from './get-compositions';
21
21
  export { ImageFormat, StillImageFormat, validateSelectedPixelFormatAndImageFormatCombination, validImageFormats, } from './image-format';
22
22
  export type { LogLevel } from './log-level';
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");
@@ -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];
@@ -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)({
@@ -1,12 +1,34 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.stitchFramesToVideo = exports.spawnFfmpeg = void 0;
7
30
  const execa_1 = __importDefault(require("execa"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const promises_1 = require("fs/promises");
31
+ const fs_1 = __importStar(require("fs"));
10
32
  const path_1 = __importDefault(require("path"));
11
33
  const remotion_1 = require("remotion");
12
34
  const calculate_asset_positions_1 = require("./assets/calculate-asset-positions");
@@ -182,7 +204,8 @@ const spawnFfmpeg = async (options, remotionRoot) => {
182
204
  }
183
205
  const file = await new Promise((resolve, reject) => {
184
206
  if (tempFile) {
185
- (0, promises_1.readFile)(tempFile)
207
+ fs_1.promises
208
+ .readFile(tempFile)
186
209
  .then((f) => {
187
210
  return resolve(f);
188
211
  })
@@ -295,7 +318,8 @@ const spawnFfmpeg = async (options, remotionRoot) => {
295
318
  (0, delete_directory_1.deleteDirectory)(options.assetsInfo.downloadMap.stitchFrames);
296
319
  return null;
297
320
  }
298
- return (0, promises_1.readFile)(tempFile)
321
+ return fs_1.promises
322
+ .readFile(tempFile)
299
323
  .then((file) => {
300
324
  return Promise.all([
301
325
  file,
@@ -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;
@@ -69,7 +69,7 @@ const validateFfmpeg = async (customFfmpegBinary, remotionRoot, binary) => {
69
69
  }
70
70
  const binaryUrl = (0, ffmpeg_flags_1.getBinaryDownloadUrl)(binary);
71
71
  if (binaryUrl) {
72
- await (0, ffmpeg_flags_1.downloadBinary)(remotionRoot, binaryUrl.url, 'ffmpeg');
72
+ await (0, ffmpeg_flags_1.downloadBinary)(remotionRoot, binaryUrl.url, binary);
73
73
  return (0, exports.validateFfmpeg)(customFfmpegBinary, remotionRoot, binary);
74
74
  }
75
75
  throw new Error(`${binary} could not be installed automatically. Your architecture and OS combination (os = ${os_1.default.platform()}, arch = ${process.arch}) is not supported. Please install ${binary} manually and add "${binary}" to your PATH.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "3.3.0",
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.0",
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": "29322c95729df0229eecc5f674d019145a783b46"
60
+ "gitHead": "d7422b5d86e4766a4cdb0bc4e291e462a6bf8bb6"
61
61
  }