#!/usr/bin/perl

# (c) G. Finch (salsaman)

# released under the GNU GPL 3 or later
# see file COPYING or www.gnu.org for details





#######################################################################
# LiVES x264 plugin v0.5

$queuefile="264stream.y4m";

#######################################################################

if (!defined($standalone)) {
    my $smogrify;
    if ($^O eq "MSWin32") {
	$smogrify="smogrify";
    }
    else {
	$smogrify=`which smogrify`;
	chomp($smogrify);
    }
    if ($smogrify ne "") {
	require $smogrify;
    }
}
else {
    $command=$ARGV[0];
}



#######################################################################


if ($command eq "version") {
    print "x264 encoder plugin v0.5\n";
    exit 0;
}


if ($command eq "init") {
    # perform any initialisation needed
    # On error, print error message and exit 1
    # otherwise exit 0

    if (&location("x264") eq "") {
	print "x264 was not found. Please install x264 and try again.";
	exit 1;
    }

    if (&location("mplayer") eq "") {
	if (&location("mplayer2") eq "") {
	print "mplayer or mplayer2 was not found. Please install it and try again.";
	exit 1;
    }

    # end init code
    print "initialised\n";
    exit 0;
}



if ($command eq "get_capabilities") {
    # return capabilities - this is a bitmap field
    # bit 0 - takes extra parameters (using RFX request)
    # bit 1 - unused
    # bit 2 - can encode png
    # bit 3 - not pure perl
    print "4\n";
    exit 0;
}



if ($command eq "get_formats") {
   # for each format: -
   # return format_name|display_name|audio_types|restrictions|extension|

   # audio types are: 0 - cannot encode audio, 1 - can encode using
    #  mp3, 2 - can encode using pcm, 3 - can encode using pcm and mp3
    
    print "mp4|h264/aac/mp4 (super high quality mp4)|32|none|mp4|\n";
    print "divx+|DivX Plus HD|32|fps=24;24000:1001;25;30000:1001;30,hblock=8,vblock=8,minw=320,minh=240,maxw=1920,maxh=1024|mkv|\n";
    print "divxh+|DivX Plus HD high framerate|32|fps=50;60000:1001;60,hblock=8,vblock=8,minw=320,minh=240,maxw=1280,maxh=720|mkv|\n";
    print "x264_br_1080p|x264 blu-ray 1080p NTSC (Experimental)|32|size=1920x1080,fps=24000:1001;24|mpg|\n"; # NTSC 1080p
    print "x264_br_1080pp|x264 blu-ray 1080p PAL (Experimental)|32|size=1920x1080,fps=25|mpg|\n"; # PAL 1080p
    print "x264_br_720p|x264 blu-ray 720p NTSC (Experimental)|32|size=1280x720,fps=60000:1001|mpg|\n"; # 720p
    print "x264_br_720pp|x264 blu-ray 720p PAL (Experimental)|32|size=1280x720,fps=50000:1001|mpg|\n"; # 720p
    print "x264_br_720p|x264 blu-ray 720p 30 fps NTSC (Experimental)|32|size=1280x720,fps=30|mpg|\n"; # 720p
    print "x264_br_720pp|x264 blu-ray 720p 24/25 fps PAL (Experimental)|32|size=1280x720,fps=24;25|mpg|\n"; # 720p

    exit 0;
}



if ($command eq "encode") {
    # encode 

    if (($otype eq "divx+" ||$otype eq "divxh+") && &location("mkvmerge") eq "") {
	print STDERR "You must install mkvmerge in order to create this file.\nTry installing the mkvtoolnix package.\n";
	&sig_complete;
	exit 1;
    }

    if (&location("MP4Box") eq "") {
	print STDERR "You must install MP4Box in order to create this file.\nTry installing the gpac package.\n";
	&sig_complete;
	exit 1;
    }

    if ($audiofile ne "" && &location("ffmpeg") eq "") {
	print STDERR "You must install ffmpeg with libfaac support in order to encode with audio.\n";
	&sig_complete;
	exit 1;
    }

    $err=">/dev/null 2>&1";
    if (defined($DEBUG_ENCODERS)) {
	$err="1>&2";
    }

    $ncpus=&get_num_procs;

    $threads=$ncpus;


    unlink $queuefile;

    $mf_ver=&rc_get("mplayer_mf_version");


    if ($mf_ver==1) {
	if ($img_ext eq ".png") {
	    $syscom="mplayer -frames $end -mf on -mf type=png -nosound -benchmark -fps $fps -ao null -vo yuv4mpeg:file=$queuefile </dev/null";
	}
	else {
	    $syscom="mplayer -frames $end -mf on -mf  h=$vsize:w=$hsize:type=jpg -nosound -benchmark -fps $fps -ao null -vo yuv4mpeg:file=$queuefile </dev/null";
	}
    }
    else {
	$mplayer_com="mplayer";
	if (&location("mplayer") eq "") {
	    $mplayer_com="mplayer2";
	}
	if ($img_ext eq ".png") {
	    $syscom="$mplayer_com -frames $end -mf fps=$fps:type=png mf://*.png -nosound -benchmark -fps $fps -ao null -vo yuv4mpeg:file=$queuefile </dev/null";
	}
	else {
	    $syscom="$mplayer_com -frames $end -mf fps=$fps:type=jpg mf://*".$img_ext." -nosound -benchmark -fps $fps -ao null -vo yuv4mpeg:file=$queuefile </dev/null";
	}

    }

    print STDERR "Running stream to queue with command:\n$syscom\n";

    system("$syscom $err");

    $ofile="temp.264";

    if ($otype eq "mp4") {
	$syscom="x264 --frames $end --crf 12 --threads auto --preset veryslow --tune animation $queuefile --fps $fps -o \"$ofile\"";
    }
    elsif ($otype eq "divx+" || $otype eq "divxh+") {
	$syscom="x264 --frames $end --no-mixed-refs --no-weightb --weightp 0 --ref 2 --threads auto --trellis 0 --vbv-maxrate=20000 --vbv-bufsize=25000 --level 40 --bframes 3 --keyint ".($fps*4.)." $queuefile --fps $fps -o \"$ofile\"";
    }
    else {
	if ($fps<=30 && ($otype eq "x264_br_720p" || $otype eq "x264_br_720pp")) {
	    # do we need this for 1024p ?
	    $fi=" --fake-interlaced";
	}
	else {
	    $fi="";
	}

	$syscom="x264 --frames $end $fi --crf 16 --threads auto --preset veryslow --tune film --weightp 0 --bframes 3 --nal-hrd vbr --vbv-maxrate 40000 --vbv-bufsize 30000 --level 4.1 --keyint 24 --b-pyramid strict --slices 4 --aud --colorprim \"bt709\" --transfer \"bt709\" --colormatrix \"bt709\" --sar 1:1 $queuefile --fps $fps -o \"$ofile\"";
    }

    print STDERR "Processing queue with:\n$syscom\n";

    system("$syscom $err");


    if ($audiofile ne "") {
	$syscom="nohup ffmpeg -i audiodump.wav -acodec aac -strict experimental -ab 192k -ar 44100 -threads $threads temp.aac";
	
	print STDERR "Encoding audio with:\n$syscom\n";

	system("$syscom $err");

	if ($otype ne "divx+" && $otype ne "divxh+") {
	    $syscom="MP4Box -fps $fps -tmp $curtmpdir -add $ofile -add temp.aac \"$nfile\"";
	}
	else {
	    $syscom="mkvmerge --default-duration 0:$fps"."fps --title \"$title\" $ofile temp.aac -o \"$nfile\"";
	}

	print STDERR "Muxing with:\n$syscom\n";
	
	system("$syscom $err");

    }
    else {
	if ($otype ne "divx+" && $otype ne "divxh+") {
	    $syscom="MP4Box -fps $fps -tmp $curtmpdir -add $ofile \"$nfile\"";
	}
	else {
	    $syscom="mkvmerge --default-duration 0:$fps"."fps --title \"$title\" $ofile -o \"$nfile\"";
	}

	print STDERR "Muxing with:\n$syscom\n";
	
	system("$syscom $err");
    }


    # required
    &sig_complete;
    exit 0;
}


if ($command eq "clear") {
    # this is called after "encode"
    # note that encoding could have been stopped at any time

    unlink $queuefile;

    unlink "output.264";

    unlink "temp.aac";

    unlink "nohup.out";

    &sig_complete;
    exit 0;
}


if ($command eq "finalise") {
    # do any finalising code

    # ...

    # end finalising code
    print "finalised\n";
    exit 0;
}


###### subroutines #######




sub get_format_request {
    # return the code for how we would like audio and video delivered
    # this is a bitmap field composed of:
    # bit 0 - unset=raw pcm audio; set=pcm audio with wav header
    # bit 1 - unset=all audio; set=clipped audio
    # bit 2 - unset=all frames; set=frames for selection only

    return 7; # clipped wav, clipped frames
}


sub get_num_procs {
    my $result=`cat /proc/cpuinfo|grep processor`;

    $result=(split (/\n/,$result))[-1];
    $result=(split (/: /,$result))[1];
    return ++$result;
}
