#
# Frame rate conversion script.  Takes a stream on STDIN and performs
# frame rate conversion, writing the new stream to STDOUT.  The
# conversion is performed by copying/dropping frames as necessary to
# meet the target rate requirements.
#
# Note, this script understands the XF frame tag.  This is a
# non-standard tag which specifies the duration for each frame.  Thus,
# it is possible to convert variable frame rate movies with this
# script.  How to generate such tags is up to you, but there is a
# patch available for mplayer to support this tag.
#

use YUV4MPEG ':all';
use Getopt::Long;

my $i_rate;
my $o_rate;
my $help;

my %rates = (0 => FPS_UNKNOWN,
             1 => FPS_NTSC_FILM,
             2 => FPS_FILM,
             3 => FPS_PAL,
             4 => FPS_NTSC,
             5 => FPS_30,
             6 => FPS_PAL_FIELD,
             7 => FPS_NTSC_FIELD,
             8 => FPS_60);

GetOptions("i=i" => \$i_rate,
           "o=i" => \$o_rate,
           "help|h|?" => \$help);

do_help() if ($help);

$i_rate = $rates{$i_rate};
$o_rate = $rates{$o_rate};

die "Output rate not specified" if (! defined $o_rate);

my $si = new YUV4MPEG::StreamInfo;
my $fi = new YUV4MPEG::FrameInfo;
my $frame;
my $frame_rate;
my $frame_cnt;

my $i_ratio, $o_ratio;
my $budget;

$si->read();
$frame = new YUV4MPEG::Frame($si);

$i_rate = $si->get_framerate() if (! defined $i_rate);

$si->set_framerate($o_rate);
$si->write();

$o_ratio = $o_rate->get_n() / $o_rate->get_d();

$frame_cnt = 0;

while ($frame->read($fi) == Y4M_OK) 
{
  $frame_cnt++;

  if ($fi->xtags()->count() > 0) 
    {
      my @tags = $fi->xtags()->get_all();
      my @rate = grep(/^XF\d+:\d+$/, @tags);
      
      if ($#rate >= 0) 
        {
          $rate[0] =~ /^XF(\d+):(\d+)$/;
          
          $i_rate = new YUV4MPEG::Ratio($1, $2);
        }
      
      $fi->xtags()->clearlist();
    }
  
  my $count = 0;

  $budget += 1;
  $i_ratio = $i_rate->get_n() / $i_rate->get_d();

  while ($budget >= 1) 
    {
      $frame->write($fi);
      
      $budget -= ($i_ratio / $o_ratio);
      $count++;
    }

  print STDERR "Frame $frame_cnt (x$count, $i_ratio)\n";
}

sub do_help
{
  print "Usage: $0 [-i input_rate] -o output_rate\n";
  print "  Where input_rate and output_rate are:\n";

  foreach (keys %rates) 
    {
      if ($_ == 0) 
        {
          print "    0 - invalid\n";
        } 
      else {
        printf ("    $_ - %.4f\n", $rates{$_}->get_n() / $rates{$_}->get_d());
      }
    }

  exit(0);
}
