Spaces:
Running
Running
Commit
·
f077067
1
Parent(s):
dba0530
Add speed
Browse files- server-plugins/apply.js +2 -0
- server-plugins/speed.js +55 -0
server-plugins/apply.js
CHANGED
|
@@ -4,12 +4,14 @@ import { SplitRenderPlugin } from './split-render.js';
|
|
| 4 |
import { FramesPlugin } from './frames.js';
|
| 5 |
import { CaptionPlugin } from './generate-captions.js';
|
| 6 |
import { FlattenPathsPlugin } from './flatten-paths.js';
|
|
|
|
| 7 |
|
| 8 |
const pluginRegistry = {
|
| 9 |
'split-media-render': SplitRenderPlugin,
|
| 10 |
'frames': FramesPlugin,
|
| 11 |
'generate-captions': CaptionPlugin,
|
| 12 |
'flatten-paths': FlattenPathsPlugin,
|
|
|
|
| 13 |
};
|
| 14 |
|
| 15 |
export async function applyPluginsPrerender(plugins, originalManuscript, originalManuscriptPath, jobId) {
|
|
|
|
| 4 |
import { FramesPlugin } from './frames.js';
|
| 5 |
import { CaptionPlugin } from './generate-captions.js';
|
| 6 |
import { FlattenPathsPlugin } from './flatten-paths.js';
|
| 7 |
+
import { SpeedPlugin } from './speed.js';
|
| 8 |
|
| 9 |
const pluginRegistry = {
|
| 10 |
'split-media-render': SplitRenderPlugin,
|
| 11 |
'frames': FramesPlugin,
|
| 12 |
'generate-captions': CaptionPlugin,
|
| 13 |
'flatten-paths': FlattenPathsPlugin,
|
| 14 |
+
'speed': SpeedPlugin,
|
| 15 |
};
|
| 16 |
|
| 17 |
export async function applyPluginsPrerender(plugins, originalManuscript, originalManuscriptPath, jobId) {
|
server-plugins/speed.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import _ from 'lodash'
|
| 2 |
+
import fs from 'fs'
|
| 3 |
+
import { Plugin } from './plugin.js';
|
| 4 |
+
import { FFMpegUtils } from 'common-utils';
|
| 5 |
+
|
| 6 |
+
export class SpeedPlugin extends Plugin {
|
| 7 |
+
constructor(name, options) {
|
| 8 |
+
super(name, options);
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
async applyPrerender(originalManuscript, jobId) {
|
| 12 |
+
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
async applyPostrender(originalManuscript, jobId, outFiles) {
|
| 16 |
+
for (let outFile of outFiles) {
|
| 17 |
+
const speedFactor = this.options.speed || 1.0;
|
| 18 |
+
if (speedFactor !== 1.0) {
|
| 19 |
+
|
| 20 |
+
const tempFile = outFile + '.original.mp4';
|
| 21 |
+
fs.renameSync(outFile, tempFile);
|
| 22 |
+
try {
|
| 23 |
+
const pts = 1.0 / speedFactor;
|
| 24 |
+
if (pts <= 0) {
|
| 25 |
+
return
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
// atempo only supports 0.5-2.0, so we chain filters to approximate the target
|
| 29 |
+
let remaining = speedFactor;
|
| 30 |
+
const atempoFilters = [];
|
| 31 |
+
while (remaining > 2.0) {
|
| 32 |
+
atempoFilters.push('atempo=2.0');
|
| 33 |
+
remaining /= 2.0;
|
| 34 |
+
}
|
| 35 |
+
while (remaining < 0.5) {
|
| 36 |
+
atempoFilters.push('atempo=0.5');
|
| 37 |
+
remaining *= 2.0;
|
| 38 |
+
}
|
| 39 |
+
atempoFilters.push(`atempo=${remaining.toFixed(6)}`);
|
| 40 |
+
const audioFilter = atempoFilters.join(',');
|
| 41 |
+
this.log(`Speeding the video ${outFile} by a factor of x${speedFactor}`);
|
| 42 |
+
const cmd = `ffmpeg -i ${tempFile} -filter_complex "[0:v]setpts=${pts.toFixed(6)}*PTS[v];[0:a]${audioFilter}[a]" -map "[v]" -map "[a]" ${outFile}`;
|
| 43 |
+
await FFMpegUtils.execute(cmd);
|
| 44 |
+
fs.unlinkSync(tempFile);
|
| 45 |
+
} catch (err) {
|
| 46 |
+
this.log(`Error applying speed change: ${err}`);
|
| 47 |
+
if (fs.existsSync(outFile)) {
|
| 48 |
+
fs.unlinkSync(outFile);
|
| 49 |
+
}
|
| 50 |
+
fs.renameSync(tempFile, outFile);
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}
|