#!/usr/bin/perl -w

# get_video	K. J. Turner	07/01/19

# This script gets the current video from an IP camera (Tenvis JPT3815W, Tenvis
# TH661, or similar) into "video_am.mp4" or "video_pm.mp4" depending on whether
# it is morning or afternoon. Video is captured in H.264 format (i.e. MP4)
# without sound. Videos are created writeable by the owner and readable by
# everyone. The video format is typically as follows:
#
#   JPT3815W		H.264/MPEG-4, 640 x 480, 7.5 frames/sec
#   TH661 (channel 2)	H.264/MPEG-4, 640 x 352, 20 frames/sec
#
# If getting a video fails, this is logged to standard output.

################################# Modules #################################

use Cwd;					# load current directory package
use Getopt::Std;				# load options package

############################### Main Program ##############################

&customise;					# customise script
&initialise;					# initialise script
&get_video;					# get camera video
&finalise;					# finalise script

############################### Subroutines ###############################

# customise script

sub customise {
  $CAMERA_JPT3815W = "JPT3815W";		# set camera type (JPT3815W)
  $CAMERA_TH661 = "TH661";			# set camera type (TH661)
  $CAMERA_TYPE = "XXX";				# set actual camera type
  $CREDS = "XXX:XXX";				# set username:password creds
  $VIDEO_BASE = "video";			# set video base name
  $VIDEO_CHANNEL = "12";			# set video channel (TH661 only)
  $VIDEO_DEINTERLACING = "";			# set no video deinterlacing
  # $VIDEO_DEINTERLACING = "deinterlaced,";	# set video deinterlacing
  $VIDEO_HOST = "XXX.XXX";			# set video host
  $VIDEO_LENGTH = 15;				# set recording length (seconds)
  $VIDEO_LIMIT = $VIDEO_LENGTH + 2;		# set recording limit (seconds)
  $VIDEO_MODE = oct("644");			# set video file mode
  $VIDEO_RATE = 512;				# set video bit rate (kbits/sec)
  $VIDEO_SIZE = "4096";				# set minimum video size (bytes)
  $VIDEO_SUFFIX = ".mp4";			# set video MP4 suffix
  $VIDEO_RTSP = "554";				# set video RTSP port (TH661)
  $VIDEO_HTTP = "80";				# set video HTTP port (JPT3815W)
  $VLC = "vlc";					# set VLC command
}

# report error

sub error {
  my($message) = @_;				# get error message

  &log("$program: $message");			# log error
  $exit_code = 1;				# set exit code of 1
  &finalise;					# exit script
}

# finalise script

sub finalise {
  exit($exit_code);				# exit with code
}

# get current camera video into "video_am.mp4" or "video_pm.mp4" depending
# on the hour

sub get_video {
  my($command, $file, $hour, $min, $name,	# locals
    $rest, $sec, $temp);

  ($sec, $min, $hour, $rest) = localtime(time);	# get time
  $period = $hour < 12 ? "am" : "pm";		# set AM or PM
  $file = "${VIDEO_BASE}_$period$VIDEO_SUFFIX";	# set video filename
  $command =					# set video capture command
    "$VLC -I dummy --quiet --no-sout-audio '$opt_u' " .
    "--run-time=$VIDEO_LIMIT --stop-time=$VIDEO_LENGTH " .
    "$stream_option vlc://quit > /dev/null 2>&1";
  &run($command);				# capture video
  if (!$exit_code) {				# VLC run completed?
    if (-r $video_temp) {			# video captured?
      $size = -s $video_temp;			# get video size
      if ($size >= $VIDEO_SIZE) {		# video is minimum size?
	$command = "mv $video_temp $file";	# set rename command
	&run($command);				# rename video file
	if (!$exit_code) {			# renamed completed?
	  &log("Success retrieving video");	# log video retrieval
	  chmod($VIDEO_MODE, $file);		# set video file mode
	}
      }
      else {					# video is below minimum size
	&error("Video size $size bytes is too small"); # report error
      }
    }
    else {					# video does not exist
      &error("Video '$file' was not created");	# report error
    }
  }
}

# initialise script and options

sub initialise {
  my($directory);				# locals

  # set common variables
  $program = $0;				# set program name
  $program =~ s/.*\///go;			# remove directories
  $directory = $0;				# set program name
  if (index($directory, "/") == -1 ||		# no directory or ...
      $directory =~ /^\.\//o) {			# in current directory?
    $directory = cwd();				# use current directory
  }
  else {					# in other directory
    $directory =~ s/\/[^\/]+$//o;		# remove program name
  }
  chdir($directory) ||				# change to directory or ...
    &error("Failure changing to directory '$directory'"); # log error
  $exit_code = 0;				# initialise exit code

  # set camera URL
  if ($CAMERA_TYPE eq $CAMERA_JPT3815W) {	# Tenvis JPT3815W?
    $opt_u =					# set camera URL
      "http://$CREDS\@$VIDEO_HOST:$VIDEO_HTTP/videostream.asf";
  }
  elsif ($CAMERA_TYPE eq $CAMERA_TH661) {	# Tenvis TH661?
    $opt_u =					# set camera URL
      "rtsp://$CREDS\@$VIDEO_HOST:$VIDEO_RTSP/$VIDEO_CHANNEL";
  }
  else {					# unknown camera type
    &error("unknown camera type '$CAMERA_TYPE'"); # report error
  }

  # get options
  $opt_h = 0;					# set no help
  $usage =					# options wrong, help, args?
    !getopts('hu:') || $::opt_h || $#ARGV >= 0;
  $video_temp = "temp$VIDEO_SUFFIX";		# set temporary video filename
  if ($usage) {					# usage required?
    &usage;					# print usage
  }

  # set video streaming option
  if ($CAMERA_TYPE eq $CAMERA_JPT3815W) {	# Tenvis JPT3815W?
    $stream_option =				# transcode stream to MP4
      "--sout='#transcode{vcodec=h264$VIDEO_DEINTERLACING,vb=$VIDEO_RATE}:" .
	"std{access=file,dst=$video_temp}'";
  }
  elsif ($CAMERA_TYPE eq $CAMERA_TH661) {	# Tenvis TH661?
    $stream_option =				# save stream as MP4
      "--sout='#standard{access=file,vcodec=h264$VIDEO_DEINTERLACING," .
      "vb=$VIDEO_RATE,dst=$video_temp}'";
  }
}

# log message

sub log {
  my($message) = @_;				# get message
  my($command, $email, $hour, $mday, $min,	# locals
     $mon, $rest, $sec, $year);

  ($sec, $min, $hour, $mday, $mon, $year, $rest) = # get time
    localtime(time);
  $mon++;					# get month 1..12
  $year += 1900;				# get year 1900..
  $message =					# set log message
   sprintf("%02d:%02d:%02d %02d/%02d/%04d %s\n",
      $hour, $min, $sec, $mday, $mon, $year, $message);
  system("echo \"$message\"");			# output log message
}

# run command, reporting any error

sub run {
  my($command) = @_;				# get command

  # &log("Running '$command'");			# log command
  if (system($command)) {			# command failed?
    &error("Failure running '$command'");	# log problem
  }
}

# print script usage

sub usage {
  print STDERR "usage: $program\n";
  print STDERR "  -h       " .
    "help on parameters\n";
  print STDERR "|\n";
  print STDERR "  -u [url] " .
    "camera URL (default '$opt_u')\n";
  exit(1);
}
