X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=bin%2Fmplayer.pl;h=ffc4d4922e551b763e04f4b6622afbf6eba92adb;hb=bb1948374f28cd8da4d65871ae99ee10c248c543;hp=5410e44ef91f2db66be1f74c0dee80fd173200b4;hpb=d002ba0c3a468ba5830418e32eb3602cb7fcbce5;p=HTML5TV.git diff --git a/bin/mplayer.pl b/bin/mplayer.pl index 5410e44..ffc4d49 100755 --- a/bin/mplayer.pl +++ b/bin/mplayer.pl @@ -4,15 +4,20 @@ use warnings; use strict; use IPC::Open3 qw(open3); -use IO::Epoll; +use IO::Select; use Data::Dump qw(dump); use File::Slurp; use YAML; use JSON; use HTML::TreeBuilder; -use Imager; +use Graphics::Magick; +use Time::HiRes qw(time); +use File::Path qw(rmtree); -my $debug = 0; +use lib 'lib'; +use HTML5TV::Slides; + +my $debug = $ENV{DEBUG} || 0; my $movie = shift @ARGV; @@ -56,6 +61,8 @@ my $preroll = 3; my $slide_factor = 4; # 1/4 size of video +my $min_slide_height = 480; + our $to_mplayer; our $from_mplayer; our $err_mplayer; @@ -65,23 +72,22 @@ my $pid = open3( $to_mplayer, $from_mplayer, $err_mplayer, 'mplayer', '-slave', '-idle', '-quiet', + '-msglevel', 'demux=9', '-msgmodule', '-edlout', $edl, '-osdlevel', 3, '-vf' => 'screenshot', ); -my $epfd = epoll_create(10); - -epoll_ctl($epfd, EPOLL_CTL_ADD, fileno STDIN , EPOLLIN ) >= 0 || die $!; -epoll_ctl($epfd, EPOLL_CTL_ADD, fileno $from_mplayer , EPOLLIN ) >= 0 || die $!; -#epoll_ctl($epfd, EPOLL_CTL_ADD, fileno $to_mplayer , EPOLLOUT ) >= 0 || die $!; +my $select = IO::Select->new(); +#$select->add( \*STDIN ); +$select->add( $from_mplayer ); +$select->add( $err_mplayer ); sub load_subtitles; sub load_movie { warn "$movie ", -s $movie, " bytes $edl\n"; print $to_mplayer qq|loadfile "$movie"\n|; - print $to_mplayer "get_property $_\n" foreach ( qw/metadata video_codec video_bitrate width height fps length/ ); load_subtitles; } @@ -137,7 +143,12 @@ sub oggThumb { my $video = shift; my $file = shift; my $t = join(',', @_); - system "oggvideotools/src/oggThumb -t $t -o jpg -n $file $video"; + system "oggThumb -t $t -o jpg -n $file $video"; +} + +sub fmt_mmss { + my $t = shift; + return sprintf('%02d:%02d', int($t/60), int($t%60)); } sub html5tv { @@ -204,8 +215,10 @@ sub html5tv { } if ( @frames ) { + rmdir $_ foreach glob "$media_dir/s/[124]"; my $hires = "$media_dir/s/hires"; mkdir $hires unless -e $hires; + oggThumb $movie, "$hires/.f%.jpg", map { $_->[0] } @frames; foreach my $i ( 0 .. $#frames ) { @@ -213,6 +226,7 @@ sub html5tv { my $to = "$hires/f" . $frames[$i]->[1] . '.jpg'; rename $from, $to || warn "can't rename $from -> $to: $!"; } + } foreach ( 0 .. $#slide_t ) { @@ -226,54 +240,62 @@ sub html5tv { my @slides_hires = glob "$media_dir/s/hires/*"; - foreach my $factor ( 4, 2, 1 ) { - my $w = $prop->{width} / $factor; - my $h = $prop->{height} / $factor; + my $path = "$media_dir/s"; - my $path = "$media_dir/s"; - if ( ! -d $path ) { - warn "create slides imaes in $path"; - mkdir $path; - } + if ( ! -d $path ) { + warn "create slides images in $path"; + mkdir $path; + } - $path .= '/' . $factor; + foreach my $hires ( @slides_hires ) { - if ( ! -d $path ) { - mkdir $path; - warn "created $path\n"; + my $im = Graphics::Magick->new; + $im->ReadImage( $hires ); - } + my ($slide_width, $slide_height) = Graphics::Magick->new->Ping( $hires ); + my $slide_aspect = $slide_width / $slide_height; - foreach my $hires ( @slides_hires ) { + my $nr = $1 if $hires =~ m{(\d+)\.\w+$} || warn "can't find number in $hires"; + next unless $nr; + + foreach my $factor ( 1, 2, 4 ) { + + mkdir "$path/$factor" unless -e "$path/$factor"; - my $nr = $1 if $hires =~ m{(\d+)\.\w+$} || warn "can't find number in $hires"; - next unless $nr; my $file = slide_jpg( $factor => $nr ); - warn "slide $hires -> $file\n"; next if -e $file; - if ( my $im = Imager->new( file => $hires ) ) { - $im->scale( xpixels => $w, ypixels => $h, type => 'min' )->write( file => $file ); - warn "resized $file ", -s $file, " bytes\n"; - } else { - die "can't open $hires: $!"; - } + $min_slide_height = $prop->{height} if $prop->{height} > $min_slide_height; + + my $w = $min_slide_height / $factor * $slide_aspect; + my $h = $min_slide_height / $factor; + + warn "slide [$nr] $hires -> ${w}x${h} $file\n"; + + $im->Resize( width => $w, height => $h, filter => 13, blur => 0.9 ); + + my $c = $h / 10; + my %info = ( + font => 'Sans', pointsize => $h / 10, + #text => "$factor = $w*$h", + text => " $nr ", + y => $c, + x => $c, + ); + #warn "# info ", dump %info; + #warn dump $im->QueryFontMetrics( %info ); + my ($x_ppem, $y_ppem, $ascender, $descender, $width, $height, $max_advance) = $im->QueryFontMetrics( %info ); + my $background = Graphics::Magick->new( size => $width . 'x' . $height ); + $background->ReadImage( 'xc:black' ); + $im->Composite( image => $background, compose => 'Over', x => $c, y => $c, opacity => 75 ); + $info{y} += $ascender; + $im->Annotate( fill => 'yellow', %info ); + $im->Write( filename => $file ); } } - my ( $slide_width, $slide_height ); - - my $im = Imager->new( file => slide_jpg( 1 => 1 ) ); - - if ( $im ) { - $slide_width = $im->getwidth / $slide_factor; - $slide_height = $im->getheight / $slide_factor; - } else { - warn "can't find first slide default to 1/$slide_factor of video size\n"; - $slide_width = $prop->{width} / $slide_factor; - $slide_height = $prop->{height} / $slide_factor; - } + my ($slide_width, $slide_height, $size, $format) = Graphics::Magick->new->Ping( slide_jpg( $slide_factor => 1 ) ); my $html5tv = { sync => $sync, @@ -334,20 +356,24 @@ sub html5tv { $html5tv->{html}->{subtitles_table} = qq|| . join("\n", - map { qq| + map { + my $s = fmt_mmss( $_->{startTime} ); + my $e = fmt_mmss( $_->{endTime} ); + qq| - - + + - | } + | + } customEvents_sorted ) . qq|
$_->{startTime}$_->{endTime}$s$e $_->{args}->{title}
download subtitles| ; my $hCalendar = '
Create hCalendar.html to fill this space
'; - my $hcal_path = '$media_dir/hCalendar.html'; + my $hcal_path = "$media_dir/hCalendar.html"; if ( -e $hcal_path ) { $html5tv->{hCalendar} = read_file $hcal_path; my $tree = HTML::TreeBuilder->new; @@ -522,6 +548,8 @@ sub add_subtitle { preroll $subtitles[ $#subtitles ]->[0], $line; } +our $pos; + sub time_pos { print $to_mplayer qq|get_property time_pos\n|; my $pos = <$from_mplayer>; @@ -537,7 +565,6 @@ sub sub_fmt { } sub prev_subtitle { - my $pos = time_pos; my $s = ( grep { $_->[0] < $pos } @subtitles )[-1] || return; warn "<<<< subtitle ", sub_fmt $s; preroll $s->[0], $s->[2]; @@ -545,7 +572,6 @@ sub prev_subtitle { } sub next_subtitle { - my $pos = time_pos; my $s = ( grep { $_->[0] > $pos } @subtitles )[0] || return; warn ">>>> subtitle ", sub_fmt $s; preroll $s->[0], $s->[2]; @@ -554,7 +580,6 @@ sub next_subtitle { sub current_subtitle { my $callback = shift; - my $pos = time_pos; my $visible; foreach my $nr ( 0 .. $#subtitles ) { my $s = $subtitles[$nr]; @@ -585,83 +610,77 @@ sub move_subtitle { load_movie; -while ( my $events = epoll_wait($epfd, 10, 1000) ) { # Max 10 events returned, 1s timeout - - warn "no events" unless $events; - - foreach my $e ( @$events ) { -# warn "# event: ", dump($e), $/; - - my $fileno = $e->[0]; - - if ( $fileno == fileno STDIN ) { - my $chr; - sysread STDIN, $chr, 1; - print $chr; - } elsif ( $fileno == fileno $from_mplayer ) { - my $chr; - sysread $from_mplayer, $chr, 1; - print $chr; - - if ( $chr =~ m{[\n\r]} ) { - - exit if $line =~ m{Exiting}; +my $slides = HTML5TV::Slides->new( + sub { + my $t = shift; + my $nr = 0; + foreach my $s ( @subtitles ) { + $nr = $1 if $s->[2] =~ m{\[(\d+)\]} && $s->[0] < $t; + } + return $nr; + } +); - if ( $line =~ m{ANS_(\w+)=(\S+)} ) { - $prop->{$1} = $2; - warn "prop $1 = $2\n"; - } elsif ( $line =~ m{No bind found for key '(.+)'} ) { +print $to_mplayer "get_property $_\n" foreach grep { ! $prop->{$_} } ( qw/metadata video_codec video_bitrate width height fps length/ ); - # XXX keyboard shortcuts +my $t = time; - $1 eq 'c' ? repl - : $1 eq ',' ? add_subtitle - : $1 eq 'F1' ? prev_subtitle - : $1 eq 'F2' ? move_subtitle( -0.3 ) - : $1 eq 'F3' ? move_subtitle( +0.3 ) - : $1 eq 'F4' ? next_subtitle - : $1 eq 'F5' ? save_subtitles - : $1 eq 'F9' ? add_subtitle - : $1 eq 'F12' ? edit_subtitles - : warn "CUSTOM $1\n" - ; +while ( my $line = <$from_mplayer> ) { - } elsif ( $line =~ m{EDL}i ) { +#warn "### $line\n"; - print $to_mplayer qq|osd_show_text "$line"\n|; + my $dt = time - $t; +#warn "dt $dt\n"; + if ( abs($dt) > 0.7 ) { + $slides->show( $pos ); + $t = time; + } - if ( my $pos = time_pos ) { - if ( $line =~ m{start}i ) { - push @subtitles, [ $pos, $pos, '-' ]; - } else { - $subtitles[ $#subtitles ]->[1] = $pos; - } - } - } elsif ( $line =~ m{(shot\d+.png)} ) { - my $shot = $1; - my $t = time_pos; - warn "shot $t $shot\n"; + if ( $line =~ m{DEMUX.+pts=(\d+\.\d+)} ) { + $pos = $1 if $1 > 0.2; # mplayer demuxer report fake position while seeking + } elsif ( $line =~ m{Exiting} ) { + exit; + } elsif ( $line =~ m{ANS_(\w+)=(\S+)} ) { + $prop->{$1} = $2; + warn "prop $1 = $2\n"; + } elsif ( $line =~ m{No bind found for key '(.+)'} ) { + + # XXX keyboard shortcuts + + $1 eq 'c' ? repl + : $1 eq ',' ? add_subtitle + : $1 eq 'F1' ? prev_subtitle + : $1 eq 'F2' ? move_subtitle( -0.3 ) + : $1 eq 'F3' ? move_subtitle( +0.3 ) + : $1 eq 'F4' ? next_subtitle + : $1 eq 'F5' ? save_subtitles + : $1 eq 'F9' ? add_subtitle + : $1 eq 'F12' ? edit_subtitles + : warn "CUSTOM $1\n" + ; - my @existing_slides = glob("$media_dir/s/hires/*"); - my $nr = $#existing_slides + 2; + } elsif ( $line =~ m{EDL}i ) { - push @subtitles, [ $t, $t, "slide:$nr shot:$t" ]; + print $to_mplayer qq|osd_show_text "$line"\n|; - warn "slide $nr from video $t file $shot\n"; - save_subtitles; - } + if ( $line =~ m{start}i ) { + push @subtitles, [ $pos, $pos, '-' ]; + } else { + $subtitles[ $#subtitles ]->[1] = $pos; + } + } elsif ( $line =~ m{(shot\d+.png)} ) { + my $shot = $1; + warn "shot $pos $shot\n"; - $line = ''; - } else { - $line .= $chr; - } + my @existing_slides = glob("$media_dir/s/hires/*"); + my $nr = $#existing_slides + 2; + push @subtitles, [ $pos, $pos, "slide:$nr shot:$pos" ]; - } elsif ( $fileno == fileno $to_mplayer ) { -# warn "command"; - } else { - die "invalid fileno $fileno"; - } + warn "slide $nr from video $pos file $shot\n"; + save_subtitles; + } else { + warn "IGNORE $line"; } }