Phar support, more plugins and presets
This commit is contained in:
parent
1938337bb0
commit
0ca1da06e7
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/vendor
|
/vendor
|
||||||
|
composer.lock
|
||||||
|
114
PRESETS.md
Normal file
114
PRESETS.md
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
VfxApply Presets Documentation
|
||||||
|
==============================
|
||||||
|
|
||||||
|
|
||||||
|
## Preset keys
|
||||||
|
|
||||||
|
**Common keys**
|
||||||
|
|
||||||
|
| Key | Type | Description
|
||||||
|
|------.------------|----------------|-------------------------------------------
|
||||||
|
| `preset/name` | *String* | A description string for this preset
|
||||||
|
| `preset/group` | *String|Null* | Logical grouping
|
||||||
|
| `preset/plugin` | *String* | The id of the plugin this preset is for
|
||||||
|
| `preset/props` | *Array* | Properties used by the plugin
|
||||||
|
| `preset/params` | *Array|Null* | Parameters for tweaking
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
**ffmpeg**
|
||||||
|
|
||||||
|
| Property | Type | Description
|
||||||
|
|-------------------|----------------|-------------------------------------------
|
||||||
|
| `filter` | *String* | The filter string, with optional param placeholders
|
||||||
|
| `extra` | *String|Null* | Extra options to pass on the ffmpeg command line
|
||||||
|
| `type` | *Enum|Null* | ffmpeg filter type; One of `complex` (default), `audio` or `video`
|
||||||
|
|
||||||
|
|
||||||
|
**natron**
|
||||||
|
|
||||||
|
| Property | Type | Description
|
||||||
|
|------.------------|--------------------|-------------------------------------------
|
||||||
|
| `project` | *String* | Natron project file name
|
||||||
|
| `input` | *String|Int|Null* | Extra options to pass on the ffmpeg command line
|
||||||
|
| `output` | *String|Int|Null* | ffmpeg filter type; One of `complex`, `audio` or `video`
|
||||||
|
| `framescale` | *Float* | Ratio of output frames to input files, 2.0=twice as many out as in=half speed
|
||||||
|
|
||||||
|
**executor**
|
||||||
|
|
||||||
|
| Property | Type | Description
|
||||||
|
|------.------------|--------------------|-------------------------------------------
|
||||||
|
| `set` | *Array* | Define variables
|
||||||
|
| `script` | *Array* | Define commands
|
||||||
|
| `set/%/value` | *String* | Set variable % to value.
|
||||||
|
| `set/%/escape` | *Bool* | If true, the resulting vriable will be escaped
|
||||||
|
| `script/%/info` | *String* | Info about what this step is doing
|
||||||
|
| `script/%/exec` | *String* | Command to execute
|
||||||
|
| `script/%/parse` | *Map* | Parse output from command, see docs for plugin
|
||||||
|
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
All parameters must specify `label` and `type`. The remaining keys are depending on the
|
||||||
|
type of parameter.
|
||||||
|
|
||||||
|
**float**
|
||||||
|
|
||||||
|
Float parameters need to specify `min`, `max`, `default` and optionally `step`.
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### ffmpeg
|
||||||
|
|
||||||
|
preset:
|
||||||
|
name: Normalize audio level
|
||||||
|
group: ffmpeg/audio
|
||||||
|
plugin: ffmpeg
|
||||||
|
props:
|
||||||
|
filter: "dynaudnorm=m={maxgain}:s={compress}"
|
||||||
|
extra: "-c:v copy"
|
||||||
|
type: complex
|
||||||
|
params:
|
||||||
|
compress: { label:"Compression factor", type:float, min:0.0, max:30.0, default:0.0 }
|
||||||
|
maxgain: { label:"Max gain factor", type:float, min:0.0, max:100.0, default:10.0 }
|
||||||
|
|
||||||
|
### natron
|
||||||
|
|
||||||
|
preset:
|
||||||
|
name: Apply a CCTV look to the video
|
||||||
|
group: natron
|
||||||
|
plugin: natron
|
||||||
|
props:
|
||||||
|
project: natron-cctv.ntp
|
||||||
|
reader: Reader1
|
||||||
|
writer: Writer1
|
||||||
|
|
||||||
|
### executor
|
||||||
|
|
||||||
|
preset:
|
||||||
|
name: Stabilize video clip (two-pass)
|
||||||
|
group: video
|
||||||
|
plugin: executor
|
||||||
|
props:
|
||||||
|
set:
|
||||||
|
inputtrf: { value:"{%uinput}.trf", escape:true }
|
||||||
|
script:
|
||||||
|
analyze:
|
||||||
|
info: Getting stabilization vectors
|
||||||
|
exec: "transcode -i {%input} -J stabilize"
|
||||||
|
parse:
|
||||||
|
from: 'stderr'
|
||||||
|
regex: '/encoding frames \[0-([0-9]+?)\],\s+([0-9\.]+?) fps/'
|
||||||
|
frame:1
|
||||||
|
eta:2
|
||||||
|
stabilize:
|
||||||
|
info: Stabilizing video
|
||||||
|
exec: "transcode -i {%input} -o {%output} -J transform -y xvid"
|
||||||
|
parse:
|
||||||
|
from: 'stderr'
|
||||||
|
regex: '/encoding frames \[0-([0-9]+?)\],\s+([0-9\.]+?) fps/'
|
||||||
|
frame:1
|
||||||
|
eta:2
|
||||||
|
cleanup:
|
||||||
|
exec: "rm {%inputtrf}"
|
26
README.md
26
README.md
@ -9,11 +9,12 @@ Natron pipeline.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
vfxapply [-i <input>] [-o <output>|-O] [-p <preset>] [-c <key>=<value>]
|
vfxapply [-i <input>] [-o <output>|-O] [-l] [-p <preset>] [-c <key>=<value>]
|
||||||
|
|
||||||
-i Set the input file (if omitted, a file picker will be displayed)
|
-i Set the input file (if omitted, a file picker will be displayed)
|
||||||
-o Set the output file (if omitted, a file picker will be displayed)
|
-o Set the output file (if omitted, a file picker will be displayed)
|
||||||
-O Automatically assign output filename based on input filename
|
-O Automatically assign output filename
|
||||||
|
-l List presets
|
||||||
-p Select the preset to apply
|
-p Select the preset to apply
|
||||||
-c Specify parameters for the preset
|
-c Specify parameters for the preset
|
||||||
-b Batch mode, input parameter is a list of files
|
-b Batch mode, input parameter is a list of files
|
||||||
@ -33,4 +34,25 @@ Examples:
|
|||||||
|
|
||||||
### ffmpeg
|
### ffmpeg
|
||||||
|
|
||||||
|
This plugin allows for both video filters, audio filters and complex filters
|
||||||
|
to f.ex. normalize audio or generate spectrograms of the audio channes
|
||||||
|
|
||||||
### natron
|
### natron
|
||||||
|
|
||||||
|
*This plugin is currently broken*
|
||||||
|
|
||||||
|
### executor
|
||||||
|
|
||||||
|
The executor plugin does as the name suggests; it executes one or more custom
|
||||||
|
commands on the input file. The command output can be parsed using regular
|
||||||
|
expressions to present the progress.
|
||||||
|
|
||||||
|
### melt
|
||||||
|
|
||||||
|
The melt plugin uses the MLT library, the same as is used by f.ex. Kdenlive
|
||||||
|
to process the media.
|
||||||
|
|
||||||
|
### transcode
|
||||||
|
|
||||||
|
Transcode uses the transcode tool from transcoder.org. While powerful, it
|
||||||
|
works best with AVI files.
|
||||||
|
31
check-requirements
Executable file
31
check-requirements
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function group {
|
||||||
|
echo -e "\e[1m$1\e[0m"
|
||||||
|
}
|
||||||
|
function good {
|
||||||
|
echo -e "[\e[92m ok \e[0m] \e[32m$1\e[0m"
|
||||||
|
}
|
||||||
|
function bad {
|
||||||
|
echo -e "[\e[91mfail\e[0m] \e[31m$1\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
function check {
|
||||||
|
local NAME
|
||||||
|
test -z "$2" || NAME="$2"
|
||||||
|
test -z "$NAME" && NAME="$1"
|
||||||
|
if [ -z "$(which $1)" ]; then
|
||||||
|
bad "$NAME is missing"
|
||||||
|
else
|
||||||
|
good "Found $NAME at $(which $1)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
group "Checking for zenity"
|
||||||
|
check "zenity"
|
||||||
|
check "dialog"
|
||||||
|
|
||||||
|
group "Checking tools"
|
||||||
|
check "ffprobe"
|
||||||
|
check "ffmpeg"
|
||||||
|
check "transcode"
|
@ -1,23 +1,5 @@
|
|||||||
preset:
|
Executor Plugin for VfxApply
|
||||||
name: Stabilize video clip
|
============================
|
||||||
group: video
|
|
||||||
plugin: transcode
|
|
||||||
props:
|
|
||||||
set:
|
|
||||||
inputtrf: { value:"{%uinput}.trf", escape:true }
|
|
||||||
script:
|
|
||||||
analyze:
|
|
||||||
info: Getting stabilization vectors
|
|
||||||
exec: "transcode -J stabilize -i {%input}"
|
|
||||||
parse: { regex: '/^encoding frames [0-([0-9]+?)], ([0-9\.]+?) fps/', frame:1, eta:2 }
|
|
||||||
stabilize:
|
|
||||||
info Stabilizing video
|
|
||||||
exec: "transcode -J transform -i {%input} -o {%output}"
|
|
||||||
parse: { regex: '/^encoding frames [0-([0-9]+?)], ([0-9\.]+?) fps/', frame:1, eta:2 }
|
|
||||||
cleanup:
|
|
||||||
exec: "rm {%inputtrf}"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
@ -25,6 +7,16 @@ Each script command is named, and will be executed in order of appearance. Error
|
|||||||
will be reported and execution will stop if the exit code is non-zero, using
|
will be reported and execution will stop if the exit code is non-zero, using
|
||||||
the names as logical pointers.
|
the names as logical pointers.
|
||||||
|
|
||||||
|
props:
|
||||||
|
set:
|
||||||
|
<varname>: { value:<expr>, escape:<bool> }
|
||||||
|
script:
|
||||||
|
<step>:
|
||||||
|
info: <string>
|
||||||
|
exec: <commmand>
|
||||||
|
parse: <parse-expr>
|
||||||
|
|
||||||
|
|
||||||
### Command lines
|
### Command lines
|
||||||
|
|
||||||
Command line uses placeholders.
|
Command line uses placeholders.
|
||||||
@ -40,11 +32,35 @@ Any parameters will also be available:
|
|||||||
|
|
||||||
And you can use `set` to assign stuff to variables.
|
And you can use `set` to assign stuff to variables.
|
||||||
|
|
||||||
|
|
||||||
|
### Setting variables
|
||||||
|
|
||||||
|
Setting variables is done using the `set` prop. The core syntax is:
|
||||||
|
|
||||||
|
set:
|
||||||
|
myvarname: { value:"MyValue" }
|
||||||
|
|
||||||
|
Additionally, `escape` can be used to flag that the value need to be
|
||||||
|
escaped for the command line.
|
||||||
|
|
||||||
|
myvarname: { value:"SomeValue", escape:true }
|
||||||
|
|
||||||
|
Variables set this way can be used for the command line, and the same
|
||||||
|
expressions can be used to define vars:
|
||||||
|
|
||||||
|
set:
|
||||||
|
tempfile: { value:"{%uinput}.tmp", escape:true }
|
||||||
|
script:
|
||||||
|
first:
|
||||||
|
exec "first --temp-file {%tempfile}"
|
||||||
|
|
||||||
|
|
||||||
### Parsing output
|
### Parsing output
|
||||||
|
|
||||||
To parse the output, add a `parse` key to the command block.
|
To parse the output, add a `parse` key to the command block.
|
||||||
|
|
||||||
parse:
|
parse:
|
||||||
regex: <- expression
|
regex: <- expression
|
||||||
|
from: <- stream for comparison (stdout or stderr)
|
||||||
frame: <- index of frame number, or leave out
|
frame: <- index of frame number, or leave out
|
||||||
fps: <- index of frames per second, or leave out
|
fps: <- index of frames per second, or leave out
|
||||||
|
24
plugins/melt/plugin.php
Normal file
24
plugins/melt/plugin.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace VfxApply\Plugin\Melt;
|
||||||
|
|
||||||
|
use VfxApply\Plugin;
|
||||||
|
use VfxApply\Input;
|
||||||
|
use VfxApply\Output;
|
||||||
|
use VfxApply\Preset;
|
||||||
|
|
||||||
|
class MeltPlugin extends Plugin
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return "melt";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyPreset(Preset $preset, Input $input, Output $output)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MeltPlugin();
|
24
plugins/transcode/plugin.php
Normal file
24
plugins/transcode/plugin.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace VfxApply\Plugin\Transcode;
|
||||||
|
|
||||||
|
use VfxApply\Plugin;
|
||||||
|
use VfxApply\Input;
|
||||||
|
use VfxApply\Output;
|
||||||
|
use VfxApply\Preset;
|
||||||
|
|
||||||
|
class TranscodePlugin extends Plugin
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return "transcode";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyPreset(Preset $preset, Input $input, Output $output)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TranscodePlugin();
|
18
presets/executor/executor-vidstab-ffmpeg.yml
Normal file
18
presets/executor/executor-vidstab-ffmpeg.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
preset:
|
||||||
|
name: Stabilize video clip (two-pass, ffmpeg)
|
||||||
|
group: video
|
||||||
|
plugin: executor
|
||||||
|
props:
|
||||||
|
set:
|
||||||
|
inputtrf: { value:"{%uinput}.trf", escape:true }
|
||||||
|
script:
|
||||||
|
analyze:
|
||||||
|
info: Getting stabilization vectors
|
||||||
|
exec: "ffmpeg -i {%input} -vf vidstabdetect=stepsize=6:shakiness=8:accuracy=9:result={%inputtrf} -f null -"
|
||||||
|
parse: { from: 'stderr', regex: '/^frame=[\s]*([0-9]+)\s/', frame:1 }
|
||||||
|
stabilize:
|
||||||
|
info: Stabilizing video
|
||||||
|
exec: "ffmpeg -i {%input} -vf vidstabtransform=input={%inputtrf}:zoom=1:smoothing=30,unsharp=5:5:0.8:3:3:0.4 -vcodec libx264 -preset slow -tune film -crf 18 -acodec copy {%output}"
|
||||||
|
parse: { from: 'stderr', regex: '/^frame=[\s]*([0-9]+)\s/', frame:1 }
|
||||||
|
cleanup:
|
||||||
|
exec: "rm {%inputtrf}"
|
@ -2,6 +2,10 @@ preset:
|
|||||||
name: Stabilize video clip (two-pass)
|
name: Stabilize video clip (two-pass)
|
||||||
group: video
|
group: video
|
||||||
plugin: executor
|
plugin: executor
|
||||||
|
info: >
|
||||||
|
This preset uses 'transcode' to stabilize the video clip. As transcode has limited
|
||||||
|
support for other output containers than AVI, the resulting file will be an .AVI
|
||||||
|
file.
|
||||||
props:
|
props:
|
||||||
set:
|
set:
|
||||||
inputtrf: { value:"{%uinput}.trf", escape:true }
|
inputtrf: { value:"{%uinput}.trf", escape:true }
|
||||||
@ -17,18 +21,3 @@ preset:
|
|||||||
parse: { from: 'stderr', regex: '/encoding frames \[0-([0-9]+?)\],\s+([0-9\.]+?) fps/', frame:1, eta:2 }
|
parse: { from: 'stderr', regex: '/encoding frames \[0-([0-9]+?)\],\s+([0-9\.]+?) fps/', frame:1, eta:2 }
|
||||||
cleanup:
|
cleanup:
|
||||||
exec: "ls {%inputtrf}"
|
exec: "ls {%inputtrf}"
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#INPUT="$1"
|
|
||||||
#OUTPUT="$1.stab.avi"
|
|
||||||
#CODEC="-y xvid"
|
|
||||||
|
|
||||||
#if [ -e "$INPUT.trf" ]; then
|
|
||||||
# echo "Cache found, not re-calling stabilize..."
|
|
||||||
#else
|
|
||||||
# Start the deshake process
|
|
||||||
# transcode -J stabilize -i $INPUT || transcode -J stabilize --mplayer_probe -i $INPUT
|
|
||||||
#fi
|
|
||||||
|
|
||||||
# Now, stabilize the video
|
|
||||||
#transcode -J transform -i $INPUT $CODEC -o $OUTPUT
|
|
||||||
|
9
presets/melt/melt-grayscale.yml
Normal file
9
presets/melt/melt-grayscale.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
preset:
|
||||||
|
name: Turn the video into grayscale
|
||||||
|
group: melt
|
||||||
|
plugin: melt
|
||||||
|
props:
|
||||||
|
filters:
|
||||||
|
- { type: greyscale, in: ~, out: ~ }
|
||||||
|
|
||||||
|
# melt test.mp4 -filter greyscale -consumer avformat:output.avi acodec=libmp3lame vcodec=libx264
|
6
presets/transcode/transcode-deshake.yml
Normal file
6
presets/transcode/transcode-deshake.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
preset:
|
||||||
|
name: Deshake video clip (single-pass)
|
||||||
|
group: video
|
||||||
|
plugin: transcode
|
||||||
|
props:
|
||||||
|
filter: deshake
|
@ -12,7 +12,7 @@ class Application
|
|||||||
public function readPlugins()
|
public function readPlugins()
|
||||||
{
|
{
|
||||||
$iter = new \DirectoryIterator(
|
$iter = new \DirectoryIterator(
|
||||||
__DIR__."/../plugins"
|
APP_ROOT."/plugins"
|
||||||
);
|
);
|
||||||
foreach ($iter as $dir) {
|
foreach ($iter as $dir) {
|
||||||
if (!$dir->isDir())
|
if (!$dir->isDir())
|
||||||
@ -27,7 +27,7 @@ class Application
|
|||||||
{
|
{
|
||||||
$iter = new \RecursiveIteratorIterator(
|
$iter = new \RecursiveIteratorIterator(
|
||||||
new \RecursiveDirectoryIterator(
|
new \RecursiveDirectoryIterator(
|
||||||
__DIR__."/../presets"
|
APP_ROOT."//presets"
|
||||||
));
|
));
|
||||||
foreach ($iter as $file) {
|
foreach ($iter as $file) {
|
||||||
if ($file->isDir() || ($file->getExtension()!='yml'))
|
if ($file->isDir() || ($file->getExtension()!='yml'))
|
||||||
@ -83,8 +83,30 @@ class Application
|
|||||||
$this->readPlugins();
|
$this->readPlugins();
|
||||||
$this->readPresets();
|
$this->readPresets();
|
||||||
|
|
||||||
$opts = getopt("i:o:p:l");
|
$opts = getopt("hi:o:p:l");
|
||||||
|
|
||||||
|
if (array_key_exists('h',$opts)) {
|
||||||
|
printf("Usage:\n");
|
||||||
|
foreach([
|
||||||
|
"%s -h",
|
||||||
|
"%s -l",
|
||||||
|
"%s [-i FILE] [-o FILE] [-p PRESET]"
|
||||||
|
] as $example)
|
||||||
|
printf(" ".$example."\n", "vfxapply");
|
||||||
|
printf("Options:\n");
|
||||||
|
foreach ([
|
||||||
|
"-h" => "Show this help",
|
||||||
|
"-i FILE" => "Input filename",
|
||||||
|
"-o FILE" => "Output filename",
|
||||||
|
"-p PRESET" => "Select preset",
|
||||||
|
"-l" => "List presets",
|
||||||
|
] as $opt=>$info)
|
||||||
|
printf(" %-10s %s\n", $opt, $info);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (array_key_exists('l',$opts)) {
|
if (array_key_exists('l',$opts)) {
|
||||||
foreach ($this->presets as $name=>$preset) {
|
foreach ($this->presets as $name=>$preset) {
|
||||||
printf("%s: %s\n", $name, $preset->getName());
|
printf("%s: %s\n", $name, $preset->getName());
|
||||||
@ -110,8 +132,8 @@ class Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
$dur = $input->getVideoDuration();
|
$dur = $input->getVideoDuration();
|
||||||
printf("Input: %s %.2fs (%d frames)\n", $input->getFilename(), $dur->seconds, $dur->frames);
|
printf("Input: \e[1m%s\e[0m %.2fs (%d frames)\n", $input->getFilename(), $dur->seconds, $dur->frames);
|
||||||
printf("Output: %s\n", $output->getFilename());
|
printf("Output: \e[1m%s\e[0m\n", $output->getFilename());
|
||||||
|
|
||||||
if (empty($opts['p'])) {
|
if (empty($opts['p'])) {
|
||||||
if (!($preset = $this->selectPreset())) {
|
if (!($preset = $this->selectPreset())) {
|
||||||
|
@ -11,5 +11,14 @@ define("DIALOG_SAVEFILE", "savefile");
|
|||||||
require_once __DIR__."/../vendor/autoload.php";
|
require_once __DIR__."/../vendor/autoload.php";
|
||||||
|
|
||||||
use VfxApply\Application;
|
use VfxApply\Application;
|
||||||
|
|
||||||
|
// Find the actual root, follow links, and strip the bin part if local
|
||||||
|
if (!($script = dirname(@readlink($_SERVER['SCRIPT_NAME']))))
|
||||||
|
$script = dirname($_SERVER['SCRIPT_NAME']);
|
||||||
|
if (basename($script)=='bin')
|
||||||
|
$script = dirname($script);
|
||||||
|
|
||||||
|
define("APP_ROOT", $script);
|
||||||
|
|
||||||
$app = new Application();
|
$app = new Application();
|
||||||
$app->run();
|
$app->run();
|
Loading…
Reference in New Issue
Block a user