#!/usr/bin/perl
# AVI2MPEG written by Stanislaw Polak
# http://home.agh.edu.pl/~polak/
# 5 Oct 2004
#
# Copyright (c) 2004 Stanislaw Polak
# Unpublished work.
# Permission granted to use and modify this script so long as the
# copyright above is maintained, modifications are documented, and
# credit is given for any use of the script.
#
# For more information, see:
# http://home.agh.edu.pl/~polak/skrypty/avi2mpeg.html.var    
#
#Version 1.01 (12 Oct 2004) 
#             Errors handling has been fixed
#Version 1.0 (5 Oct 2004)
#             The first public version

################################
#Variables
################################
use strict;
use vars qw($opt_v $opt_h $opt_o $opt_n $opt_r @opt_t);
use Getopt::Long;

my($tmp,$outputFilename,$transitionLength,$defaultTransition,%transitions,$DEBUG,@tmpFiles);


$tmp="/tmp"; # a place where temporary files will be stored 
$outputFilename=setOutputFilename(); #if option '-o' is not specified, output file name is "day-month-year_hour:minute.mpg"
$transitionLength=25; #length of transition in frames (it must be multiple of 25)
#predefined transitions
%transitions = (
		"blend" => "transist.flt -o 0 -O 255 -d $transitionLength",
		"overlay1" => "overlay.flt -l $transitionLength",
		"overlay2" => "overlay.flt -l $transitionLength -i",
		"wipe1" => "wipe.flt -l  $transitionLength -d 1",
		"wipe2" => "wipe.flt -l  $transitionLength -d 2",
		"wipe3" => "wipe.flt -l  $transitionLength -d 3",
		"wipe4" => "wipe.flt -l  $transitionLength -d 4",
		);
$defaultTransition="blend";
$DEBUG=0; 

###################################
# Command line options processing
###################################
sub init()
{
    &GetOptions("t|transition:s@", "h|help","r|reposition=i","n|number=i","o|output:s","v|version") or usage();
    if($opt_v){
	#option '-v' or '--version' was used
	print << "EOF";
avi2mpeg converter, version 1.01
Written by Stanislaw Polak (http://home.agh.edu.pl/~polak/).


This is free software.  There is NO warranty; not even for MERCHANTABILITY 
or FITNESS FOR A PARTICULAR PURPOSE.
EOF
exit;
    }# if($opt_v)
    usage() if $opt_h;	#option '-h' or '--help' was used
    usage() if $#ARGV == -1; #script was run without arguments
    $outputFilename=$opt_o if $opt_o; 	#option '-o' or '--output' was used
}


###################################
# Set output file name as:
# day-month-year_hour:minute.mpg
###################################
sub setOutputFilename()
{
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    $year = 1900 + $year;
    return "$mday-$mon-$year\_$hour:$min.mpg";
}

###################################
# how many frames has the video file
###################################
sub movieLength()
{
    my(@result);
    open PROG, "lavinfo $_[0] |" or die("I can't execute 'lavinfo $_[0]'\n") ;
    while(<PROG>){
	#find  "video_frames=..."
	last if /^video_frames/ 	
	}
    close PROG or die("I can't execute 'lavinfo $_[0]'\n") ;
    @result=split /=/;
    return $result[1];
}
###################################
# execute UNIX command
###################################
sub execCmd()
{
    if(! $DEBUG){
	system($_[0]);
	if ($? == -1) {
	    die "Failed to execute: \"$_[0]\"\nMaybe you didn't install the \"MJPEGTOOLS\" library or \"wipe.flt\" and \"overlay.flt\" programs\n$!, stopped";
	}
	elsif ($? & 127) {
	    printf STDERR "child died with signal %d, %s coredump\n",
	    ($? & 127),  ($? & 128) ? 'with' : 'without';
	    exit $? ;
	}
    }
    else{
	print "$_[0]\n";
    }
}

###################################
# Message about this program and how to use it
###################################
#

sub usage()
{
    print STDERR << "EOF";	
      usage: $0 [OPTION] FILE ...[OPTION]... [FILE]
      
      -h
      --help        
                    This (help) message

      -v
      --version         
                    Output version information and exit

      -o name
      --output=name    
                    Use 'name' as the name for the file produced 
                    by this script
      -t TRANS
      --transition=TRANS
                   When files are joined the TRANS transition will be used.
		   TRANS may be: 'random', 'blend', 'overlay1', 'overlay2', 
		   'wipe1', 'wipe2', 'wipe3' or 'wipe4'. When TRANS is 'wipe1', 
		   'wipe2', 'wipe3' or 'wipe4' you can use the following 2 options:
                   
          -n NUM
          --number=NUM
                   number of wipe columns/rows (default: 1)

          -r NUM
	  --reposition=NUM
                   disable/enable reposition.
		   0: disable          1: only scene 1
		   2: only scene 2     3: both


    example: $0 -n=3 first.avi -t=wipe1 second.avi -o a.mpg

EOF
        exit;
}


###################################
# cut the selected part of a movie
# and return the name of a new movie
###################################
#

sub cut()
{
    my($beginOffset,$endOffset,$file,$length);
    #start cutting the 'file' movie from 'beginOffset' to 'length-endOffset'
    $beginOffset=$_[0];
    $endOffset=$_[1]; 
    $file=$_[2];
    $length=&movieLength("$file")-($beginOffset+$endOffset);
    &execCmd("lav2yuv -o $beginOffset -f $length $file|yuv2lav -f a -q 80 -o ${tmp}/$beginOffset-$endOffset-$file");
    push(@tmpFiles,"${tmp}/$beginOffset-$endOffset-$file");
    return "${tmp}/$beginOffset-$endOffset-$file";
    
}
###################################
# creates a movie with  selected transition
# and returns the name of the movie 
###################################
#

sub createTransition()
{
    my($transitionName,$file1,$file2,$transition,$i,$key,$value);
    
    $transitionName=$_[0]; #the name of transition specified with '-t' or '--transition' option
    $file1=$_[1]; #the name of the first movie
    $file2=$_[2]; #the name of the second movie
    if($transitionName=~/random/){
	#the 'random' transition
	my($howManyTransitions,$transitionNumber);
	$howManyTransitions= scalar keys %transitions; #number of predefined transition = number of elements in the 'transitions' hash
	$transitionNumber=int(rand $howManyTransitions)+1; #draw a transition number
	for($i=0;$i<$transitionNumber;$i++){
	    ($key,$value)=each %transitions; #get 'transitionNumber'-nth transition
	}
	if($key=~/^wipe/){
	    #the 'wipe' transition was choosed
	    my($r,$n);
	    $r=int(rand 3); #draw a value of the 'reposition' parameter
	    $n=int(rand 4)+1; #draw a value of the ' number of wipe columns/rows' parameter
	    $value = $r ? "$value -r $r" : $value; #append the above parameter
	    $value = $n ? "$value -n $n" : $value; #append the above parameter
	}#	if($key=~/^wipe/)
	$transition=$value;
    }# if($transitionName=~/random/
    else{
	$transition=$transitions{"$transitionName"};
    }
    if(!$transition){
	print STDERR "Unknown transition \"$transitionName\". Instead of them I'm using \"$defaultTransition\"\n";
	$transition=$transitions{$defaultTransition};
    }
    if($transitionName=~ /^wipe/){
	#if the 'wipe' transition was specified in '-t' or '--transition' option
	$transition = $opt_r ? "$transition -r $opt_r" : $transition; #append the value of  the 'reposition' parameter
	$transition = $opt_n ? "$transition -n $opt_n" : $transition; #append the value of  the ' number of wipe columns/rows' parameter
    }
    if($transition){
	&execCmd("ypipe \"lav2yuv -o -25 $file1\" \"lav2yuv -f 25 $file2\" | $transition | yuv2lav -f a -q 80 -o ${tmp}/$file1-transition-$file2");
	push(@tmpFiles,"${tmp}/$file1-transition-$file2");
    }
    return "${tmp}/$file1-transition-$file2";
}
###################################

srand(time()^($$+($$<<15)));
init();
my(@files);
@files=@ARGV;
@tmpFiles=();
print "\033[35mI'm separating an audio stream\033[0m\n";
&execCmd("lavtrans -o ${tmp}/audio.wav -f w @files");
&execCmd("cat ${tmp}/audio.wav | mp2enc -v 2 -V -o ${tmp}/audio.mp2");
unlink "${tmp}/audio.wav" if ! $DEBUG;
print "\033[35mI'm separating a video stream\033[0m\n";
if($#opt_t != -1){
    #option "--transition" or "-t" was used
    $#files=-1;
    #cut the first movie from beginning possition ('0') to the 'length Of The Movie - transitionLength' position
    push(@files,&cut(0,$transitionLength,$ARGV[0]));
    while($#opt_t > -1){
	#table of '-t' or '--transiotion' arguments is not empty
	if(! $#ARGV ) {last;} #list of arguments is empty, leave this loop
	#create the 'opt_t[0]' transition for the 'ARGV[0]' and 'ARGV[1]' movie 
	push(@files,&createTransition($opt_t[0],$ARGV[0],$ARGV[1]));
	if($#ARGV>=2 && $#opt_t){
	    #cut the second movie from 'transitionLength' to 'length Of The Movie - transitionLength' position
	    push(@files,&cut($transitionLength,$transitionLength,$ARGV[1]));
	}
	shift @opt_t;
	shift @ARGV;
    }#while($#opt_t > -1
    #cut the first movie from 'transitionLength' position to the end of this movie
    push(@files,&cut($transitionLength,0,$ARGV[0]));
    while($ARGV[1]){
	#if the list of '-t' or '--transition' is empty
	#join the other movies without transition
	push(@files,$ARGV[1]);
	shift @ARGV;
    }
} 
&execCmd("lav2yuv @files | mpeg2enc  -o ${tmp}/video.mpg");
print "\033[35mI'm putting together both streams\033[0m\n";
&execCmd("mplex -o $outputFilename ${tmp}/video.mpg ${tmp}/audio.mp2");

END{
    if(!$DEBUG){
	unlink  @tmpFiles if @tmpFiles;
	unlink "${tmp}/video.mpg" if -e "${tmp}/video.mpg";
	unlink "${tmp}/audio.mp2" if -e "${tmp}/audio.mp2";
	unlink "${tmp}/audio.wav" if -e "${tmp}/audio.wav";
    }
    else{
	print "@files\n";
    }
}
