# ================================================================== # Plugins::ConvertVideo - Auto Generated Program Module # # Plugins::ConvertVideo # Author : Virginia Lo # Version : 1.1 # Updated : Wed Feb 21 16:05:27 2007 # # ================================================================== # package Plugins::ConvertVideo; # ================================================================== use strict; use GT::Base; use GT::Plugins qw/STOP CONTINUE/; use Links qw/$CFG $IN $DB/; use Links::Plugins; use vars qw/$WIDTH $HEIGHT $LINKID $CONVERTBOX $CHECKCONVERTBOX/; # Inherit from base class for debug and error methods @Plugins::ConvertVideo::ISA = qw(GT::Base); # Your code begins here! Good Luck! # PLUGIN HOOKS # =================================================================== sub validate_link_pre { # ------------------------------------------------------------------- # This subroutine will get called whenever the hook 'validate_link' # is run. You should call GT::Plugins->action (STOP) if you don't # want the regular code to run, otherwise the code will continue as # normal. # my ($link) = @_; $link = convert_video($link); return $link; } sub pre_form_link { # ------------------------------------------------------------------- # my $opts = shift; if ($opts->{mode} =~ /([add|modify])_form/) { $CONVERTBOX = 1; if ($1 eq 'add') { $CHECKCONVERTBOX = 1; } } return $opts; } sub post_form_link { # ------------------------------------------------------------------- # my @args = @_; if (($CONVERTBOX and $IN->param('db') eq 'Links') || $IN->param('action') eq 'link_add_form' || $IN->param('action') eq 'link_modify_form') { my $checked = ''; if ($IN->param('action') eq 'link_add_form' || $CHECKCONVERTBOX) { $checked = ' checked'; } my $font = 'face="Tahoma,Arial,Helvetica" size="2"'; $args[0] .= qq~

Converting Video(s)? YES
~; } return @args; } sub modify_link_pre { # ------------------------------------------------------------------- # This subroutine will get called whenever the hook 'modify_link' # is run. You should call GT::Plugins->action (STOP) if you don't # want the regular code to run, otherwise the code will continue as # normal. # my @args = @_; my $link = $args[0]; $LINKID = $link->{ID}; return @args; } sub modify_link_post { # ------------------------------------------------------------------- # my $ret = shift; if ($ret and $LINKID and $IN->param('admin_convert_video')) { my $linkdb = $DB->table('Links'); my $link = convert_video($linkdb->get($LINKID)); my $res = $linkdb->update($link, { ID => $LINKID }); if (!$res) { die "Can't modify link #$LINKID: $GT::SQL::error\n"; } } return $ret; } sub add_link_post { # ------------------------------------------------------------------- # $LINKID = shift; if ($LINKID) { &modify_link_post(1); } return $LINKID; } sub convert_video { # ------------------------------------------------------------------ # Grab video details my ($link) = @_; my $linkid = $link->{ID}; my $result = { ID => $linkid }; my $linksdb = $DB->table('Links'); my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo'); my $vf_field = $cfg->{video_file_field}; my $ff_field = $cfg->{flash_file_field}; my $thumb = $cfg->{thumbnail_file_field}; my $image = $cfg->{image_file_field}; my $url_field = $cfg->{video_url_field}; if ($cfg->{flash_dimension} =~ /\s*(\d+)x(\d+)\s*/) { ($WIDTH, $HEIGHT) = ($1, $2); } my $url = $link->{$url_field}; if ($url and $url ne '' and $url ne 'http://') { my $fh = $linksdb->file_info($image, $linkid) or return $result; require Plugins::SlideShow; # save the Image file (if required) my $fname = Plugins::SlideShow::get_filename("$fh"); my $efname = GT::CGI::escape($fname); my $main_fpath = $CFG->{admin_root_path} . "/tmp/work-$efname"; if ($main_fpath ne "$fh") { open IMG, ">$main_fpath" or return throw_error( $! ); binmode IMG; print IMG <$fh>; close IMG; } my $quality = 75; my $image_path = $CFG->{admin_root_path} . "/tmp/image-$efname"; Plugins::SlideShow::resize_image($main_fpath, $image_path, $WIDTH, $HEIGHT, $quality); $result->{$image} = GT::SQL::File->open($image_path); if ($cfg->{thumbnail_size} =~ /\s*(\d+)x(\d+)\s*/) { my ($thumb_width, $thumb_height) = ($1, $2); my $thumb_path = $CFG->{admin_root_path} . "/tmp/thumbnail-$efname"; Plugins::SlideShow::resize_image($main_fpath, $thumb_path, $thumb_width, $thumb_height, $quality); $result->{$thumb} = GT::SQL::File->open($thumb_path); } return $result; } my $fh = $linksdb->file_info($vf_field, $linkid) or return $result; my $full_path = "$fh"; my $video = {}; my $filename = $full_path; $filename =~ s/(.+)\/\d-([^\/]+)\.$/$2/g; my $flv_file_path = $CFG->{admin_root_path} . "/tmp/" . $linkid . ".flv"; my $thumb_path = $CFG->{admin_root_path} . "/tmp/" . "thumbnail-" . $linkid . ".png"; my $image_path = $CFG->{admin_root_path} . "/tmp/" . "image-" . $linkid . ".png"; my $buf = `ffmpeg -i "$full_path" 2>&1`; if ($buf =~ /Video:\s.+\s+(\d+)x(\d+),?.*\s+(\d+)\s+(?:fps|tb)/) { $video->{width} = $1; $video->{height} = $2; $video->{fps} = $3; if ($buf =~ /Duration:\s+(\d+):(\d+):(\d+).+bitrate:\s+(\d+)\s+kb\/s/) { $video->{duration} = $1 * 3600 + $2 * 60 + $3; $video->{bitrate} = $4; } } else { warn "Couldn't get video info"; return $result; } # Figure out any scaling we might need to do if ($video->{width} > $WIDTH and $video->{height} > $HEIGHT) { # Choose the larger dimension to scale down if ($video->{width} / $WIDTH > $video->{height} / $HEIGHT) { $video->{out_height} = int($video->{height} * $WIDTH / $video->{width}); $video->{out_width} = $WIDTH; } else { $video->{out_width} = int($video->{width} * $HEIGHT / $video->{height}); $video->{out_height} = $HEIGHT; } } elsif ($video->{width} > $WIDTH) { $video->{out_height} = int($HEIGHT * $WIDTH / $video->{width}); $video->{out_width} = $WIDTH; } elsif ($video->{height} > $HEIGHT) { $video->{out_height} = $HEIGHT; $video->{out_width} = int($video->{height} * $WIDTH / $HEIGHT); } # Source dimensions are smaller than output else { $video->{out_height} = $video->{height}; $video->{out_width} = $video->{width}; } $video->{out_height}++ if $video->{out_height} % 2; $video->{out_width}++ if $video->{out_width} % 2; $video->{out_padtop} = int(($HEIGHT - $video->{out_height}) / 2); $video->{out_padtop}-- if $video->{out_padtop} % 2; $video->{out_padbottom} = $HEIGHT - $video->{out_height} - $video->{out_padtop}; $video->{out_padleft} = int(($WIDTH - $video->{out_width}) / 2); $video->{out_padleft}-- if $video->{out_padleft} % 2; $video->{out_padright} = $WIDTH - $video->{out_width} - $video->{out_padleft}; # Encode the video system( "ffmpeg", '-i', "$full_path", '-y', # overwrite # video options '-vf', "scale=$video->{out_width}:$video->{out_height},pad='$WIDTH:$HEIGHT:$video->{out_padleft}:$video->{out_padtop}'", # audio options '-ar', 22050, # audio sampling rate (Hz) '-ab', 64, # audio bitrate (kb/s) '-ac', 2, # audio channels # encoding options # '-b', 100000, # video bitrate (b/s) '-qscale', $cfg->{flash_quality} || 6, # quality scale (1 [best] - 31 [worst]) # watermark # '-vhook', '/usr/lib/vhook/watermark.so -f admin/water3.gif', # output "$flv_file_path", ); =tag # video options '-r', $video->{fps}, # frame rate '-s', "$video->{out_width2}x$video->{out_height2}", # frame size '-padtop', $video->{out_padtop}, '-padbottom', $video->{out_padbottom}, '-padleft', $video->{out_padleft}, '-padright', $video->{out_padright}, =cut # ----------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------- # Generate a thumbnail (a quarter of the way through) my $when = int($video->{duration} * 0.25); my $hours = int($when / 3600); my $mins = int($when / 60) - $hours * 60; my $secs = $when - $hours * 3600 - $mins * 60; $when = sprintf("%.2d:%.2d:%.2d", $hours, $mins, $secs); if ($cfg->{thumbnail_size} and $cfg->{thumbnail_file_field}) { system( "ffmpeg", '-i', "$flv_file_path", '-y', # overwrite '-vframes', 1, # record 1 frame '-ss', $when, '-an', # no audio '-vcodec', 'png', '-f', 'rawvideo', '-s', $cfg->{thumbnail_size}, "$thumb_path", ); } system( "ffmpeg", '-i', "$flv_file_path", '-y', # overwrite '-vframes', 1, # record 1 frame '-ss', $when, '-an', # no audio '-vcodec', 'png', '-f', 'rawvideo', '-s', "${WIDTH}x$HEIGHT", # frame size "$image_path", ); $result->{$ff_field} = GT::SQL::File->open($flv_file_path); $result->{$image} = GT::SQL::File->open($image_path); $result->{$thumb} = GT::SQL::File->open($thumb_path) if ($cfg->{thumbnail_file_field} and $thumb_path); return $result; } sub get_file_path { # --------------------------------------------------------------------------- # return file path of a file column # my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo'); my $id = shift; my $field_name = shift || "flash_file_field"; my $field = $cfg->{$field_name}; my $wantpath = shift || 0; my $fh = $DB->table('Links')->file_info($field, $id); return { $field_name . "_path" => '' } if (!$fh); my $fdir = $fh->File_Directory(); my $full_path = "$fh"; my $rel_path = $full_path; $rel_path =~ s,$fdir,,; $rel_path =~ s,%,%25,g; if ($wantpath) { return $rel_path; } return { $field_name . "_path" => $cfg->{video_url} . $rel_path }; } sub get_flash_dimension { my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo'); my $width = 320; my $height = 240; if ($cfg->{flash_dimension} =~ /\s*(\d+)x(\d+)\s*/) { ($width, $height) = ($1, $2); } return { 'video_width' => $width, 'video_height' => $height }; } sub get_video_max_size { my $cfg = Links::Plugins::get_plugin_user_cfg('ConvertVideo'); my $field_name = $cfg->{video_file_field}; my %cols = $DB->table('Links')->_file_cols(); return $cols{$field_name}->{file_max_size}; } # Always end with a 1. 1;