#!/usr/bin/perl -w
#
#  Very simple test of the DVB PES multiplexer:
#  - reading sliced data from an analog capture device
#  - multiplexer output is written to STDOUT
#  - output can be decoded with examples/decode.pl --pes --all
#
#  Copyright (C) 2007 Tom Zoerner
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

# $Id: dvb-mux.pl,v 1.1 2007/12/02 18:42:17 tom Exp tom $

use strict;
use blib;
use Video::ZVBI qw(/^VBI_/);

# callback function invoked by Video::ZVBI::dvb_mux::feed()
sub feed_cb {
   my ($pkg, $user_data) = @_;

   syswrite STDOUT, $pkg;
   print STDERR "wrote ".length($pkg)."\n";
   # return 1, else multiplexing is aborted
   1;
}

sub main_func {
   my $opt_device = "/dev/vbi0";
   my $opt_buf_count = 5;
   my $opt_services = VBI_SLICED_TELETEXT_B_625;
   #my $opt_services = VBI_SLICED_TELETEXT_A;
   my $opt_strict = 0;
   my $opt_verbose = 0;
   my $opt_use_feed = 0;
   my $err;
   my $pxc;
   my $cap;
   my $mux;

   $pxc = Video::ZVBI::proxy::create($opt_device, $0, 0, $err, $opt_verbose);
   if (defined $pxc) {
      $cap = Video::ZVBI::capture::proxy_new($pxc, 5, 0, $opt_services, $opt_strict, $err);
      undef $pxc unless defined $cap;
   }
   if (!defined $cap) {
      $cap = Video::ZVBI::capture::v4l2_new($opt_device, $opt_buf_count, $opt_services, $opt_strict, $err, $opt_verbose);
   }
   if (!defined $cap) {
      $cap = Video::ZVBI::capture::v4l_new($opt_device, 0, $opt_services, $opt_strict, $err, $opt_verbose);
   }
   if (!defined $cap) {
      $cap = Video::ZVBI::capture::bktr_new($opt_device, 0, $opt_services, $opt_strict, $err, $opt_verbose);
   }
   die "Failed to open video device: $err\n" unless $cap;

   Video::ZVBI::set_log_on_stderr(0xFFFF);

   # create DVB multiplexer
   if ($opt_use_feed) {
      $mux = Video::ZVBI::dvb_mux::pes_new(\&feed_cb);
   } else {
      $mux = Video::ZVBI::dvb_mux::pes_new();
   }
   die "failed to create dvb_mux: $!\n" unless defined $mux;

   while (1) {
      my $sliced;
      my $timestamp;
      my $n_lines;
      my $res;

      # read a sliced VBI frame
      $res = $cap->pull_sliced($sliced, $n_lines, $timestamp, 1000);
      die "Capture error: $!\n" if $res < 0;

      if ($opt_use_feed == 0) {
         my $sliced_left = $n_lines;

         # pass sliced data to multiplexer
         my $buf_size = 2048;
         my $buf_left = $buf_size;
         my $buf;
         while ($sliced_left > 0) {
            print STDERR "$timestamp $buf_left <- $n_lines+$sliced_left\n";
            if (!$mux->cor($buf, $buf_left, $sliced, $sliced_left, $opt_services, $timestamp*90000.0)) {

               # encoding error: dump the offending line
               print STDERR "ERROR in line ".($n_lines-$sliced_left)."\n";
               my($data,$id,$line) = Video::ZVBI::get_sliced_line($sliced, $n_lines-$sliced_left);
               Video::ZVBI::unpar_str($data);
               $data =~ s#[\x00-\x1F\x7F]#.#g;
               print STDERR "MUX ERROR in line idx:".($n_lines-$sliced_left)." ID:$id phys:$line >".substr($data,0,42)."<\n";

               $sliced_left -= 1 if $sliced_left > 0;
               last if $sliced_left == 0;
            }
            #die if $buf_left == 0;  # buffer too small
         }
         syswrite STDOUT, $buf, $buf_size-$buf_left if defined $buf;
         print STDERR "wrote ".($buf_size-$buf_left)."\n";
      } else {

         if (!$mux->feed($sliced, $n_lines, $opt_services, $timestamp*90000.0)) {
            print STDERR "ERROR in feed\n";
         }
      }
   }

   exit(-1);
}

main_func();

