Phar support, more plugins and presets

This commit is contained in:
Chris 2017-01-13 02:18:46 +01:00
parent 1938337bb0
commit 0ca1da06e7
13 changed files with 328 additions and 43 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/vendor /vendor
composer.lock

114
PRESETS.md Normal file
View 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}"

View File

@ -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
View 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"

View File

@ -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
View 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();

View 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();

View 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}"

View File

@ -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

View 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

View File

@ -0,0 +1,6 @@
preset:
name: Deshake video clip (single-pass)
group: video
plugin: transcode
props:
filter: deshake

View File

@ -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())) {

View File

@ -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();