#! /usr/bin/perl
#
# transcode-stabilize.pl -- a script to demonstrate a deshaker for linux.
#
# (C) 2011, jw@suse.de 
# Distribute under GPL-2.0 or GPL-3.0
#
# http://forum.pardususer.de/index.php?topic=1494.0
# http://linuxreviews.org/man/transcode/
# http://www.transcoding.org/transcode?Transcode
# http://www.transcoding.org/transcode?Filter_Plugins/Filter_Stabilize
# http://www.transcoding.org/transcode?Filter_Plugins/Filter_Transform
#
# 2011-04-25, 0.5 -- jw, added ffprobe call to find length and bitrate of input.

use Getopt::Long;
use Pod::Usage;

my $version = '0.5';
my $verbose = 1;
my $noop = 0;
my $nozoom = 0;
my $shakiness = 4;	# 4 is default from [filter_stabilize.so] v0.76
my $accuracy  = 15;	# 4 is default from [filter_stabilize.so] v0.76
my $smoothing = 30;	# 10 is default from [filter_stabilize.so] v0.76
my $help;
my $outopt_def = '-y xvid -w 8000,25,100';
my $outopt;

my $ffprobe = '/usr/bin/ffprobe';

GetOptions(
	"verbose+"     => \$verbose,
	"quiet"        => sub { $verbose = 0; },
	"shakiness=s"  => \$shakiness,
	"accuracy=s"   => \$accuracy,
	"smoothing=s"  => \$smoothing,
	"nozoom"       => \$nozoom,
	"outopt=s"     => \$outopt,
	"transform=s"  => \$transform_input,
        "noop|n"       => \$noop,
	"help|?"       => \$help,
) or $help=1;

my @err;
my $input_mpg  = shift or $help or push @err, "no input file specified";
my $output_mpg = shift;
push @err, "accuracy must be equal to or greater than shakiness=$shakiness, not $accuracy" if $shakiness > $accuracy;
push @err, "datafile name $transform_input must not contain ':', please rename" if defined $transform_input and $transform_input =~ m{:};

if (defined($input_mpg) and not defined $output_mpg)
  {
    my $base = $input_mpg;
    my $suf = $1 if $base =~ s{(\.\w+)$}{};

    $output_mpg = $base . '-stab';
    $output_mpg .= $suf if defined $suf;
  }

push @err, "input and output are identical" if defined($input_mpg) and defined($output_mpg) and $input_mpg eq $output_mpg;

if (-e $ffprobe and defined $input_mpg)
  {
    my $dur_sec = 0;
    # Input #0, mpeg, from '/home/testy/kdenlive/haslach_bike_4k.mpg':
    #   Duration: 00:00:50.12, start: 1.000000, bitrate: 4044 kb/s
    #       Stream #0.0[0x1e0]: Video: mpeg2video (Main), yuv420p, 1280x720 [PAR 1:1 DAR 16:9], 104857 kb/s, 25 fps, 25 tbr, 90k tbn, 50 tbc

    my $res = `$ffprobe '$input_mpg' 2>&1`;
    if ($res =~ m{^\s*Duration: (\d\d):(\d\d):(\d\d(\.\d*)?).* bitrate: (\d+)(.\d+)? kb/s}m)
      {
        my ($hh, $mm, $ss, $kbps) = ($1,$2,$3, $5);
	$dur_sec = 3600*$hh + 60 * $mm + $ss;
	print "Duration: $dur_sec sec, kbps: $kbps\n" if $verbose;
	$outopt_def =~ s{-w \d+}{-w $kbps};
      }
    while ($res =~ m{^\s*Stream.*Video:.* (\d+(.\d+)?) kb/s, (\d+(\.\d+)?) fps}mg)
      {
        my ($kbps, $fps) = ($1, $3);
	printf "Frames: %d\n", $dur_sec * $fps if $verbose;
      }
    push @err, "ffprobe could not read duration of '$input_mpg'" unless $dur_sec;
  }

$outopt = $outopt_def unless defined $outopt;

my $err;
$err = "ERROR: " . join(";\n       ", @err) . '.' if @err;

$help++ if $err;

pod2usage(-verbose => 1, -msg => qq{
transform_input.pl V$version Usage: 

$0 [options] INPUTVIDEO.MPG [OUTPUTVIDEO.MPG]

Default output name is derived from input, with '-stab' added.

 --shakiness NN   
   	how shaky is the video and how quick is the camera?
        1: little (fast) 10: very strong/quick (slow) (def: $shakiness)

 --accuracy NN
  	accuracy of detection process (>=shakiness)
        1: low (fast) 15: high (slow) (def: $accuracy)

 --smoothing NN
 	number of frames*2 + 1 used for lowpass filtering 
        used for stabilizing (def: $smoothing)

 --nozoom 
 	Disable transform's "optzoom".
 	'optzoom'   0: nothing, 1: determine optimal zoom (def)
        i.e. no (or only little) border should be visible.
        Note that the value given at 'zoom' is added to the 
        here calculated one

 --transform STABILIZE_DATA_FILE.trf
	Skip running the stabilize step, take tha named data file, and only run transform step.
	Options --shakiness, --accuracy have no effect when you use --transform.

 --outopt "-y ffmpeg,null -F mpeg2video -w BITRATE,KEYFRAMES,CRISPNESS"
        Transcode output options. See 'man transcode'. Default: "$outopt"

 -n   No operation. Print the transcode commands only.

 -v   Be more verbose. Default: $verbose.
 -q   Be quiet, not verbose.
 -h -? --help
 	Show this online help.

$err
}) if $help;


my $cmd;
my $trf_file = "${input_mpg}_shakiness=${shakiness}_accuracy=${accuracy}.trf";
$trf_file =~ s{:}{_}g;
unless ($transform_input)
  {
    $transform_input = $trf_file;
    $cmd = "transcode -J 'stabilize=shakiness=$shakiness:show=$verbose:result=$transform_input";
    $cmd .= ",preview" if $verbose;
    $cmd .= "' -i '$input_mpg' -y null,null -o dummy";
    print "+ $cmd\n";
    system($cmd) unless $noop;
  }

$cmd = "transcode -J 'transform=smoothing=$smoothing:interpol=2:input=$transform_input";
$cmd .= ":optzoom=0" if $nozoom;
$cmd .= "' -i '$input_mpg' $outopt -o '$output_mpg'";
print "+ $cmd\n";
system($cmd) unless $noop;

