#!/usr/bin/perl use strict; use warnings; use Getopt::Std; use Date::Parse; use POSIX qw ( ceil ); use Fcntl ':flock'; use Time::HiRes qw ( time sleep ); use Fcntl; use Video::Frequencies; use Video::ivtv 0.13; my $Tv = "/usr/local/bin/tv"; my $Xine = "/usr/local/bin/xine"; my $MPlay = "/usr/local/bin/mplayer"; my $APlay = "/usr/bin/aplay"; my $Ptune = "/usr/local/bin/ivtv/ptune-ui.pl"; my $IrRC = "/usr/local/bin/irrc"; my $TunerNum = 0; my %FreqCh = %NTSC_BCAST_JP; my $Lock = "/var/lock/video/LCK..video"; my $LockBS = $Lock . "BS"; my $Dev = "/dev/video"; my %ChNo = ( 'NHK' => 1, 'MX' => 2, 'ETV' => 3, 'NTV' => 4, 'nippon' => 4, 'TVK' => 5, 'TBS' => 6, 'CX' => 8, 'fuji' => 8, 'tokyu' => 9, 'EX' => 10, 'asahi' => 10, 'UAIR' => 11, 'TX' => 12, 'tokyo' => 12, ); my $Infinite = "24h"; my $PeerAddr; my $UDPSA; my $DevNum; my $Freq; my $RecSec; my %Locked; my @MonthName = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jly', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); our ($opt_0, $opt_1, $opt_x, $opt_X, $opt_u, $opt_l, $opt_c, $opt_f, $opt_r, $opt_o, $opt_t, $opt_j, $opt_v, $opt_P, $opt_U); getopts('01xXulc:f:r:o:t:jvP:U:') || &help; my $Verbose = $opt_v; if ($opt_P) { use Socket; use Socket6; use Carp; my $port = $opt_P; my $proto = getprotobyname('tcp'); # socket(SERVER, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; # bind(SERVER, sockaddr_in($port, INADDR_ANY)) || die "bind: $!"; socket(SERVER, AF_INET6, SOCK_STREAM, $proto) || die "socket: $!"; bind(SERVER, sockaddr_in6($port, pack("NNNN", 0))) || die "bind: $!"; listen(SERVER, SOMAXCONN) || die "listen: $!"; exit 0 if fork; my $paddr; while ($paddr = accept(CLIENT, SERVER)) { if (!fork) { close(STDOUT); open(STDOUT, ">&CLIENT"); my $request; while () { $request .= $_; last if /^\r/; } print STDERR "--\n${request}--\n" if $Verbose; if ($request =~ /^(GET|POST)\s+\/\?(\S+)/) { for (split('&', $2)) { if (/(\w+)=(.*)/) { my ($var, $val) = ($1, $2); print STDERR "$var=$val\n" if $Verbose; if ($var eq "c") { $opt_c = $val; } elsif ($var eq "l") { $opt_l = $val; } } } } $| = 1; print "HTTP/1.1 200 OK\r\nContent-Type: video/mpeg\r\n\r\n"; undef $opt_P; if (! $opt_r) { $opt_r = $Infinite; } $PeerAddr = getpeername(CLIENT); last; } wait; close(CLIENT); } close(SERVER); exit 1 if $opt_P; } if ($opt_U) { if ($opt_U =~ /(.*)\:([\w\d]+)$/) { my $host = $1; my $port = $2; use Socket; use Socket6; use Carp; my @res = getaddrinfo($host, $port, AF_UNSPEC, SOCK_DGRAM); my $family = -1; my $socktype; my $proto; my $canonname; while (scalar(@res) >= 5) { ($family, $socktype, $proto, $UDPSA, $canonname, @res) = @res; if (socket(UDPSOCKET, $family, $socktype, $proto)) { print STDERR "send udp to ${host}:$port\n" if $Verbose; last; } undef $UDPSA; } } else { print STDERR "illegal dest: $opt_U\n"; exit 1; } } my $JustTime; if ($opt_j) { $JustTime = ceil((time+1) / 60) * 60; } if ($opt_0) { $DevNum = 0; } elsif ($opt_1) { $DevNum = 1; } else { if (($opt_r && ! $opt_t) || $opt_U) { my @order; if ($opt_r eq $Infinite) { @order = (1, 0); } elsif ($opt_r && ($opt_c || $opt_f)) { @order = (0, 1); } else { @order = (1, 0); } undef $DevNum; for (my $j=0; $j < 10; $j++) { for my $i (@order) { if (! &islocked($Lock . $i)) { $DevNum = $i; last; } } last if defined($DevNum); sleep 10; } defined($DevNum) || die "all ports are used\n"; } else { $DevNum = 1; } } END { for (keys %Locked) { if ($_ eq $LockBS) { system $IrRC, "vPower"; } if (-f $_) { unlink $_; } } } if ($opt_c) { if ($ChNo{$opt_c}) { $opt_c = $ChNo{$opt_c}; } if ($FreqCh{$opt_c}) { $Freq = $FreqCh{$opt_c}; } elsif ($opt_c =~ /^BS\d+$/) { if (! $opt_t) { my $bsok = 0; for (my $j=0; $j < 10; $j++) { if (! &islocked($LockBS)) { system $IrRC, "vPower"; $bsok = 1; last; } sleep 10; } $bsok || die "BS tuner is used\n"; $opt_l = 1; system $IrRC, "v$opt_c"; undef $opt_c; } } else { die "Unknown channel '$opt_c'\n"; } } if ($opt_f) { $Freq = $opt_f; } if ($opt_r) { if ($opt_r =~ /^((\d+)h)?((\d+)m)?((\d+)s?)?$/) { my $h = $2; my $m = $4; my $s = $6; $h = 0 unless defined $h; $m = 0 unless defined $m; $s = 0 unless defined $s; $RecSec = (($h * 60) + $m) * 60 + $s; } else { die "Can't parse '$opt_r'\n"; } if ($opt_o) { die "File exists: $opt_o\n" if -f $opt_o; sysopen(OUTPUT, $opt_o, O_CREAT | O_WRONLY | O_LARGEFILE) || die "Can't create '$opt_o' $!\n"; print STDERR "recording $RecSec sec to $opt_o\n" if $Verbose; } else { open(OUTPUT, ">&STDOUT"); } } if ($opt_X) { if (!fork) { my @mopt = ("-dr", "-quiet", "-fps", "30", "-aspect", "4:3", "-rawvideo", "on:ntsc:hm12", $Dev . ($DevNum + 32)); my @aopt = ("-q", "-f", "dat", $Dev . ($DevNum + 24)); if (!$Verbose) { close(STDOUT); open(STDOUT, "/dev/null"); } print STDERR "exec $APlay ", join(" ", @aopt), "\n" if $Verbose; my $apid; if (!($apid = fork)) { close(STDERR); open(STDERR, "/dev/null"); exec $APlay, @aopt; } print STDERR "exec $MPlay ", join(" ", @mopt), "\n" if $Verbose; my $mpid; if (!($mpid = fork)) { &dolock("$Lock$DevNum", 'x', 0) || exit 1; close(STDERR); open(STDERR, "/dev/null"); exec $MPlay, @mopt; } waitpid($mpid, 0); kill 15, $apid; unlink "$Lock$DevNum"; exit 0; } sleep 5; } if ($opt_x) { print STDERR "exec $Xine stdin://mpeg2 < $Dev$DevNum\n" if $Verbose; if (!fork) { &dolock("$Lock$DevNum", 'x', 0) || exit 1; close(STDIN); open(STDIN, "$Dev$DevNum"); exec $Xine, 'stdin://mpeg2'; } sleep 5; } if ($opt_u) { my @opts = ('-d', "$Dev$DevNum", '--freqtable', 'ntsc-bcast-jp'); print STDERR "exec $Ptune ", join(" ", @opts), "\n" if $Verbose; if (!fork) { exec $Ptune, @opts; } } if ($opt_t) { my $time = str2time($opt_t); my $now = time; $time += (60*60)*24 if $time < $now && $now < $time + (60*60)*24; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); die "sec must be 0 at `-t