#!/usr/bin/perl use warnings; use strict; use Image::Magick; use MIME::Base64; # Usage: $0 myneat.flv/mpg/avi OR $0 r # The r option will skip ripping and recombine # the contents of the riptemp-$base subdir. # This allows you to manually edit individual files. # If more than 2 riptemp dirs are present, the first # in a dirlist will be used. So.... work on 1 at a time # in their own directories. This is just a snippet. :-) # I admit, that the Lives (Linux Video Editing System) # at http://lives.sourceforge.net/ # is much more powerful than this. Check it out, and # it's "smogrify" perl script.... which is it's workhorse. $|++; my $video = shift || 'z-men.mpg'; my $base; if($video eq 'r'){ recombine(); }else{ $video =~ /^(.+)(\.\w+)$/; $base = $1; } # only 2 IM objects reused in overlay, so they are global my $bimage = Image::Magick->new; #reused objects my $oimage = Image::Magick->new; #reused objects rip(); make_overlay_graphic(); overlay(); recombine(); exit; #######################################################3 sub rip{ #rip to jpg's and audio #will make it's own temp dir my @moptions =( 'mplayer', '-osdlevel', 0, '-vo', "jpeg:quality=100:outdir=riptemp-$base:maxfiles=2000", '-noframedrop', #important for quality '-ao', "pcm:file=$base.wav", $video, ); system(@moptions); } #########################################################3 sub make_overlay_graphic{ # enter lines of text as array elements my @tarray; foreach (1..1500){ push @tarray , "$_ blah blah blah" } # get logo from base64encoded text my $wimage = Image::Magick->new(magick=>'png'); my $stamp = get_stamp(); $wimage->BlobToImage($stamp); #$wimage->Write('stamp.png'); #if you want to examine it #setup overlay $oimage->Set(size=>'150x1500'); #convenient for my tests #but could be calculated based on the base video frame sizes #this is just a crude demo my $rc = $oimage->Read("xc:green"); $oimage->Transparent('color' => 'green'); #not neccessary to use green here, other than to show # how green screened overlays are made =head1 IM's Annotate methods text=>string, font=>string, family=>string, style=>{Normal, Italic, Oblique, Any}, stretch=>{Normal, UltraCondensed, ExtraCondensed, Condensed, SemiCondensed, SemiExpanded, Expanded, ExtraExpanded, UltraExpanded}, weight=>integer, pointsize=>integer, density=>geometry, stroke=>color name, strokewidth=>integer, fill=>color name, undercolor=>color name, geometry=>geometry, gravity=>{NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast}, antialias=>{true, false}, x=>integer, y=>integer, affine=>array of float values, translate=>float, float, scale=>float, float, rotate=>float. skewX=>float, skewY=> float, align=>{Left, Center, Right}, encoding=>{UTF-8} =cut # create overlay image my $pos = 0; foreach (@tarray){ $pos+=50; $oimage->Annotate( pointsize => 12, fill => '#ffeeffff', #last 2 digits transparency in hex ff=max text => $_, #gravity => $pos x=> 1, y=> $pos, ); # add logo every 300 if ($pos % 300 == 0){ $rc = $oimage->Composite( #gravity => "Center", compose=>'Plus', image => $wimage, #opacity => '50%', #how much transparency #tile => 0, x=> 50, y=> $pos ); } } #print "$pos\n"; $oimage->Write("$base-overlay.png"); } ##############################################3 sub overlay{ my @files = ; #print join "\n", @files; my $max = scalar @files; #reload $oimage undef @$oimage; $oimage->read("$base-overlay.png"); my $count = 0; my $x = 0; my $y = 0; foreach my $file ( @files ) { # operate on jpgs for effects $count++; print "\rprocessing file $file $count/$max"; $y += 2; $bimage->Read($file); $bimage->Sharpen(10); my $geom_string = '-'.$x.'-'.$y; print "\n$geom_string\n"; my $rc = $bimage->Composite( geometry => $geom_string, #'-0-500', compose=>'ATop', image => $oimage, # opacity => '100%', # tile => 0, ); $bimage->Write($file); undef @$bimage; #clear out object data # for quick testing # last if $count == 10; } print "\n\nDone effects processing\n\n"; } ##################################################################### sub recombine{ opendir my $dh, '.' or die "Error: $!\n"; my @files = grep !/^\.\.?$/, readdir $dh; @files = grep /^riptemp-(.*)$/, @files; closedir $dh; my $dir = $files[0]; $dir =~ /^riptemp-(.*)$/; my $base = $1; my @moptions =( 'mencoder', "mf://$dir/*.jpg", '-mf', 'fps=29.97', #NTSC tv video rate in '-audiofile', "$base.wav", '-srate', 22050, '-o', "$base-overlayed.mpg", '-ovc', 'lavc', '-lavcopts', 'vcodec=mpeg4:vbitrate=100', '-oac', 'mp3lame', '-audio-delay', 2, #adjust for audio syncing problems ); system(@moptions); } ######################################################################3 sub get_stamp{ return decode_base64( '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'); }