Automate-Animate-FFmpeg
view release on metacpan or search on metacpan
lib/Automate/Animate/FFmpeg.pm view on Meta::CPAN
use IPC::Run;
use Text::ParseWords;
use Encode;
use Data::Roundtrip qw/perl2dump no-unicode-escape-permanently/;
use Cwd::utf8 qw/abs_path cwd/;
sub new {
my $class = $_[0];
my $params = $_[1];
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $self = {
'input-images' => [],
'output-filename' => undef,
'verbosity' => 0,
# params to ffmpeg must be given as an arrayref
# these are our standard params, they are read only and must
# be supplied here as an ARRAYref
'ffmpeg-standard-params' => ['-c', 'copy', '-c:v', 'copy', '-c:a', 'copy', '-q:a', '0', '-q:v', '1'],
# extra params to ffmpeg can be specified by the caller
lib/Automate/Animate/FFmpeg.pm view on Meta::CPAN
if( $verbos > 1 ){ print "${whoami} (via $parent), line ".__LINE__." : parameter '$ak' set to : ".$params->{$ak}."\n"; }
}
return $self
}
# it spawns ffmpeg as external command via IPC::Run::run(@cmd)
# requires that at least 1 input image was specified before.
# returns 0 on failure, 1 on success
sub make_animation {
my $self = $_[0];
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $verbos = $self->verbosity();
my $cmdret = $self->_build_ffmpeg_cmdline();
if( ! defined $cmdret ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, failed to build ffmpeg command line, call to ".'_build_ffmpeg_cmdline()'." has failed.\n"; return 0 }
my $cmdline = $cmdret->{'cmdline'};
my $tmpfile = $cmdret->{'tmpfile'};
if( $verbos > 0 ){ print "${whoami} (via $parent), line ".__LINE__." : executing system command:\n".join(' ',@$cmdline)."\n" }
my ($in, $out, $err);
my $ret = IPC::Run::run($cmdline, \$in, \$out, \$err);
if( ! $ret ){
lib/Automate/Animate/FFmpeg.pm view on Meta::CPAN
if( $verbos > 0 ){
if( $verbos > 1 ){ print $out."\n" }
print "${whoami} (via $parent), line ".__LINE__." : done, success. Output animation of ".$self->num_input_images()." input images is in '".$self->output_filename()."'.\n"
}
unlink($tmpfile);
return 1;
}
sub _build_ffmpeg_cmdline {
my $self = $_[0];
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $verbos = $self->verbosity();
if( $self->num_input_images() == 0 ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, no input images in store.\n"; return undef }
if( ! defined $self->output_filename() ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, no output filename specified.\n"; return undef }
my $execu = $self->ffmpeg_executable();
if( ! defined $execu ){ print STDERR "$whoami() (via $parent), line ".__LINE__." : error, the path to the ffmpeg executable is undefined. That means that the external, 3rd-party dependency 'ffmpeg' was not located during installation. First you need...
# get a tmp file - only drawback is it is in current working dir
# but on the other hand we do not want caller to delete a directory!
lib/Automate/Animate/FFmpeg.pm view on Meta::CPAN
$self->{'ffmpeg-extra-params'} = $ret;
return $ret
}
sub ffmpeg_standard_params { return $_[0]->{'ffmpeg-standard-params'} }
sub num_input_images { return scalar @{$_[0]->{'input-images'}} }
# specify a text file which holds image filenames, one per line to be added
# hash-comments are understood, empty/only-space lines are removed
# returns 1 on success, 0 on failure
sub input_file_with_images {
my ($self, $infile) = @_;
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $verbos = $self->verbosity();
if( ! defined $infile ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, an input filename of input image filenames is expected.\n"; return 0 }
my $fh;
if( ! open($fh, '<:encoding(UTF-8)', $infile) ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, could not open input file '$infile' for reading, $!\n"; return 0 }
while( <$fh> ){
chomp;
s/#.*$//;
s/^\s*$//;
$self->input_images($_) unless /^\s*$/;
} close $fh;
return 1
}
sub clear_input_images { $#{ $_[0]->{'input-images'} } = -1 }
# Add using a single pattern/searchdir
# add image files via a pattern and an input dir, e.g. '*.png', '/x/y/z/'
# make sure that the order you expect is what you get during the pattern materialisation
# the search dir is optional, default is Cwd::cwd
sub input_pattern {
my ($self, $params) = @_;
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $verbos = $self->verbosity();
my ($_pattern, $indir) = @$params;
my $indir_need_encode_utf8 = 0;
if( ! defined $indir ){
$indir = _my_cwd();
if( $verbos > 0 ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : warning, no search dir was specified and using current dir '$indir'.\n" }
} else { $indir_need_encode_utf8 = 1 }
my $pattern;
# allows for /pattern/modifiers
if( $_pattern =~ m!^regex\(/(.*?)/(.*?)\)$! ){
lib/Automate/Animate/FFmpeg.pm view on Meta::CPAN
->in(Encode::encode_utf8($indir))
]) ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, call to input_images() has failed.\n"; return 0 }
return 1 # success
}
# This adds many patterns:
# the input is an ARRAY of 1-or-2-item arrays
# each subarray must consist of a pattern and optionally a search dir (else current dir will be used)
sub input_patterns {
my ($self, $specs) = @_;
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $verbos = $self->verbosity();
for my $as (@$specs){
if( (scalar(@$as)==0)
|| (scalar(@$as)>2)
){ print STDERR perl2dump($as)."${whoami} (via $parent), line ".__LINE__." : error, the spec must contain at least a pattern and optionally a search-dir as an array, see above.\n"; return 0; }
if( ! $self->input_pattern($as) ){ print STDERR "${whoami} (via $parent), line ".__LINE__." : error, call to input_pattern() has failed for this spec: @$as\n"; return 0 }
}
return 1 # success
}
# if no parameter is specified then it returns the current list of input images as an arrayref
# Otherwise:
# specify one or more input filenames (of images) via a single scalar, an arrayref or
# a hashref whose values are image filenames, to convert them into video
# in this case returns undef on failure or the current, updated list of input images on success
sub input_images {
my ($self, $m) = @_;
if( ! defined $m ){ return $self->{'input-images'} }
my $parent = ( caller(1) )[3] || "N/A";
my $whoami = ( caller(0) )[3];
my $verbos = $self->verbosity();
if( $verbos > 0 ){
if( $verbos > 1 ){ print STDOUT perl2dump($m)."${whoami} (via $parent), line ".__LINE__." : called with input images as shown above ...\n" }
else { print STDOUT "${whoami} (via $parent), line ".__LINE__." : called ...\n" }
}
# NOTE: Cwd::abs_path() messes up on unicode filenames and requires Encode::decode_utf8()
# but there is also Cwd::utf8 to consider sometime...
my $rf = ref $m;
if( $rf eq 'ARRAY' ){
for my $af (@$m){
( run in 0.294 second using v1.01-cache-2.11-cpan-a9ef4e587e4 )