@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.
- package/dist/assets/download-map.d.ts +3 -2
- package/dist/assets/get-video-stream-duration.d.ts +5 -0
- package/dist/assets/get-video-stream-duration.js +17 -6
- package/dist/assets/read-file.js +2 -4
- package/dist/determine-resize-params.d.ts +4 -0
- package/dist/determine-resize-params.js +10 -0
- package/dist/determine-vcodec-ffmepg-flags.d.ts +2 -0
- package/dist/determine-vcodec-ffmepg-flags.js +13 -0
- package/dist/ensure-presentation-timestamp.d.ts +6 -0
- package/dist/ensure-presentation-timestamp.js +25 -15
- package/dist/extract-frame-from-video.d.ts +0 -1
- package/dist/extract-frame-from-video.js +18 -117
- package/dist/get-can-extract-frames-fast.d.ts +10 -0
- package/dist/get-can-extract-frames-fast.js +67 -0
- package/dist/get-extension-from-codec.d.ts +1 -1
- package/dist/get-frame-of-video-slow.d.ts +17 -0
- package/dist/get-frame-of-video-slow.js +72 -0
- package/dist/get-video-info.d.ts +5 -0
- package/dist/get-video-info.js +15 -6
- package/dist/guess-extension-for-media.d.ts +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -1
- package/dist/last-frame-from-video-cache.d.ts +0 -1
- package/dist/provide-screenshot.d.ts +0 -1
- package/dist/puppeteer-screenshot.d.ts +0 -1
- package/dist/redirect-status-codes.d.ts +1 -0
- package/dist/redirect-status-codes.js +4 -0
- package/dist/render-media.d.ts +0 -1
- package/dist/screenshot-dom-element.d.ts +0 -1
- package/dist/screenshot-task.d.ts +0 -1
- package/dist/set-props-and-env.js +2 -7
- package/dist/try-to-extract-frame-of-video-fast.d.ts +12 -0
- package/dist/try-to-extract-frame-of-video-fast.js +55 -0
- 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
|
-
|
|
12
|
-
needsResize:
|
|
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
|
|
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
|
-
|
|
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));
|
package/dist/assets/read-file.js
CHANGED
|
@@ -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
|
|
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,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,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
|
|
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' ||
|
|
105
|
-
|
|
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
|
|
120
|
-
'-ss',
|
|
51
|
+
const [stdErr, stdoutBuffer] = await (0, try_to_extract_frame_of_video_fast_1.tryToExtractFrameOfVideoFast)({
|
|
121
52
|
actualOffset,
|
|
122
|
-
|
|
123
|
-
|
|
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" | "
|
|
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;
|
package/dist/get-video-info.d.ts
CHANGED
|
@@ -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>;
|
package/dist/get-video-info.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
@@ -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: "
|
|
117
|
-
validateOpenGlRenderer: (option: "
|
|
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");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const redirectStatusCodes: number[];
|
package/dist/render-media.d.ts
CHANGED
|
@@ -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 (
|
|
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.
|
|
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.
|
|
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": "
|
|
60
|
+
"gitHead": "d7422b5d86e4766a4cdb0bc4e291e462a6bf8bb6"
|
|
61
61
|
}
|