#!/usr/bin/perl -w
# bitrate.pl
# graphs the video and audio bitrate of an AVI
# by Loren Merritt
# last updated: 2004-12-19

use Getopt::Std;
getopts("o:b:l:");
$blur = defined($opt_b) ? $opt_b : ".2%";
$psout = $opt_o; undef $opt_o;
$logout = $opt_l; undef $opt_l;
$file = shift and $file =~ /\.avi/
    or die <<"EOT";
usage: $0 [opts] foo.avi
-b #      bitrate averaging window (default: .2% of total duration)
-o file   send graph to a postscript file
-l file   just create bitrate log
EOT

-f $file or die "$file doesn't exist\n";
open OLDERR, ">&STDERR";
close STDERR;
open MP, "-|", qw(mplayer -v -v -quiet -frames 0), $file
    or print OLDERR "can't exec mplayer\n" and die;
$fps = 24000/1001;
$frames=0;
$aframe=-1;

while(<MP>){
    if(/:  00dc .*len: *(\d+)/){
        $video[$frames] = $1;
        $frames++;
    }elsif(/:  01wb .*len: *(\d+)/){
        my $skip = $frames-$aframe;
        if($skip > 1){
            for($aframe+1 .. $frames){
                $audio[$_] += $1 / $skip;
            }
        }else{
            $audio[$frames] += $1;
        }
        $audio_total += $1;
        $aframe = $frames;
    }elsif(/fps=(\d+\.\d+)/){
        $fps=$1;
    }
}
close MP;

if($blur =~ /^(\d*\.?\d+)%/){
    $blur = int($frames*$1/100) + 1;
} elsif($blur =~ /^(\d*\.?\d+)$/){
    $blur = int($1+.5);
}
for(0..$frames-1) {
    $video[$_] ||= 0;
    $video[$_] *= $fps * 8 / 1000;
    $audio[$_] ||= 0;
    $audio[$_] *= $fps * 8 / 1000;
}

sub blur(\@) {
    my $a = shift;
    if(!$blur){return @$a;}
    my $sum = 0;
    my $n = 0;
    my $window = 2*$blur+1;
    my @out;
    for(0 .. $frames-1+$blur){
        if($_<$frames){
            $sum += $$a[$_];
            $n++;
        }
        if($_>$window){
            $sum -= $$a[$_-$window];
            $n--;
        }
        if($_>=$blur){
            push @out, $sum / $n;
        }
    }
    return @out;
}

@video = blur(@video);
@audio = blur(@audio) if $audio_total;

open STDERR, ">&OLDERR";

if($logout) {
    open LOG, ">", $logout or die "can't write to $logout\n";
    for(0 .. $frames-1){
        print LOG "$video[$_]\n";
    }
    exit;
}

open LOG, ">", "frames.log" or die "can't write to frames.log\n";
for(0 .. $frames-1){
    $audio[$_] ||= 0;
    print LOG "$video[$_]\t$audio[$_]\n";
}
close LOG;

$cmd = qq{
set data style lines
set title "$file"
set xlabel "time (seconds)
set ylabel "bitrate (kbit/s)
plot [0:$frames/$fps] 'frames.log' using (\$0/$fps):1 title "video"};
if($audio_total){
    $cmd .= qq{, 'frames.log' using (\$0/$fps):2 title "audio"};
}

open PLOT, "|-", "gnuplot" or die "can't exec gnuplot\n";
if(defined($psout)){
    print PLOT qq(set term postscript\nset output "$psout"\n$cmd\n);
    close PLOT;
}else{
    open PLOT, "|-", "gnuplot" or die "can't exec gnuplot\n";
    select PLOT; $|=1;
    print PLOT "$cmd\n";
    wait;
    close PLOT;
}
