#!/usr/bin/perl -w

# Copyright CREX:
# This script is released under GPL licence
# TransPerl v0.4

use Getopt::Long;

# Hauteur et largeur en pixels du dvd
our $max_largeur;
our $max_hauteur;

our $vob, ;
our $nice="nice -20";
GetOptions("projet=s"     => \$projet, # the project's name
	   "help"         => \$help, # print some usefull help
	   "desentrelace" => \$desentrelace, # activates deinterlacing
	   "noise"        => \$noise, # activates a temporal denoiser filter
	   #	   "resume"       => \$resume,
	   "codec=s"      => \$codec, # sets the codec: lavc or xvid
	   "soft=s"       => \$soft); # sets the encoder software: mencoder or transcode

if ($help) {
  print "Vous avez demandé de l'aide?
Pour utiliser ce script lancez-le avec en paramètre le nom du projet. ex:
./transperl.pl --projet TWO_WEEKS_NOTICE
Paramètres:
  --soft nom_du_soft :
    Le programme d'encodage que vous souhaitez utiliser. Actuellement:
    mencoder OU transcode
  --codec nom_du_codec :
    Choix du codec MPEG4. Actuellement:
    xvid ou lavc

Options:
  --desentrelace :
    Désentrelace la vidéo lors de l'encodage
  --noise :
    Applique un filtre de débruitage sensé améliorer la compressibilité
\n";
  exit (1);
}

if (!$projet) {
  print "Veuillez fournir le nom d'un projet SVP!\n";
  exit(1);
}

######## désentrelacement
if ($desentrelace) {
  if ($soft eq "mencoder") {
    $deint = ",pp=fd";
  } elsif ($soft eq "transcode") {
    $deint = "-J smartdeinter=threshold=10:Blend=1:diffmode=2:highq=1";
  } else {
    print "Veuillez fournir le nom du soft que vous souhaitez utiliser SVP\n";
  }
} else {
  $deint ='';
}

######## de-noiser
if ($noise) {
  $noise=",denoise3d";
} else {
  $noise='';
}

######### Lecture du fichier de config de tuxrip #############################
my ($root, $device, $delay, $lavcopts, $xvidencopts, $max_gain, $video_drv, $audio_drv, $burner, $burn_speed, $viewer, $credits_quants, $cdrom_mnt_point, $crop_threshold, $container, $resize, $lang);

open(CONFIG, "$ENV{HOME}/.tuxriprc")
  or die "ERREUR: fichier de config de tuxrip inexistant";
while (<CONFIG>) {
  chomp;			# grignotte les retours à la ligne
  if ($_ =~ m/^1\. */) {	# on identifie la ligne commençant par "1. " du fichier de config
    $root = $';			# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^2\. */) {	# on identifie la ligne commençant par "2. " du fichier de config
    $device = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^3\. */) {	# on identifie la ligne commençant par "3. " du fichier de config
    $delay = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^4\. */) {
    $lavcopts = $';
  }
  if ($_ =~ m/^5\. */) {
    $xvidencopts = $';
  }
  if ($_ =~ m/^6\. */) {	# on identifie la ligne commençant par "6. " du fichier de config
    $max_gain = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^7\. */) {	# on identifie la ligne commençant par "7. " du fichier de config
    $video_drv = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^8\. */) {	# on identifie la ligne commençant par "8. " du fichier de config
    $audio_drv = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^9\. */) {	# on identifie la ligne commençant par "9. " du fichier de config
    $burner = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^10\. */) {	# on identifie la ligne commençant par "10. " du fichier de config
    $burn_speed = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^11\. */) {	# on identifie la ligne commençant par "11. " du fichier de config
    $viewer = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^12\. */) {	# on identifie la ligne commençant par "12. " du fichier de config
    $credit_quants = $';        # $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^13\. */) {	# on identifie la ligne commençant par "13. " du fichier de config
    $cdrom_mnt_point = $';	# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^14\. */) {	# on identifie la ligne commençant par "14. " du fichier de config
    $crop_threshold = $';	# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^15\. */) {	# on identifie la ligne commençant par "15. " du fichier de config
    $container = $';		# $' matche la sous-chaine suivant la regex
  }
  if ($_ =~ m/^16\. */) {	# on identifie la ligne commençant par "16. " du fichier de config
    $resize = $';		# $' matche la sous-chaine suivant la regex
  }
}
$vob = "$root/$projet/vob/$projet.vob";
print "Your conf file is : $root \n";

######### Lecture du fichier de log du dvd #############################
open(DVD, "$root/$projet/tmp/infos.dvd")
  or die "ERREUR: fichier log du dvd inexistant";
while (<DVD>) {
  chomp;			# grignotte les retours à la ligne
  if ($_ =~ m/^VIDEO:  MPEG2  */) {
    my ($dimensions, $rubbish) = split /  /,$',2;
    print "les dimensions du dvd sont: $dimensions\n";
    ($max_largeur,$max_hauteur,$rubbish) = split /x/,$dimensions,3;
  }
}



######### Lecture du fichier de log du projet ################################
open (LOG_PROJET, "$root/$projet/tmp/log")
  or die "Pas de fichier de log pour votre projet: assurez-vous d'avoir créé un projet avec tuxrip et d'être arrivé au moins à l'étape n°5";

my ($crop_transcode, $crop_mencoder, $scale_transcode, $scale_mencoder, $bitrate);

while (<LOG_PROJET>) {
  chomp;

  ####### Traitement des paramètres Cropping #############################
  if ($_ =~ m/^cropping --> */ ) {
    my ($crop, $h,$l) = split / /,$',3;
    $crop_mencoder = $crop;
    my ($largeur,$hauteur,$crop_gauche,$crop_haut) = split /:/, $crop,4;
    ##### "Normalisation" du crop pour pouvoir utiliser le "fast resize"
    $largeur = $largeur - ($largeur%8);
    $hauteur = $hauteur - ($hauteur%8);
    my $crop_bas=$max_hauteur-$hauteur-$crop_haut;
    my $crop_droite=$max_largeur-$largeur-$crop_gauche;
    
    $crop_transcode = "$crop_haut,$crop_gauche,$crop_bas,$crop_droite";
    
    print "Le crop transcode est: $crop_transcode, celui de mencoder: $crop_mencoder\n";
  }
  
  ####### Traitement des paramètres Scale, Bitrate #######################
  if ($_ =~ m/^taille visée, résolution, bitrate --> */ ) {
    my ($taille_visee, $resolution, $bitrate_logged) = split / /,$',3;
    $bitrate = $bitrate_logged;
    $scale_mencoder = $resolution;
    my ($X, $Y) =  split /:/, $resolution,2;
    $scale_transcode = "$X"."x$Y";
    print "Le scale transcode est: $scale_transcode, celui de mencoder: $scale_mencoder\n";
  }
}

######### Encodage en fonction du codec et du logiciel désiré ############
my $commande_systeme;
if ($soft eq "mencoder") {
  my $commande_mencoder_base = "$nice mencoder $vob -mc 0 -nosound -vf crop=$crop_mencoder$deint$noise,scale=$scale_mencoder -ovc $codec ";
  if ($codec eq "lavc") {
    $commande_mencoder = $commande_mencoder_base."-lavcopts $lavcopts:vbitrate=$bitrate:vpass=";
  } elsif ($codec eq "xvid") {
    $commande_mencoder = $commande_mencoder_base."-xvidencopts $xvidencopts:bitrate=$bitrate:pass=";
  }
  $commande_systeme = "${commande_mencoder}1 -o /dev/null &&${commande_mencoder}2 -o $root/$projet/video/${projet}sans-son.avi";
} else {
  my $commande_trancode = "transcode --nice 20 -i $vob -x vob,null -y xvid4,null -V $deint -j $crop_transcode -Z $scale_transcode,fast -w $bitrate";
  $commande_systeme = "$commande_trancode -o /dev/null -R 1&&$commande_trancode -o $root/$projet/video/${projet}sans-son.avi -R 2";
}

print "Je vais lancer l'encodage avec cette commande:\n$commande_systeme\n";
chdir "$root/$projet/tmp";
get_title();
#my %crops = compute_cropping($vob);
#`mplayer  $vob -vf rectangle=$crops{width}:$crops{height}:$crops{left}:$crops{top}`;
#audio_compression($type="mp3", $audiotrack, $vob);
#system "$commande_systeme";
#compute_vid_siz($audio_path = "$root/$projet/audio");
#get_chapters($chap_file = "$root/$projet/tmp/$projet-chapitrage");

sub get_title {
  my ($device) = @_;
  $_ = `dd if=$device ibs=1 skip=32808 count=32 2>/dev/null`; # get title
  s/ //g;			## zaps spaces
  return $_;
}

sub get_chapters {
  my ($chap_file, $title, $device) = @_;
  system "dvdxchap -t $title $device 2>/dev/null > ";
}

# have XviD compute the video size itself: You tell: 629359kB (real kB: 1024)
# It outputs: 640713896 bytes, which is 625697kb (99.4% of target size)
# on mux, it produces a 701M mkv file = 734056302 bytes (target was 702)
# ogm is 705M 739091172 bytes
# (audio was 45996342 and 45639587 bytes)

sub audio_compression {
  my ($type, $audiotrack, $input) = @_;
  chdir "$root/$projet/tmp";
  if ($type eq "ac3") {
    system "tccat -i $input -d 0 | tcdemux -a $audiotrack -x ac3 -S 0 -M 1 -d 0 | tcextract -t vob -x ac3 -a $piste -d 0 | tcextract -t raw -x ac3 -d 0 > $root/$projet/audio/son.ac3";
  } else {
    my $pipe="/tmp/pcmpipe.raw";
    require POSIX;
    POSIX::mkfifo($pipe, 0666);
    
    # my mplayer_audiotrack = $audiotrack + 127;
    #system "$nice mplayer -nortc -ao pcm -vc dummy -vo null -aofile $pipe $input -quiet&";
    system "transcode -q 0 -i $input -a $audiotrack -u 50 --a52_drc_off -x null,vob -y null,wav -m $pipe -o /dev/null -J normalize";
    if ($type eq "mp3") {
      system "$nice lame -q 0 --abr 96 -r -s 48 --bitwidth 16 -o $root/$projet/audio/son.mp3 $pipe";
    } else {
      #system "$nice mplayer -nortc -ao pcm -vc dummy -vo null -aofile $pipe $root/$projet/vob/$projet.vob -quiet&";
      system "$nice oggenc -r -C2 -R48000 -B16 -q1 -o $root/$projet/audio/son.ogg $pipe";
    }
    unlink $pipe;
  }
}

sub compute_bitrate () {
  my ($target_size, $audio_size, $lenght) = @_;
    return ($target_size - $audio_size) * 1024 * 1024 / $lenght * 8 / 1000;
}

sub compute_res () {
  my ($width_croped, $height_croped, $width_disp, $height_disp, $width_pix, $height_pix, $bitrate, $CQ) = @_;
  my $ARc = ($width_croped * (($width_disp/$height_disp) / ($width_pix/$height_pix))) / $height_croped;
  
 
  my %res{Y} = INT( SQRT(1000 * $bitrate / 25 / ARc / CQ) / 16 ) * 16;
    %res{X}  INT( %res{Y} * $ARc / 16) * 16;
}

sub cc_check () {
  my $taille = (stat($vob))[7];
  if ($codec eq "lavc") {
    $cc_command = $commande_mencoder_base." -lavcopts vcodec=mpeg4:vmax_b_frames=0:vhq:v4mv:vqscale=2";
  } elsif ($codec eq "xvid") {
    $cc_command = $commande_mencoder_base." -xvidencopts vhq=3:fixed_quant=2";
  }
  
  my $pas=$taille_vob/105;
  for (my $i=0; i<100; $i++) {
    my $debut = ($i+2)*$pas;
    system "$cc_command -sb $debut -endpos $sec -o $RACINE/$projet/tmp/cctemp${i}.avi >/dev/null 2>&1";
  }
}

sub compute_vid_siz {
  my ($audio_path) = @_;
  use Cwd;
  my $vid_siz = 0;
  my $orig_path = getcwd();	# saves the current path, to get back there

  chdir $audio_path;
  while (<*>) {
    $vid_siz += (stat($_))[7];	#get the size of all files in $audio_path
  }

  chdir $orig_path;
  return $vid_siz;
}

sub compute_bitrate {
  my ($vid_siz, $playtime, $container) = @_;
  my $bitrate = ($vid_siz * 1024 * 1024 / $playtime * 8 / 1000);
  # Ok, this is strictly experimental: matroska is more space-efficient than
  # ogm, and XviD produces slitly undersized files. This should help
  if ($container eq "matroska") {
    $bitrate = $bitrate * 1.0128;
  }
  use integer;
  return ($bitrate/1);		# trick to have a bitrate that's strictly an integer
}

sub compute_cropping {
  my ($vob) = @_;
  my $position = (stat($vob))[7];
  $position = $position/5;
  use integer;
  $position = $position/1;
  print "test pos: $position\n";
  for ( `mplayer $vob -sb $position -frames 4 -vf cropdetect -vo null -nosound` ) {
    chomp;
    if ($_ =~ m/^.*-vf crop=.*$/ ) {
      my ($start, $width, $height, $left, $top, $finish) = /(.*)=([0-9]+):([0-9]+):([0-9]+):([0-9]+)(.*)/;
      return (
	      width  => $width,
	      height => $height,
	      left => $left,
	      top => $top);
    }
  }
}

sub do_merge {
  my ($root, $projet, $delay) = @_;
  my $audio_tracks = '';
  # read audio dir + parse log files
  $audio_tracks = "$audio_tracks -s $decal -c LANGUAGE=${pisteaudio[2]} $root/$projet/audio/son.ogg";
  system "ogmmerge -o $root/$projet/video/${projet}.ogm $root/$projet/video/${projet}sans-son.avi $audio_tracks 2>$RACINE/$projet/tmp/logmux";
}
