The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package SReview::Videopipe;

use Mojo::JSON qw(decode_json);
use Moose;

has 'inputs' => (
	traits => ['Array'],
	is => 'ro',
	isa => 'ArrayRef[SReview::Video]',
	default => sub { [] },
	clearer => 'clear_inputs',
	handles => {
		add_input => 'push',
	},
);

has 'output' => (
	is => 'rw',
	isa => 'SReview::Video',
	required => 1,
);

has 'map' => (
	traits => ['Array'],
	is => 'ro',
	isa => 'ArrayRef[SReview::Map]',
	default => sub {[]},
	clearer => 'clear_map',
	handles => {
		add_map => 'push',
	},
);

has 'vcopy' => (
	isa => 'Bool',
	is => 'rw',
	default => 1,
);

has 'acopy' => (
	isa => 'Bool',
	is => 'rw',
	default => 1,
);

has 'multipass' => (
	isa => 'Bool',
	is => 'rw',
	default => 0,
);

has 'progress' => (
	isa => 'CodeRef',
	is => 'ro',
	predicate => 'has_progress',
);

sub run_progress {
	my $self = shift;
	my $command = shift;
	my $pass = shift;
	my $multipass = shift;
	my ($in, $out, $err);
	my $running;
	my @lines;
	my $old_perc = 0;
	my %vals;

	my $length = $self->inputs->[0]->duration * 1000000;
	shift @$command;
	unshift @$command, ('ffmpeg', '-progress', '/dev/stdout');
	open my $ffmpeg, "-|", @{$command};
	while(<$ffmpeg>) {
		/^(\w+)=(.*)$/;
		$vals{$1} = $2;
		if($1 eq 'progress') {
			my $perc = int($vals{out_time_ms} / $length * 100);
			if($vals{progress} eq 'end') {
				$perc = 100;
			}
			if($multipass) {
				$perc = int($perc / 2);
			}
			if($pass == 2) {
				$perc += 50;
			}
			if($perc != $old_perc) {
				$old_perc = $perc;
				&{$self->progress}($perc);
			}
		}
	}
}

sub run {
	my $self = shift;
	my $pass;
	my @attrs = (
		'video_codec' => 'vcopy',
		'video_size' => 'vcopy',
		'video_width' => 'vcopy',
		'video_height' => 'vcopy',
		'video_bitrate' => 'vcopy',
		'video_framerate' => 'vcopy',
		'pix_fmt' => 'vcopy',
		'audio_codec' => 'acopy',
		'audio_bitrate' => 'acopy',
		'audio_samplerate' => 'acopy',
	);
	my @video_attrs = ('video_codec', 'video_size', 'video_width', 'video_height', 'video_bitrate', 'video_framerate', 'pix_fmt');
	my @audio_attrs = ('audio_codec', 'audio_bitrate', 'audio_samplerate');

	for($pass = 1; $pass <= ($self->multipass ? 2 : 1); $pass++) {
		my @command = ("ffmpeg", "-loglevel", "warning", "-y");
		foreach my $input(@{$self->inputs}) {
			if($self->multipass) {
				$input->pass($pass);
				$self->output->pass($pass);
			}
			while(scalar(@attrs) > 0) {
				my $attr = shift @attrs;
				my $target = shift @attrs;
				next unless $self->meta->get_attribute($target)->get_value($self);
				my $oval = $self->output->meta->find_attribute_by_name($attr)->get_value($self->output);
				my $ival = $input->meta->find_attribute_by_name($attr)->get_value($input);
				if(defined($oval) && $ival ne $oval) {
					$self->meta->get_attribute($target)->set_value($self, 0);
				}
			}
			push @command, $input->readopts($self->output);
		}
		if(!$self->vcopy()) {
			my $isize = $self->inputs->[0]->video_size;
			my $osize = $self->output->video_size;
			if(defined($isize) && defined($osize) && $isize ne $osize) {
				push @command, ("-vf", "scale=" . $osize);
			}
		}
		foreach my $map(@{$self->map}) {
			my $in_map = $map->input;
			my $index;
			for(my $i=0; $i<=$#{$self->inputs}; $i++) {
				if($in_map == ${$self->inputs}[$i]) {
					$index = $i;
				}
			}
			push @command, $map->arguments($index);
		}
		if($self->vcopy) {
			push @command, ('-c:v', 'copy');
		}
		if($self->acopy) {
			push @command, ('-c:a', 'copy');
		}
		push @command, $self->output->writeopts($self);

		print "Running: '" . join ("' '", @command) . "'\n";
		if($self->has_progress) {
			$self->run_progress(\@command, $pass, $self->multipass);
		} else {
			system(@command);
		}
	}
	foreach my $input(@{$self->inputs}) {
		$input->clear_pass;
	}
	$self->output->clear_pass;
}

no Moose;

1;