rife-fps
Advanced tools
Comparing version 0.0.4 to 0.0.5
@@ -16,2 +16,3 @@ export interface RifeOptions { | ||
transparentColor?: string; | ||
parallelFrames?: number; | ||
} | ||
@@ -27,9 +28,13 @@ export default class Rife { | ||
}>; | ||
static interpolateDirectory: (inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void) => Promise<string>; | ||
private static splitArray; | ||
static interpolateFrame: (input1: string, input2: string, outputPath: string, options?: RifeOptions) => Promise<string>; | ||
static interpolateDirectorySingle: (inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => Promise<boolean>; | ||
static interpolateBucket: (originalDir: string, inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => Promise<boolean>; | ||
static interpolateDirectory: (inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => Promise<boolean>; | ||
private static parseTransparentColor; | ||
private static encodeGIF; | ||
static interpolateGIF: (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void) => Promise<string>; | ||
static interpolateVideo: (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void) => Promise<string>; | ||
static interpolateGIF: (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => Promise<string>; | ||
static interpolateVideo: (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => Promise<string>; | ||
private static awaitStream; | ||
private static removeDirectory; | ||
} |
225
dist/rife.js
@@ -156,7 +156,40 @@ "use strict"; | ||
}); }; | ||
Rife.interpolateDirectory = function (inputDir, outputDir, options, progress) { return __awaiter(void 0, void 0, void 0, function () { | ||
var frameExt, frameArray, targetCount, absolute, program, command, child, index; | ||
Rife.splitArray = function (array, chunkSize) { | ||
var result = []; | ||
for (var i = 0; i < array.length; i += chunkSize) { | ||
result.push(array.slice(i, i + chunkSize)); | ||
} | ||
return result; | ||
}; | ||
Rife.interpolateFrame = function (input1, input2, outputPath, options) { return __awaiter(void 0, void 0, void 0, function () { | ||
var absolute, program, command, child; | ||
return __generator(_a, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
absolute = options.rifePath ? path_1.default.normalize(options.rifePath).replace(/\\/g, "/") : path_1.default.join(__dirname, "../rife"); | ||
program = "cd \"".concat(absolute, "\" && cd windows && rife-ncnn-vulkan.exe"); | ||
if (process.platform === "darwin") | ||
program = "cd \"".concat(absolute, "\" && cd mac && ./rife-ncnn-vulkan"); | ||
if (process.platform === "linux") | ||
program = "cd \"".concat(absolute, "\" && cd linux && ./rife-ncnn-vulkan"); | ||
command = "".concat(program, " -0 \"").concat(input1, "\" -1 \"").concat(input2, "\" -o \"").concat(outputPath, "\" -m \"rife-v4.6\""); | ||
if (options.threads) | ||
command += " -j ".concat(options.threads, ":").concat(options.threads, ":").concat(options.threads); | ||
child = child_process_1.default.exec(command); | ||
return [4 /*yield*/, new Promise(function (resolve, reject) { | ||
child.on("close", function () { | ||
resolve(); | ||
}); | ||
})]; | ||
case 1: | ||
_b.sent(); | ||
return [2 /*return*/, outputPath]; | ||
} | ||
}); | ||
}); }; | ||
Rife.interpolateDirectorySingle = function (inputDir, outputDir, options, progress) { return __awaiter(void 0, void 0, void 0, function () { | ||
var frameExt, frameArray, resume, existing, total, i, block, j, index, outputPath, input2, stop_1; | ||
return __generator(_a, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
frameExt = options.pngFrames ? "png" : "jpg"; | ||
@@ -167,2 +200,51 @@ frameArray = fs_1.default.readdirSync(inputDir).map(function (f) { return "".concat(inputDir, "/").concat(f); }).filter(function (f) { return path_1.default.extname(f) === ".".concat(frameExt); }); | ||
options.multiplier = 2; | ||
resume = 0; | ||
existing = fs_1.default.readdirSync(outputDir); | ||
if (existing.length) | ||
resume = Math.floor(existing.length / options.multiplier); | ||
total = frameArray.length * options.multiplier; | ||
i = resume; | ||
_b.label = 1; | ||
case 1: | ||
if (!(i < frameArray.length)) return [3 /*break*/, 6]; | ||
block = [frameArray[i]]; | ||
j = 0; | ||
_b.label = 2; | ||
case 2: | ||
if (!(j < options.multiplier)) return [3 /*break*/, 5]; | ||
index = i * options.multiplier + j; | ||
outputPath = path_1.default.join(outputDir, "frame".concat(index, ".").concat(frameExt)); | ||
input2 = frameArray[i + 1] ? frameArray[i + 1] : frameArray[i]; | ||
return [4 /*yield*/, _a.interpolateFrame(block[block.length - 1], input2, outputPath, options)]; | ||
case 3: | ||
_b.sent(); | ||
block.push(outputPath); | ||
if (progress) { | ||
stop_1 = progress(100 / total * index); | ||
if (stop_1) | ||
return [2 /*return*/, true]; | ||
} | ||
_b.label = 4; | ||
case 4: | ||
j++; | ||
return [3 /*break*/, 2]; | ||
case 5: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 6: return [2 /*return*/, false]; | ||
} | ||
}); | ||
}); }; | ||
Rife.interpolateBucket = function (originalDir, inputDir, outputDir, options, progress) { return __awaiter(void 0, void 0, void 0, function () { | ||
var frameExt, originalArray, frameArray, targetCount, absolute, program, command, child, index; | ||
return __generator(_a, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
frameExt = options.pngFrames ? "png" : "jpg"; | ||
originalArray = fs_1.default.readdirSync(originalDir).map(function (f) { return "".concat(originalDir, "/").concat(f); }).filter(function (f) { return path_1.default.extname(f) === ".".concat(frameExt); }); | ||
originalArray = originalArray.sort(new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare); | ||
frameArray = fs_1.default.readdirSync(inputDir).map(function (f) { return "".concat(inputDir, "/").concat(f); }).filter(function (f) { return path_1.default.extname(f) === ".".concat(frameExt); }); | ||
frameArray = frameArray.sort(new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare); | ||
if (!options.multiplier) | ||
options.multiplier = 2; | ||
targetCount = frameArray.length * options.multiplier; | ||
@@ -175,3 +257,3 @@ absolute = options.rifePath ? path_1.default.normalize(options.rifePath).replace(/\\/g, "/") : path_1.default.join(__dirname, "../rife"); | ||
program = "cd \"".concat(absolute, "\" && cd linux && ./rife-ncnn-vulkan"); | ||
command = "".concat(program, " -i \"").concat(inputDir, "\" -o \"").concat(outputDir, "\" -m \"rife-v4.6\" -f \"frame%08d.").concat(frameExt, "\" -n ").concat(targetCount, " -v"); | ||
command = "".concat(program, " -i \"").concat(inputDir, "\" -o \"").concat(outputDir, "\" -m \"rife-v4.6\" -f \"frame%d.").concat(frameExt, "\" -n ").concat(targetCount, " -v"); | ||
if (options.threads) | ||
@@ -185,12 +267,16 @@ command += " -j ".concat(options.threads, ":").concat(options.threads, ":").concat(options.threads); | ||
var name = (_b = chunk.match(/(frame)(.*?)(?= )/)) === null || _b === void 0 ? void 0 : _b[0]; | ||
var newIndex = frameArray.findIndex(function (f) { return path_1.default.basename(f) === name; }); | ||
var newIndex = originalArray.findIndex(function (f) { return path_1.default.basename(f) === name; }); | ||
if (newIndex > index) | ||
index = newIndex; | ||
var percent = 100 / (frameArray.length - 1) * index; | ||
if (progress) | ||
progress(percent); | ||
var percent = 100 / (originalArray.length - 1) * index; | ||
if (progress) { | ||
var stop_2 = progress(percent); | ||
if (stop_2) { | ||
child.stdio.forEach(function (s) { return s.destroy(); }); | ||
child.kill("SIGINT"); | ||
return true; | ||
} | ||
} | ||
}); | ||
child.on("close", function () { | ||
if (progress) | ||
progress(100); | ||
resolve(); | ||
@@ -201,6 +287,110 @@ }); | ||
_b.sent(); | ||
return [2 /*return*/, outputDir]; | ||
return [2 /*return*/, false]; | ||
} | ||
}); | ||
}); }; | ||
Rife.interpolateDirectory = function (inputDir, outputDir, options, progress) { return __awaiter(void 0, void 0, void 0, function () { | ||
var frameExt, frameArray, targetCount, splitArray, bucketDir, interBucketDir, _loop_1, i, state_1, i, bucket, interBucket, cancel, stop_3, interArray, _loop_2, i, index; | ||
return __generator(_a, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
frameExt = options.pngFrames ? "png" : "jpg"; | ||
frameArray = fs_1.default.readdirSync(inputDir).map(function (f) { return "".concat(inputDir, "/").concat(f); }).filter(function (f) { return path_1.default.extname(f) === ".".concat(frameExt); }); | ||
frameArray = frameArray.sort(new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare); | ||
if (!options.multiplier) | ||
options.multiplier = 2; | ||
targetCount = frameArray.length * options.multiplier; | ||
splitArray = _a.splitArray(frameArray, 1000); | ||
bucketDir = path_1.default.join(outputDir, "buckets"); | ||
interBucketDir = path_1.default.join(outputDir, "interBuckets"); | ||
if (!fs_1.default.existsSync(bucketDir)) | ||
fs_1.default.mkdirSync(bucketDir, { recursive: true }); | ||
if (!fs_1.default.existsSync(interBucketDir)) | ||
fs_1.default.mkdirSync(interBucketDir, { recursive: true }); | ||
_loop_1 = function (i) { | ||
var bucket, stop_4; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
bucket = path_1.default.join(bucketDir, String(i + 1)); | ||
if (!fs_1.default.existsSync(bucket)) | ||
fs_1.default.mkdirSync(bucket, { recursive: true }); | ||
if (fs_1.default.readdirSync(bucket).length === 1000) | ||
return [2 /*return*/, "continue"]; | ||
return [4 /*yield*/, Promise.all(splitArray[i].map(function (img) { | ||
var dest = path_1.default.join(bucket, path_1.default.basename(img)); | ||
fs_1.default.renameSync(img, dest); | ||
}))]; | ||
case 1: | ||
_c.sent(); | ||
if (progress) { | ||
stop_4 = progress(null); | ||
if (stop_4) | ||
return [2 /*return*/, { value: true }]; | ||
} | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}; | ||
i = 0; | ||
_b.label = 1; | ||
case 1: | ||
if (!(i < splitArray.length)) return [3 /*break*/, 4]; | ||
return [5 /*yield**/, _loop_1(i)]; | ||
case 2: | ||
state_1 = _b.sent(); | ||
if (typeof state_1 === "object") | ||
return [2 /*return*/, state_1.value]; | ||
_b.label = 3; | ||
case 3: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 4: | ||
i = 0; | ||
_b.label = 5; | ||
case 5: | ||
if (!(i < splitArray.length)) return [3 /*break*/, 8]; | ||
bucket = path_1.default.join(bucketDir, String(i + 1)); | ||
interBucket = path_1.default.join(interBucketDir, String(i + 1)); | ||
if (!fs_1.default.existsSync(interBucket)) | ||
fs_1.default.mkdirSync(interBucket, { recursive: true }); | ||
if (fs_1.default.readdirSync(interBucket).length === 1000 * options.multiplier) | ||
return [3 /*break*/, 7]; | ||
return [4 /*yield*/, _a.interpolateBucket(inputDir, bucket, interBucket, options, progress)]; | ||
case 6: | ||
cancel = _b.sent(); | ||
if (cancel) | ||
return [2 /*return*/, true]; | ||
if (progress) { | ||
stop_3 = progress(null); | ||
if (stop_3) | ||
return [2 /*return*/, true]; | ||
} | ||
_b.label = 7; | ||
case 7: | ||
i++; | ||
return [3 /*break*/, 5]; | ||
case 8: | ||
if (progress) | ||
progress(100); | ||
interArray = []; | ||
_loop_2 = function (i) { | ||
var interBucket = path_1.default.join(interBucketDir, String(i + 1)); | ||
var files = fs_1.default.readdirSync(interBucket).map(function (f) { return path_1.default.join(interBucket, f); }); | ||
files = files.sort(new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare); | ||
interArray.push.apply(interArray, files); | ||
}; | ||
for (i = 0; i < splitArray.length; i++) { | ||
_loop_2(i); | ||
} | ||
index = fs_1.default.readdirSync(outputDir).length - 2; | ||
return [4 /*yield*/, Promise.all(interArray.map(function (file, i) { | ||
fs_1.default.renameSync(file, path_1.default.join(outputDir, "frame".concat(index + i).concat(path_1.default.extname(interArray[i])))); | ||
}))]; | ||
case 9: | ||
_b.sent(); | ||
return [2 /*return*/, false]; | ||
} | ||
}); | ||
}); }; | ||
Rife.parseTransparentColor = function (color) { | ||
@@ -262,3 +452,3 @@ return Number("0x".concat(color.replace(/^#/, ""))); | ||
} | ||
var frameExt, frames, _b, folder, image, local, frameDest, resume, constraint, step, frameArray, delayArray, interlopDest, cancel, interlopFrames, newDelayArray, i, j, finalDest; | ||
var frameExt, frames, _b, folder, image, local, frameDest, constraint, step, frameArray, delayArray, interlopDest, cancel, interlopFrames, newDelayArray, i, j, finalDest; | ||
return __generator(_a, function (_c) { | ||
@@ -281,3 +471,2 @@ switch (_c.label) { | ||
frameDest = "".concat(folder, "/").concat(path_1.default.basename(input, path_1.default.extname(input)), "Frames"); | ||
resume = 0; | ||
fs_1.default.mkdirSync(frameDest, { recursive: true }); | ||
@@ -296,7 +485,6 @@ constraint = options.speed > 1 ? frames.length / options.speed : frames.length; | ||
fs_1.default.mkdirSync(interlopDest, { recursive: true }); | ||
cancel = false; | ||
options.rename = ""; | ||
return [4 /*yield*/, _a.interpolateDirectory(frameDest, interlopDest, options, progress)]; | ||
case 3: | ||
_c.sent(); | ||
cancel = _c.sent(); | ||
interlopFrames = fs_1.default.readdirSync(interlopDest).map(function (f) { return "".concat(interlopDest, "/").concat(f); }).filter(function (f) { return path_1.default.extname(f) === ".".concat(frameExt); }); | ||
@@ -366,3 +554,3 @@ interlopFrames = interlopFrames.sort(new Intl.Collator(undefined, { numeric: true, sensitivity: "base" }).compare); | ||
(0, fluent_ffmpeg_1.default)(input).outputOptions(__spreadArray([], framerate, true)) | ||
.save("".concat(frameDest, "/frame%08d.").concat(frameExt)) | ||
.save("".concat(frameDest, "/frame%d.").concat(frameExt)) | ||
.on("end", function () { return resolve(); }); | ||
@@ -388,7 +576,6 @@ })]; | ||
fs_1.default.mkdirSync(interlopDest, { recursive: true }); | ||
cancel = false; | ||
options.rename = ""; | ||
return [4 /*yield*/, _a.interpolateDirectory(frameDest, interlopDest, options, progress)]; | ||
case 8: | ||
_d.sent(); | ||
cancel = _d.sent(); | ||
tempDest = "".concat(interlopDest, "/temp.mp4"); | ||
@@ -405,3 +592,3 @@ finalDest = path_1.default.join(folder, image); | ||
return [4 /*yield*/, new Promise(function (resolve) { | ||
(0, fluent_ffmpeg_1.default)("".concat(interlopDest, "/frame%08d.").concat(frameExt)).input(audio).outputOptions(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], targetFramerate, true), codec, true), crf, true), colorFlags, true), filter_1, true)) | ||
(0, fluent_ffmpeg_1.default)("".concat(interlopDest, "/frame%d.").concat(frameExt)).input(audio).outputOptions(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], targetFramerate, true), codec, true), crf, true), colorFlags, true), filter_1, true)) | ||
.save("".concat(interlopDest, "/").concat(image)) | ||
@@ -430,3 +617,3 @@ .on("end", function () { return resolve(); }); | ||
return [4 /*yield*/, new Promise(function (resolve) { | ||
(0, fluent_ffmpeg_1.default)("".concat(interlopDest, "/frame%08d.").concat(frameExt)).outputOptions(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], targetFramerate, true), codec, true), crf, true), colorFlags, true), filter_2, true)) | ||
(0, fluent_ffmpeg_1.default)("".concat(interlopDest, "/frame%d.").concat(frameExt)).outputOptions(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], targetFramerate, true), codec, true), crf, true), colorFlags, true), filter_2, true)) | ||
.save(tempDest) | ||
@@ -433,0 +620,0 @@ .on("end", function () { return resolve(); }); |
{ | ||
"name": "rife-fps", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "Video framerate interlopation with rife", | ||
@@ -5,0 +5,0 @@ "main": "dist/rife.js", |
150
rife.ts
@@ -28,2 +28,3 @@ import util from "util" | ||
transparentColor?: string | ||
parallelFrames?: number | ||
} | ||
@@ -84,3 +85,28 @@ | ||
public static interpolateDirectory = async (inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void) => { | ||
private static splitArray = (array: any[], chunkSize: number) => { | ||
const result = [] | ||
for (let i = 0; i < array.length; i += chunkSize) { | ||
result.push(array.slice(i, i + chunkSize)) | ||
} | ||
return result | ||
} | ||
public static interpolateFrame = async (input1: string, input2: string, outputPath: string, options?: RifeOptions) => { | ||
let absolute = options.rifePath ? path.normalize(options.rifePath).replace(/\\/g, "/") : path.join(__dirname, "../rife") | ||
let program = `cd "${absolute}" && cd windows && rife-ncnn-vulkan.exe` | ||
if (process.platform === "darwin") program = `cd "${absolute}" && cd mac && ./rife-ncnn-vulkan` | ||
if (process.platform === "linux") program = `cd "${absolute}" && cd linux && ./rife-ncnn-vulkan` | ||
let command = `${program} -0 "${input1}" -1 "${input2}" -o "${outputPath}" -m "rife-v4.6"` | ||
if (options.threads) command += ` -j ${options.threads}:${options.threads}:${options.threads}` | ||
const child = child_process.exec(command) | ||
await new Promise<void>((resolve, reject) => { | ||
child.on("close", () => { | ||
resolve() | ||
}) | ||
}) | ||
return outputPath | ||
} | ||
public static interpolateDirectorySingle = async (inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => { | ||
let frameExt = options.pngFrames ? "png" : "jpg" | ||
@@ -90,2 +116,32 @@ let frameArray = fs.readdirSync(inputDir).map((f) => `${inputDir}/${f}`).filter((f) => path.extname(f) === `.${frameExt}`) | ||
if (!options.multiplier) options.multiplier = 2 | ||
let resume = 0 | ||
const existing = fs.readdirSync(outputDir) | ||
if (existing.length) resume = Math.floor(existing.length / options.multiplier) | ||
let total = frameArray.length * options.multiplier | ||
for (let i = resume; i < frameArray.length; i++) { | ||
let block = [frameArray[i]] | ||
for (let j = 0; j < options.multiplier; j++) { | ||
const index = i * options.multiplier + j | ||
const outputPath = path.join(outputDir, `frame${index}.${frameExt}`) | ||
const input2 = frameArray[i + 1] ? frameArray[i + 1] : frameArray[i] | ||
await Rife.interpolateFrame(block[block.length - 1], input2, outputPath, options) | ||
block.push(outputPath) | ||
if (progress) { | ||
const stop = progress(100 / total * index) | ||
if (stop) return true | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
public static interpolateBucket = async (originalDir: string, inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => { | ||
let frameExt = options.pngFrames ? "png" : "jpg" | ||
let originalArray = fs.readdirSync(originalDir).map((f) => `${originalDir}/${f}`).filter((f) => path.extname(f) === `.${frameExt}`) | ||
originalArray = originalArray.sort(new Intl.Collator(undefined, {numeric: true, sensitivity: "base"}).compare) | ||
let frameArray = fs.readdirSync(inputDir).map((f) => `${inputDir}/${f}`).filter((f) => path.extname(f) === `.${frameExt}`) | ||
frameArray = frameArray.sort(new Intl.Collator(undefined, {numeric: true, sensitivity: "base"}).compare) | ||
if (!options.multiplier) options.multiplier = 2 | ||
const targetCount = frameArray.length * options.multiplier | ||
@@ -96,3 +152,3 @@ let absolute = options.rifePath ? path.normalize(options.rifePath).replace(/\\/g, "/") : path.join(__dirname, "../rife") | ||
if (process.platform === "linux") program = `cd "${absolute}" && cd linux && ./rife-ncnn-vulkan` | ||
let command = `${program} -i "${inputDir}" -o "${outputDir}" -m "rife-v4.6" -f "frame%08d.${frameExt}" -n ${targetCount} -v` | ||
let command = `${program} -i "${inputDir}" -o "${outputDir}" -m "rife-v4.6" -f "frame%d.${frameExt}" -n ${targetCount} -v` | ||
if (options.threads) command += ` -j ${options.threads}:${options.threads}:${options.threads}` | ||
@@ -105,15 +161,78 @@ | ||
const name = chunk.match(/(frame)(.*?)(?= )/)?.[0] | ||
const newIndex = frameArray.findIndex((f: string) => path.basename(f) === name) | ||
const newIndex = originalArray.findIndex((f: string) => path.basename(f) === name) | ||
if (newIndex > index) index = newIndex | ||
const percent = 100 / (frameArray.length - 1) * index | ||
if (progress) progress(percent) | ||
const percent = 100 / (originalArray.length - 1) * index | ||
if (progress) { | ||
const stop = progress(percent) | ||
if (stop) { | ||
child.stdio.forEach((s) => s.destroy()) | ||
child.kill("SIGINT") | ||
return true | ||
} | ||
} | ||
}) | ||
child.on("close", () => { | ||
if (progress) progress(100) | ||
resolve() | ||
}) | ||
}) | ||
return outputDir | ||
return false | ||
} | ||
public static interpolateDirectory = async (inputDir: string, outputDir: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => { | ||
let frameExt = options.pngFrames ? "png" : "jpg" | ||
let frameArray = fs.readdirSync(inputDir).map((f) => `${inputDir}/${f}`).filter((f) => path.extname(f) === `.${frameExt}`) | ||
frameArray = frameArray.sort(new Intl.Collator(undefined, {numeric: true, sensitivity: "base"}).compare) | ||
if (!options.multiplier) options.multiplier = 2 | ||
const targetCount = frameArray.length * options.multiplier | ||
const splitArray = Rife.splitArray(frameArray, 1000) | ||
const bucketDir = path.join(outputDir, "buckets") | ||
const interBucketDir = path.join(outputDir, "interBuckets") | ||
if (!fs.existsSync(bucketDir)) fs.mkdirSync(bucketDir, {recursive: true}) | ||
if (!fs.existsSync(interBucketDir)) fs.mkdirSync(interBucketDir, {recursive: true}) | ||
for (let i = 0; i < splitArray.length; i++) { | ||
const bucket = path.join(bucketDir, String(i+1)) | ||
if (!fs.existsSync(bucket)) fs.mkdirSync(bucket, {recursive: true}) | ||
if (fs.readdirSync(bucket).length === 1000) continue | ||
await Promise.all(splitArray[i].map((img: string) => { | ||
const dest = path.join(bucket, path.basename(img)) | ||
fs.renameSync(img, dest) | ||
})) | ||
if (progress) { | ||
const stop = progress(null) | ||
if (stop) return true | ||
} | ||
} | ||
for (let i = 0; i < splitArray.length; i++) { | ||
const bucket = path.join(bucketDir, String(i+1)) | ||
const interBucket = path.join(interBucketDir, String(i+1)) | ||
if (!fs.existsSync(interBucket)) fs.mkdirSync(interBucket, {recursive: true}) | ||
if (fs.readdirSync(interBucket).length === 1000 * options.multiplier) continue | ||
let cancel = await Rife.interpolateBucket(inputDir, bucket, interBucket, options, progress) | ||
if (cancel) return true | ||
if (progress) { | ||
const stop = progress(null) | ||
if (stop) return true | ||
} | ||
} | ||
if (progress) progress(100) | ||
let interArray = [] | ||
for (let i = 0; i < splitArray.length; i++) { | ||
const interBucket = path.join(interBucketDir, String(i+1)) | ||
let files = fs.readdirSync(interBucket).map((f: string) => path.join(interBucket, f)) | ||
files = files.sort(new Intl.Collator(undefined, {numeric: true, sensitivity: "base"}).compare) | ||
interArray.push(...files) | ||
} | ||
const index = fs.readdirSync(outputDir).length - 2 | ||
await Promise.all(interArray.map((file, i) => { | ||
fs.renameSync(file, path.join(outputDir, `frame${index+i}${path.extname(interArray[i])}`)) | ||
})) | ||
return false | ||
} | ||
private static parseTransparentColor = (color: string) => { | ||
@@ -154,3 +273,3 @@ return Number(`0x${color.replace(/^#/, "")}`) | ||
public static interpolateGIF = async (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void) => { | ||
public static interpolateGIF = async (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => { | ||
options = {...options} | ||
@@ -167,3 +286,2 @@ if (!output) output = "./" | ||
let frameDest = `${folder}/${path.basename(input, path.extname(input))}Frames` | ||
let resume = 0 | ||
fs.mkdirSync(frameDest, {recursive: true}) | ||
@@ -191,5 +309,4 @@ const constraint = options.speed > 1 ? frames.length / options.speed : frames.length | ||
let cancel = false | ||
options.rename = "" | ||
await Rife.interpolateDirectory(frameDest, interlopDest, options, progress) | ||
let cancel = await Rife.interpolateDirectory(frameDest, interlopDest, options, progress) | ||
@@ -215,3 +332,3 @@ let interlopFrames = fs.readdirSync(interlopDest).map((f) => `${interlopDest}/${f}`).filter((f) => path.extname(f) === `.${frameExt}`) | ||
public static interpolateVideo = async (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void) => { | ||
public static interpolateVideo = async (input: string, output?: string, options?: RifeOptions, progress?: (percent: number) => void | boolean) => { | ||
options = {...options} | ||
@@ -241,3 +358,3 @@ if (!output) output = "./" | ||
ffmpeg(input).outputOptions([...framerate]) | ||
.save(`${frameDest}/frame%08d.${frameExt}`) | ||
.save(`${frameDest}/frame%d.${frameExt}`) | ||
.on("end", () => resolve()) | ||
@@ -256,5 +373,4 @@ }) | ||
let cancel = false | ||
options.rename = "" | ||
await Rife.interpolateDirectory(frameDest, interlopDest, options, progress) | ||
let cancel = await Rife.interpolateDirectory(frameDest, interlopDest, options, progress) | ||
@@ -270,3 +386,3 @@ let tempDest = `${interlopDest}/temp.mp4` | ||
await new Promise<void>((resolve) => { | ||
ffmpeg(`${interlopDest}/frame%08d.${frameExt}`).input(audio).outputOptions([...targetFramerate, ...codec, ...crf, ...colorFlags, ...filter]) | ||
ffmpeg(`${interlopDest}/frame%d.${frameExt}`).input(audio).outputOptions([...targetFramerate, ...codec, ...crf, ...colorFlags, ...filter]) | ||
.save(`${interlopDest}/${image}`) | ||
@@ -289,3 +405,3 @@ .on("end", () => resolve()) | ||
await new Promise<void>((resolve) => { | ||
ffmpeg(`${interlopDest}/frame%08d.${frameExt}`).outputOptions([...targetFramerate, ...codec, ...crf, ...colorFlags, ...filter]) | ||
ffmpeg(`${interlopDest}/frame%d.${frameExt}`).outputOptions([...targetFramerate, ...codec, ...crf, ...colorFlags, ...filter]) | ||
.save(tempDest) | ||
@@ -292,0 +408,0 @@ .on("end", () => resolve()) |
74879652
1115