Changeset 18556


Ignore:
Timestamp:
2009-02-20T11:40:23+13:00 (15 years ago)
Author:
davidb
Message:

Restructing of VideoPlugin to be like ImagePlugin (with its supporting ImageConverter plugin). The pattern was then repeated for Audio, so we now have an AudioPlugin and AudioConverter. Where possible code is shared in a Multimedia base class

Location:
extensions/gsdl-video/trunk/perllib/plugins
Files:
4 added
2 edited

Legend:

Unmodified
Added
Removed
  • extensions/gsdl-video/trunk/perllib/plugins/MultimediaConverter.pm

    r18543 r18556  
    1 ##########################################################################
    2 #
    3 # videoconvert.pm -- utility to help convert video file
    4 #
    5 # Copyright (C) 1999 DigiLib Systems Limited, NZ
     1###########################################################################
     2#
     3# MultimediaConverter - helper plugin that does audio and video conversion using ffmpeg
     4#
     5# A component of the Greenstone digital library software
     6# from the New Zealand Digital Library Project at the
     7# University of Waikato, New Zealand.
     8#
     9# Copyright (C) 2008 New Zealand Digital Library Project
    610#
    711# This program is free software; you can redistribute it and/or modify
     
    2024#
    2125###########################################################################
    22 
    23 
    24 package videoconvert;
     26package MultimediaConverter;
     27
     28use BaseMediaConverter;
     29
    2530
    2631use strict;
    2732no strict 'refs'; # allow filehandles to be variables and viceversa
    2833
    29 use baseconvert;
    30 
    31 sub BEGIN {
    32     @videoconvert::ISA = ('baseconvert');
    33 }
    34 
    35 
    36 # Discover the characteristics of a video file.
    37 #  Equivalent step to that in ImagePlugin that uses ImageMagicks's 'indentify' utility
    38 #  Here we use 'ffmpeg' for video but for consistency keep the Perl method name the same
    39 #  as before
     34use gsprintf 'gsprintf';
     35
     36BEGIN {
     37    @MultimediaConverter::ISA = ('BaseMediaConverter');
     38}
     39
     40my $arguments = [
     41      { 'name' => "converttotype",
     42    'desc' => "{ImageConverter.converttotype}",
     43    'type' => "string",
     44    'deft' => "",
     45    'reqd' => "no" },
     46      { 'name' => "minimumsize",
     47    'desc' => "{ImageConverter.minimumsize}",
     48    'type' => "int",
     49    'deft' => "100",
     50    'range' => "1,",
     51    'reqd' => "no" },
     52         ];
     53
     54my $options = { 'name' => "MultimediaConverter",
     55        'desc' => "{MultimediaConverter.desc}",
     56        'abstract' => "yes",
     57        'inherits' => "yes",
     58        'args' => $arguments };
     59
     60sub new {
     61    my ($class) = shift (@_);
     62    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
     63    push(@$pluginlist, $class);
     64
     65    push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
     66    push(@{$hashArgOptLists->{"OptList"}},$options);
     67
     68    my $self = new BaseMediaConverter($pluginlist, $inputargs, $hashArgOptLists, 1);
     69
     70
     71    return bless $self, $class;
     72
     73}
     74
     75
     76
     77# needs to be called after BasePlugin init, so that outhandle is set up.
     78sub init {
     79    my $self = shift(@_);
     80
     81    my $outhandle = $self->{'outhandle'};
     82
     83    $self->{'tmp_file_paths'} = ();
     84
     85    # Check that ffmpeg is installed and available on the path
     86    my $multimedia_conversion_available = 1;
     87    my $no_multimedia_conversion_reason = "";
     88
     89    # None of this works very well on Windows 95/98...
     90    if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
     91    $multimedia_conversion_available = 0;
     92    $no_multimedia_conversion_reason = "win95notsupported";
     93    } else {
     94
     95    my $result = `ffmpeg -h 2>&1`;
     96
     97
     98    if (!defined $result || $result !~ m/^FFmpeg version/) {
     99        $self->{'ffmpeg_installed'} = 0;
     100        print $outhandle $result;
     101        $multimedia_conversion_available = 0;
     102        $no_multimedia_conversion_reason = "ffmpegnotinstalled";
     103    }
     104    else {
     105        $self->{'ffmpeg_installed'} = 1;
     106    }
     107    }
     108
     109    $self->{'multimedia_conversion_available'} = $multimedia_conversion_available;
     110    $self->{'no_multimedia_conversion_reason'} = $no_multimedia_conversion_reason;
     111
     112    if ($self->{'multimedia_conversion_available'} == 0) {
     113    &gsprintf($outhandle, "MultimediaConverter: {MultimediaConverter.noconversionavailable} ({MultimediaConverter.".$self->{'no_multimedia_conversion_reason'}."})\n");
     114    }
     115       
     116}
     117   
     118
    40119
    41120
    42121sub identify {
    43     my ($video, $outhandle, $verbosity) = @_;
    44 
    45     # Use the ffmpeg command to get the file specs
    46     my $command = "ffmpeg -i \"$video\"";
    47 
    48     print $outhandle "  $command\n" if ($verbosity > 2);
    49     my $result = '';
    50     $result = `$command 2>&1`;
    51     print $outhandle "  $result\n" if ($verbosity > 4);
    52 
    53     # Read the type, width, and height etc.
    54     my $vtype =  'unknown';
    55     my $vcodec = 'unknown';
    56     my $width =  'unknown';
    57     my $height = 'unknown';
    58     my $fps    = 'unknown';
    59 
    60     my $atype =  'unknown';
    61     my $afreq =  'unknown';
    62     my $achan =  'unknown';
    63     my $arate =  'unknown';
    64 
    65     my $video_safe = quotemeta $video;
    66 
    67     # strip off everything up to filename
    68     $result =~ s/^.*\'$video_safe\'://s;
    69 
    70     if ($result =~ m/Video: (.*?) fps/m) {
    71     my $video_info = $1;
    72     if ($video_info =~ m/([^,]+),(?: ([^,]+),)? (\d+)x(\d+),.*?(\d+\.\d+)/)
    73     {
    74         $vtype = $1;
    75         $vcodec = $2 if defined $2;
    76         $width = $3;
    77         $height = $4;
    78         $fps = $5;
    79     }
    80     }
    81 
    82 ##    if ($result =~ m/Video: (\w+), (\w+), (\d+)x(\d+),.*?(\d+\.\d+) fps/m) {
    83 #    if ($result =~ m/Video: ([^,]+),(?: ([^,]+),)? (\d+)x(\d+),.*?(\d+\.\d+) fps/m) {
    84 #   $vtype = $1;
    85 #   $vcodec = $2;
    86 #   $width = $3;
    87 #   $height = $4;
    88 #   $fps = $5;
    89 #    }
    90 
    91     if ($result =~ m/Audio: (\w+), (\d+) Hz, (\w+)(?:, (\d+.*))?/m) {
    92     $atype = $1;
    93     $afreq = $2;
    94     $achan = $3;
    95     $arate = $4 if (defined $4);
    96     }
    97 
    98     # Read the duration
    99     my $duration = "unknown";
    100     if ($result =~ m/Duration: (\d+:\d+:\d+\.\d+)/m) {
    101     $duration = $1;
    102     }
    103     print $outhandle "  file: $video:\t $vtype, $width, $height, $duration\n"
    104     if ($verbosity > 2);
    105 
    106     if ($verbosity >3) {
    107     print $outhandle "\t video codec=$vcodec, fps = $fps\n";
    108     print $outhandle "\t audio codec=$atype, freq = $afreq Hz, $achan, $arate\n";
    109     }
    110 
    111     # Return the specs
    112     return ($vtype, $width, $height, $duration, -s $video,
    113         $vcodec,$fps,$atype,$afreq,$achan,$arate);
    114 }
    115 
    116 
    117 sub vob_durations
    118 {
    119     my ($media_base_dir,$title_num,$outhandle) = @_;
    120 
    121     my $filter_re = sprintf("^VTS_%02d_[1-9]\\.VOB\$",$title_num);
    122 
    123     my $duration_info = {};
    124 
    125     if (opendir(VTSIN,$media_base_dir)) {
    126     my @vts_title_vobs = grep { $_ =~ m/$filter_re/ } readdir(VTSIN);
    127     closedir(VTSIN);
    128 
    129     foreach my $v (@vts_title_vobs) {
    130         my $full_v = &util::filename_cat($media_base_dir,$v);
    131 
    132         my ($vtype, $width, $height, $duration, $vsize,
    133         $vcodec,$fps,$atype,$afreq,$achan,$arate) = identify($full_v,$outhandle,0);
    134 
    135         my ($vob_num) = ($v =~ m/^VTS_\d\d_(\d)\.VOB$/);
    136 
    137         $duration_info->{$vob_num} = $duration;
    138         print STDERR "**** $title_num: $title_num, storing {$vob_num} => $duration\n";
    139 
    140     }
    141 
    142     }
    143     else {
    144     print $outhandle "Warning: unable to read files in directory $media_base_dir\n";
    145     }
    146    
    147     return $duration_info;
    148 
    149 }
    150 
    151 
    152 
    153 sub new {
    154     my ($class) = shift @_;
    155 
    156     my ($base_dir,$video_filename, $verbosity,$outhandle,
    157     $exp_duration,$ascii_only_filenames) = @_;
    158 
    159     my $self = new baseconvert($base_dir,$video_filename,$verbosity,$outhandle);
    160 
    161     $self->{'exp_duration'} = $exp_duration;
     122    my ($filename, $outhandle, $verbosity) = @_;
     123
     124    die "MultimediaConvert::identify() needs to be defined by inheriting plugin";
     125}
     126
     127
     128
     129sub init_cache_for_file {
     130    my $self = shift(@_);
     131
     132    my ($media_filename) = @_;
     133
     134    $self->SUPER::init_cache_for_file($media_filename);
     135
     136
     137    # This should probably be replaced with Anu's work that replaced
     138    # non-ASCII chars with URL encodings
     139
     140    my $ascii_only_filenames = $self->{'use_ascii_only_filenams'};
    162141
    163142    if (defined $ascii_only_filenames && ($ascii_only_filenames)) {
    164     my $file_root = $self->{'file_root'};
    165     $self->{'file_root'} = ascii_only_filename($file_root);
     143    my $file_root = $self->{'cached_file_root'};
     144    $self->{'cached_file_root'} = ascii_only_filename($file_root);
    166145    }
    167146                 
    168     my @ffmpeg_monitor   = ( 'monitor_init'   , "videoconvert::ffmpeg_monitor_init",
    169                  'monitor_line'   , "videoconvert::ffmpeg_monitor_line",
    170                  'monitor_deinit' , "videoconvert::ffmpeg_monitor_deinit" );
     147    my @ffmpeg_monitor   = ( 'monitor_init'   , "MultimediaConverter::ffmpeg_monitor_init",
     148                 'monitor_line'   , "MultimediaConverter::ffmpeg_monitor_line",
     149                 'monitor_deinit' , "MultimediaConverter::ffmpeg_monitor_deinit" );
    171150                   
    172     my @flvtool2_monitor = ( 'monitor_init'   ,"monitor_init_unbuffered",
    173                  'monitor_line'   , "videoconvert::flvtool2_monitor_line",
    174                  'monitor_deinit' , "monitor_deinit_unbuffered" );
    175151                   
    176152    $self->{'ffmpeg_monitor'} = \@ffmpeg_monitor;
    177     $self->{'flvtool2_monitor'} = \@flvtool2_monitor;
    178 
    179 
    180     return bless $self, $class;
    181 }
     153
     154
     155}
     156
     157
    182158
    183159
     
    216192
    217193    my $url = $file_unicode;
    218     $url =~ s/\x{2018}|\x{2019}|\x{201C}|\x{201D}//g; # remove smart quotes as cause problem in URL for video server
    219     $url =~ s/\x{2013}/\-/g; # change en-dash to '-' as again causes problems for video server
     194    $url =~ s/\x{2018}|\x{2019}|\x{201C}|\x{201D}//g; # remove smart quotes as cause problem in URL for streaming web server
     195    $url =~ s/\x{2013}/\-/g; # change en-dash to '-' as again causes problems for streaming web server
    220196   
    221197    return $url;
     
    255231
    256232
    257 
    258 sub optional_frame_scale
    259 {
    260     my $self = shift (@_);
    261     my ($orig_size,$video_width,$video_height) = @_;
    262 
    263     my $s_opt = "";
    264     if ($video_width > $video_height) {
    265     if ($video_width > $orig_size) {
    266         my $scale_factor = $orig_size/$video_width;
    267         my $scaled_width = int($video_width * $scale_factor);
    268         my $scaled_height = int($video_height * $scale_factor);
    269 
    270         # round to be ensure multiple of 2 (needed by some codecs)
    271         $scaled_width  = int($scaled_width/2)*2;
    272         $scaled_height = int($scaled_height/2)*2;
    273 
    274         $s_opt = "-s ${scaled_width}x${scaled_height}";
    275     }
    276     # else, video is smaller than requested size, don't scale up
    277     }
    278     else {
    279     if ($video_height > $orig_size) {
    280         my $scale_factor = $orig_size/$video_height;
    281         my $scaled_width = int($video_width * $scale_factor);
    282         my $scaled_height = int($video_height * $scale_factor);
    283 
    284         # round to be ensure multiple of 2 (needed by some codecs)
    285         $scaled_width  = int($scaled_width/2)*2;
    286         $scaled_height = int($scaled_height/2)*2;
    287 
    288         $s_opt = "-s ${scaled_width}x${scaled_height}";
    289     }
    290     # else, video is smaller than requested size, don't scale up
    291    
    292     }
    293    
    294     return $s_opt;
    295 }
    296 
    297 
    298 sub keyframe_cmd
    299 {
    300     my $self = shift (@_);
    301     my ($ivideo_filename) = @_;
    302 
    303     my $video_ext_dir = &util::filename_cat($ENV{'GSDLHOME'},"ext","video");
    304 
    305     my $output_dir = $self->{'cached_dir'};
    306     my $ivideo_root = $self->{'file_root'};
    307 
    308     my $oshot_filename = &util::filename_cat($output_dir,"shots.xml");
    309 
    310     my $exp_duration = $self->{'exp_duration'};
    311     my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
    312 
    313     my $main_opts = "-y $t_opt";
    314 
    315     my $hive = &util::filename_cat($video_ext_dir,"lib","vhook","hive.so");
    316 
    317     my $oflash_filename = &util::filename_cat($output_dir,"$ivideo_root\_keyframe.flv");
    318 
    319     my $vhook_opts = "$hive  -o $oshot_filename -k $output_dir $ivideo_filename";
    320 
    321     my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
    322     my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
    323 
    324     my $ffmpeg_cmd = "ffkeyframe  $main_opts -vhook \"$vhook_opts\"   -i \"$ivideo_filename_gsdlenv\" -an -y \"$oflash_filename_gsdlenv\"";
    325 
    326 
    327     return ($ffmpeg_cmd,$oflash_filename);
    328 }
    329 
    330 
    331 sub stream_cmd
    332 {
    333     my $self = shift (@_);
    334     my ($ivideo_filename,$video_width,$video_height,
    335     $streaming_quality,
    336     $streaming_bitrate,$streaming_size,
    337     $opt_streaming_achan, $opt_streaming_arate) = @_;
    338 
    339     my $streaming_achan
    340     = (defined $opt_streaming_achan) ? $opt_streaming_achan : 2;
    341 
    342     my $streaming_arate
    343     = (defined $opt_streaming_arate) ? $opt_streaming_arate : 22050;
    344 
    345     my $output_dir = $self->{'cached_dir'};
    346     my $ivideo_root = $self->{'file_root'};
    347 
    348     my $oflash_file = "${ivideo_root}_stream.flv";
    349     my $oflash_filename = &util::filename_cat($output_dir,$oflash_file);
    350 
    351     my $s_opt = $self->optional_frame_scale($streaming_size,$video_width,$video_height);
    352 
    353     my $exp_duration = $self->{'exp_duration'};
    354     my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
    355 
    356     my $main_opts = "-y $t_opt";
    357 
    358     my $bitrate_opt = "-b $streaming_bitrate";
    359     ### my $stream_opts = "-r 25 $s_opt";
    360     my $stream_opts .= " $s_opt -ac $streaming_achan -ar $streaming_arate";
    361 
    362     # -flags +ilme+ildct' and maybe '-flags +alt' for interlaced material, and try '-top 0/1'
    363 
    364     my $all_opts = "$main_opts $stream_opts";
    365 
    366     my $ffmpeg_cmd;
    367 
    368     my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
    369     my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
    370 
    371     if ($streaming_quality eq "high") {
    372 
    373     my $pass_log_file = &util::filename_cat($output_dir,"$ivideo_root-logpass.txt");
    374     if (-e $pass_log_file) {
    375         &util::rm($pass_log_file);
    376     }
    377 
    378     my $pass_log_file_gsdlenv = $self->gsdlhome_independent($pass_log_file);
    379 
    380     $all_opts .= " -passlogfile \"$pass_log_file_gsdlenv\"";
    381 
    382     my $ffmpeg_cmd_pass1 = "ffmpeg -pass 1 -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
    383 
    384     my $ffmpeg_cmd_pass2 = "ffmpeg -pass 2 -i \"$ivideo_filename_gsdlenv\" $all_opts $bitrate_opt -y \"$oflash_filename_gsdlenv\"";
    385     $ffmpeg_cmd = "( $ffmpeg_cmd_pass1 ; $ffmpeg_cmd_pass2 )";
    386     }
    387     else {
    388     # single pass
    389 
    390     $ffmpeg_cmd = "ffmpeg -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
    391     }
    392 
    393     return ($ffmpeg_cmd,$oflash_filename,$oflash_file);
    394 }
    395 
    396 
    397 
    398 sub audio_excerpt_cmd
    399 {
    400     my $self = shift (@_);
    401     my ($ivoa_filename,$hh,$mm,$ss,$opt_excerpt_len) = @_;
    402 
    403     # ivoa = input video or audio
    404 
    405     my $time_encoded = "$hh:$mm:$ss";
    406     my $time_encoded_file = "$hh$mm$ss";
    407    
    408    
    409     my $output_dir = $self->{'cached_dir'};
    410     my $ivoa_root = $self->{'file_root'};
    411 
    412     my $omp3_file = "${ivoa_root}_$time_encoded_file.mp3";
    413     my $omp3_filename = &util::filename_cat($output_dir,$omp3_file);
    414 
    415     my $all_opts = "-y -acodec mp3 -ss $time_encoded ";
    416 
    417     if (defined $opt_excerpt_len) {
    418     $all_opts .= "-t $opt_excerpt_len ";
    419     }
    420 
    421 
    422     my $ivoa_filename_gsdlenv = $self->gsdlhome_independent($ivoa_filename);
    423     my $omp3_filename_gsdlenv = $self->gsdlhome_independent($omp3_filename);
    424 
    425 
    426     my $ffmpeg_cmd = "ffmpeg -i \"$ivoa_filename_gsdlenv\" $all_opts  \"$omp3_filename_gsdlenv\"";
    427 
    428     return ($ffmpeg_cmd,$omp3_filename,$omp3_file);
    429 }
    430 
    431 
    432 
    433 sub streamseekable_cmd
    434 {
    435     my $self = shift (@_);
    436     my ($oflash_filename) = @_;
    437 
    438     my $output_dir = $self->{'cached_dir'};
    439     my $ivideo_root = $self->{'file_root'};
    440 
    441     my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
    442 
    443     my $flvtool_cmd = "flvtool2 -vUP \"$oflash_filename\"";
    444 
    445     return ($flvtool_cmd,$oflash_filename);
    446 }
    447 
    448 
    449 sub streamkeyframes_cmd
    450 {
    451     my $self = shift (@_);
    452     my ($oflash_filename,$doc_obj,$section) = @_;
    453 
    454     my $assocfilepath
    455     = $doc_obj->get_metadata_element($section,"assocfilepath");
    456 
    457     my $output_dir = $self->{'cached_dir'};
    458 
    459     my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
    460 
    461     my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
    462     my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
    463 
    464     my $collect = $ENV{'GSDLCOLLECTION'};
    465  
    466     my $flvtool_cmd = "flvtool2 -vAUtP \"$cue_filename\" -thumbLocation:$video_server$video_prefix/collect/$collect/index/assoc/$assocfilepath \"$oflash_filename\"";
    467 
    468 
    469     return ($flvtool_cmd,$oflash_filename);
    470 }
    471 
    472 
    473 sub streamcuepts_cmd
    474 {
    475     my $self = shift (@_);
    476     my ($oflash_filename) = @_;
    477 
    478     my $output_dir = $self->{'cached_dir'};
    479 
    480     my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
    481 
    482     my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
    483     my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
    484 
    485     my $collect = $ENV{'GSDLCOLLECTION'};
    486     my $thumbloc = "$video_server$video_prefix/collect/$collect";
    487 
    488 
    489 #    my $flvtool_cmd = "flvtool2 -vUAtP \"$cue_filename\" -thumbLocation:$thumbloc \"$oflash_filename\"";
    490 
    491 #    my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
    492 
    493 
    494 
    495 #    my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
    496 
    497 
    498 ##    my $flvtool_cmd = "flvtool2 -vAt \"$cue_filename\" -UP \"$oflash_filename\" \"$output_dir/updated.flv\"";
    499 
    500 ##    my $flvtool_cmd = "flvtool2 -vAtU \"$cue_filename\" \"$oflash_filename\" \"$output_dir/updated.flv\"";
    501 
    502     my $flvtool_cmd = "flvtool2 -vAtUP \"$cue_filename\" \"$oflash_filename\"";
    503 
    504     return ($flvtool_cmd,$oflash_filename);
    505 }
    506 
    507 
    508 sub keyframe_thumbnail_cmd
    509 {
    510     my $self = shift (@_);
    511     my ($ivideo_filename,$thumbnailfile,$thumbnailwidth,$thumbnailheight) = @_;
    512 
    513     my $output_dir = $self->{'cached_dir'};
    514     my $ivideo_root = $self->{'file_root'};
    515 
    516     my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
    517 
    518 
    519     # Try for 4th keyframe, but fall back to 1st if doesn't exist
    520     my $key_filename = "${key_filename_prefix}_0003.jpg";
    521     $key_filename = "${key_filename_prefix}_0000.jpg" if (!-e $key_filename);
    522 
    523     my $key_filename_gsdlenv = $self->gsdlhome_independent($key_filename);
    524     my $thumbnailfile_gsdlenv = $self->gsdlhome_independent($thumbnailfile);
    525 
    526     my $command;
    527 
    528     if (-e $key_filename) {
    529     $command = "convert -interlace plane -verbose -geometry $thumbnailwidth"
    530         . "x$thumbnailheight \"$key_filename_gsdlenv\" \"$thumbnailfile_gsdlenv\"";
    531     }
    532     else {
    533     # extractkeyframe has either not been switched on, or else had
    534     # a problem when running
    535     # => extract a from
    536     # my $frame_rate = 1.0 / 60.0;
    537    
    538     my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
    539 
    540 
    541 
    542     $command = "ffmpeg -i \"$ivideo_filename_gsdlenv\"  -ss 12.5 -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -y \"$thumbnailfile_gsdlenv\"";
    543 
    544     # fmpeg -i input.dv -r 1 -f image2 -s 120x96 images%05d.png
    545     }
    546 
    547     return ($command,$thumbnailfile);
    548 }
    549 
    550 
    551 sub keyframe_montage_cmd
    552 {
    553     my $self = shift (@_);
    554     my ($ivideo_filename,$montagefile) = @_;
    555 
    556     my $output_dir = $self->{'cached_dir'};
    557     my $ivideo_root = $self->{'file_root'};
    558 
    559     my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
    560 
    561     my $options = "-tile 10  -geometry 75x62+2+2";
    562 
    563     my $command = "montage $options ${key_filename_prefix}_*.jpg \"$montagefile\"";
    564 
    565     return ($command,$montagefile);
    566 }
    567 
    568 
    569 
    570 sub parse_shot_xml
    571 {
    572     my ($self) = shift(@_);
    573 
    574     my ($plugin) = @_;
    575 
    576     my $outhandle = $self->{'outhandle'};
    577     my $output_dir = $self->{'cached_dir'};
    578 
    579     my $shots_filename = &util::filename_cat($output_dir,"shots.xml");
    580 
    581     eval {
    582     $plugin->{'parser'}->parsefile($shots_filename);
    583     };
    584    
    585     if ($@) {
    586     print $outhandle "videoconvert.pm: skipping $shots_filename as not conformant to Hive shot syntax\n" if ($self->{'verbosity'} > 1);
    587     print $outhandle "\n Perl Error:\n $@\n" if ($self->{'verbosity'}>2);
    588     return 0;
    589     }
    590 
    591 }
    592 
    593 sub associate_keyframes_old
    594 {
    595     my ($self) = shift(@_);
    596 
    597     my ($doc_obj,$section,$plugin) = @_;
    598 
    599     my $output_dir = $self->{'cached_dir'};
    600 
    601     my $count = 1;
    602     foreach my $kframe_file (@{$plugin->{'keyframe_fnames'}}) {
    603 
    604     my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
    605     $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
    606                  $section);
    607     $count++;
    608     }
    609 
    610     $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$plugin->{'keyframe_fnames'}}));
    611 
    612 
    613     # *****
    614     # $doc_obj->add_metadata ($section, "thumblist", $plugin->{'flowplayer_thumblist'});
    615 
    616 }
    617 
    618 sub associate_keyframes
    619 {
    620     my ($self) = shift(@_);
    621 
    622     my ($doc_obj,$section,$plugin) = @_;
    623 
    624     my $output_dir = $self->{'cached_dir'};
    625     my $timeline = $plugin->{'keyframe_timeline'};
    626    
    627     my $count = 1;
    628 
    629     foreach my $t (sort { $timeline->{$a}->{'keyframeindex'} <=> $timeline->{$b}->{'keyframeindex'} } keys %$timeline)
    630     {
    631     my $kframe_file = $timeline->{$t}->{'thumb'};
    632     my $timestamp = $timeline->{$t}->{'timestamp'};
    633 
    634     my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
    635     $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
    636                  $section);
    637     $doc_obj->add_utf8_metadata($section,"KeyframeTimestamp",$timestamp);
    638 
    639     $count++;
    640     }
    641 
    642     $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$plugin->{'keyframe_fnames'}}));
    643 
    644 
    645     # *****
    646     # $doc_obj->add_metadata ($section, "thumblist", $plugin->{'flowplayer_thumblist'});
    647 }
    648 
    649 
    650 
    651233sub ffmpeg_monitor_init
    652234{
     
    693275
    694276
    695 sub flvtool2_monitor_line
    696 {
    697     my ($line) = @_;
    698 
    699     my $had_error = 0;
    700     my $generate_dot = 1;
    701 
    702     if ($line =~ m/\s+\- /) {
    703     # ignore tabulated output printed at end of command
    704     $generate_dot = 0;
    705     }
    706    
    707     if ($line =~ m/^Error:/i) {
    708     $had_error = 1;
    709     }
    710 
    711     return ($had_error,$generate_dot);
    712 }
    713 
    714 
    715 
    716277
    717278
  • extensions/gsdl-video/trunk/perllib/plugins/VideoPlugin.pm

    r18490 r18556  
    11######################################################################
    22#
    3 # VideoPlugin.pm -- plugin for processing video largely based on ImagePlug
     3# VideoPlugin.pm -- plugin for processing video files
    44# A component of the Greenstone digital library software
    55# from the New Zealand Digital Library Project at the
     
    2424###########################################################################
    2525
     26# -- Largely modeled on how ImagePlugin works
     27# -- Can convert to audio as well as video
     28
    2629package VideoPlugin;
    2730
     
    3033no strict 'subs';
    3134
    32 use videoconvert;
    3335use XMLParser;
    3436use gsprintf;
    3537
    36 use BasePlugin;
     38use MultimediaPlugin;
     39use VideoConverter;
    3740
    3841sub BEGIN {
    39     @VideoPlugin::ISA = ('BasePlugin');
    40 
    41     if (!defined $ENV{'GEXTVIDEO'}) {
    42     print STDERR "Warning: Greenstone Video extension not detected.\n";
    43     }
    44 
    45 }
    46 
    47 
    48 # Customized from BasePlugin. Make 'incremental' the default
    49 # to avoid Greenstone hashing on the file (which in the case of video
    50 # is HUGE) to generate OID. Also supress 'hash' as option so the user
    51 # can't choose it.
    52 
    53 our $oidtype_list =
    54     [ { 'name' => "auto",
    55     'desc' => "{BasePlugin.OIDtype.auto}" },
    56       { 'name' => "assigned",
    57         'desc' => "{import.OIDtype.assigned}" },
    58       { 'name' => "incremental",
    59         'desc' => "{import.OIDtype.incremental}" },
    60       { 'name' => "dirname",
    61         'desc' => "{import.OIDtype.dirname}" } ];
     42    @VideoPlugin::ISA = ('MultimediaPlugin', 'VideoConverter');
     43}
    6244
    6345
     
    6749    'type' => "regexp",
    6850    'deft' => &get_default_process_exp(),
    69     'reqd' => "no" },
    70       { 'name' => "OIDtype",
    71     'desc' => "{import.OIDtype}",
    72     'type' => "enum",
    73     'list' => $oidtype_list,
    74     'deft' => "incremental",
    75     'reqd' => "no",
    76     'modegli' => "2" },
    77 
    78       { 'name' => "noscaleup",
    79     'desc' => "{VideoPlug.noscaleup}",
    80     'type' => "flag",
    81     'reqd' => "no" },
    82       { 'name' => "use_ascii_only_filenames",
    83     'desc' => "{VideoPlug.use_ascii_only_filenames}",
    84     'type' => "flag",
    85     'reqd' => "no" },
    86       { 'name' => "video_excerpt_duration",
    87     'desc' => "{VideoPlug.video_excerpt_duration}",
    88     'type' => "string",
    89     'deft' => "",
    90     'reqd' => "no" },
    91       { 'name' => "extractthumbnail",
    92     'desc' => "{VideoPlug.extractthumbnail}",
    93     'type' => "flag",
    94     'deft' => "0",
    95     'reqd' => "no" },
    96       { 'name' => "thumbnailsize",
    97     'desc' => "{VideoPlug.thumbnailsize}",
    98     'type' => "int",
    99     'deft' => "100",
    100     'range' => "1,",
    101     'reqd' => "no" },
    102       { 'name' => "thumbnailtype",
    103     'desc' => "{VideoPlug.thumbnailtype}",
    104     'type' => "string",
    105     'deft' => "jpeg",
    106     'reqd' => "no" },
    107       { 'name' => "extractscreenview",
    108     'desc' => "{VideoPlug.extractscreenview}",
    109     'type' => "flag",
    110     'deft' => "0",
    111     'reqd' => "no" },
    112       { 'name' => "screenviewsize",
    113     'desc' => "{VideoPlug.screenviewsize}",
    114     'type' => "int",
    115     'deft' => "0",
    116     'range' => "1,",
    117     'reqd' => "no" },
    118       { 'name' => "screenviewtype",
    119     'desc' => "{VideoPlug.screenviewtype}",
    120     'type' => "string",
    121     'deft' => "jpg",
    122     'reqd' => "no" },
    123       { 'name' => "converttotype",
    124     'desc' => "{VideoPlug.converttotype}",
    125     'type' => "string",
    126     'deft' => "",
    127     'reqd' => "no" },
    128       { 'name' => "converttosize",
    129     'desc' => "{VideoPlug.converttosize}",
    130     'type' => "int",
    131     'deft' => "",
    132 ##  'deft' => "352",
    133     'reqd' => "no" },
    134       { 'name' => "converttobitrate",
    135     'desc' => "{VideoPlug.converttobitrate}",
    136     'type' => "string",
    137     'deft' => "200k",
    138     'reqd' => "no" },
    139       { 'name' => "extractkeyframes",
    140     'desc' => "{VideoPlug.extractkeyframes}",
    141     'type' => "flag",
    142     'deft' => "0",
    143     'reqd' => "no" },
    144       { 'name' => "enablestreaming",
    145     'desc' => "{VideoPlug.enablestreaming}",
    146     'type' => "flag",
    147     'deft' => "1",
    148     'reqd' => "no" },
    149       { 'name' => "streamingsize",
    150     'desc' => "{VideoPlug.streamingsize}",
    151     'type' => "int",
    152     'deft' => "352",
    153     'reqd' => "no" },
    154       { 'name' => "streamingbitrate",
    155     'desc' => "{VideoPlug.streamingbitrate}",
    156     'type' => "string",
    157     'deft' => "200k",
    158     'reqd' => "no" },
    159       { 'name' => "minimumsize",
    160     'desc' => "{VideoPlug.minimumsize}",
    161     'type' => "int",
    162     'deft' => "100",
    163     'range' => "1,",
    16451    'reqd' => "no" } ];
    16552
     53
    16654my $options = { 'name'     => "VideoPlugin",
    167         'desc'     => "{VideoPlug.desc}",
     55        'desc'     => "{VideoPlugin.desc}",
    16856        'abstract' => "no",
    16957        'inherits' => "yes",
    17058        'args'     => $arguments };
    171 
    172 
    173 my ($self);
    17459
    17560sub new {
     
    18166    push(@{$hashArgOptLists->{"OptList"}},$options);
    18267
    183     $self = new BasePlugin($pluginlist, $inputargs, $hashArgOptLists);
    184 
    185     # Check that ffmpeg is installed and available on the path (except for Windows 95/98)
    186     # This test is "inherited" from ImagePlugin where ImageMagick support
    187     # for building cannot be used on these two versions of Windows as they
    188     # do not have enough flexablity in the use of stdout and stderr to
    189     # support how our code works.  It seems reasonable to assume the
    190     # same is true for VideoPlugin work using ffmpeg.
    191 
    192     if (($ENV{'GSDLOS'} ne "windows" || Win32::IsWinNT())) {
    193 
    194     my $result = `ffmpeg -h 2>&1`;
    195 
    196 
    197     if (!defined $result || $result !~ m/^FFmpeg version/) {
    198         $self->{'ffmpeg_installed'} = 0;
    199         print STDERR $result;
    200     }
    201     else {
    202         $self->{'ffmpeg_installed'} = 1;
    203     }
    204 
    205     }
    206 
    207 
    208     # create XML::Parser object for parsing metadata.xml files
    209     my $parser;
    210     if ($]<5.008) {
    211     # Perl 5.6
    212     $parser = new XML::Parser('Style' => 'Stream',
    213                   'Handlers' => {'Char' => \&Char,
    214                          'Doctype' => \&Doctype
    215                          });
    216     }
    217     else {
    218     # Perl 5.8
    219     $parser = new XML::Parser('Style' => 'Stream',
    220                   'ProtocolEncoding' => 'ISO-8859-1',
    221                   'Handlers' => {'Char' => \&Char,
    222                          'Doctype' => \&Doctype
    223                          });
    224     }
     68    new VideoConverter($pluginlist, $inputargs, $hashArgOptLists);
     69    my $self = new MultimediaPlugin($pluginlist, $inputargs, $hashArgOptLists);
     70
     71    if ($self->{'info_only'}) {
     72    # don't worry about creating the XML parser as all we want is the
     73    # list of plugin options
     74    return bless $self, $class;
     75    }
     76
     77
     78    # create XML::Parser object for parsing keyframe files (produced by hive)
     79    my $parser = new XML::Parser('Style' => 'Stream',
     80                                 'Pkg' => 'VideoPlugin',
     81                                 'PluginObj' => $self,
     82                 'Namespaces' => 1, # strip out namespaces
     83                 'Handlers' => {'Char' => \&Char,
     84                        'XMLDecl' => \&XMLDecl,
     85                        'Entity'  => \&Entity,
     86                        'Doctype' => \&Doctype,
     87                        'Default' => \&Default
     88                                 });
    22589
    22690    $self->{'parser'} = $parser;
     
    22892
    22993    return bless $self, $class;
     94}
     95
     96
     97
     98sub begin {
     99    my $self = shift (@_);
     100    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
     101
     102    $self->SUPER::begin(@_);
     103    $self->VideoConverter::begin(@_);
    230104}
    231105
     
    236110
    237111    $self->SUPER::init(@_);
    238     ## $self->ImageConverter::init(); # ****** VideoConverter::init ??
     112    $self->VideoConverter::init(@_);
    239113}
    240114
     
    246120}
    247121
    248 # this makes no sense for image
    249 sub block_cover_image
     122
     123sub extract_keyframes
    250124{
    251     my $self =shift (@_);
    252     my ($filename) = @_;
    253 
    254     return;
    255 }
    256 
    257 
     125    my $self = shift (@_);
     126    my ($doc_obj,$originalfilename,$filename) = @_;
     127
     128    my $section = $doc_obj->get_top_section();
     129
     130    my $output_dir   = $self->{'cached_dir'};
     131    my $ivideo_root  = $self->{'cached_file_root'};
     132
     133    # Generate the keyframes with ffmpeg and hive
     134    my ($keyframe_cmd,$okeyframe_filename) = $self->keyframe_cmd($originalfilename || $filename);
     135   
     136    my $keyframe_options = { @{$self->{'ffmpeg_monitor'}},
     137                 'message_prefix' => "Keyframe",
     138                 'message' => "Extracting keyframes" };
     139   
     140    $self->autorun_cached_general_cmd($keyframe_cmd,$okeyframe_filename,$keyframe_options);
     141    $self->parse_shot_xml();
     142    $self->associate_keyframes($doc_obj,$section);
     143}
     144
     145
     146sub enable_streaming
     147{
     148    my $self = shift (@_);
     149    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
     150    $video_width,$video_height) = @_;
     151
     152    my $section = $doc_obj->get_top_section();
     153
     154    my $output_dir   = $self->{'cached_dir'};
     155    my $ivideo_root  = $self->{'cached_file_root'};
     156   
     157    # Generate the Flash FLV format for streaming purposes
     158    my $streamable_regenerated = 0;
     159
     160    my $optionally_run_general_cmd = "run_uncached_general_cmd";
     161    if ($self->{'enable_cache'}) {
     162    $optionally_run_general_cmd
     163        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
     164    }
     165
     166    my $streaming_bitrate = $self->{'streamingbitrate'};
     167    my $streaming_size    = $self->{'streamingsize'};
     168   
     169    my $streaming_quality = "high";
     170   
     171    my ($stream_cmd,$oflash_filename,$oflash_file)
     172    = $self->stream_cmd($originalfilename || $filename,
     173                $video_width,$video_height,
     174                $streaming_quality,
     175                $streaming_bitrate, $streaming_size);
     176   
     177   
     178    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
     179                   'message_prefix' => "Stream",
     180                   'message' => "Generating streamable video: $oflash_file" };
     181   
     182    my $streamable_result;
     183    my $streamable_had_error;
     184    ($streamable_regenerated,$streamable_result,$streamable_had_error)
     185    = $self->$optionally_run_general_cmd($stream_cmd,$oflash_filename,$streamable_options);
     186   
     187    if (!$streamable_had_error) {
     188    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($oflash_filename);
     189   
     190    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
     191                       'message_prefix' => "Stream Seekable",
     192                       'message' => "Reprocessing video stream to be seekable by timeline: $oflash_file" };
     193   
     194    if ($streamable_regenerated) {
     195        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
     196    }
     197   
     198    my $streamable_url = $oflash_file;
     199    ## $streamable_url =~ s/ /%20/g;
     200    my $streamable_url_safe = $self->url_safe($streamable_url);
     201   
     202    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
     203    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/flash",
     204                 $section);
     205    }
     206
     207##    my $video_width = $doc_obj->get_metadata_element($section,"VideoWidth");
     208##    my $video_height = $doc_obj->get_metadata_element($section,"VideoHeight");
     209   
     210    #
     211    # FlowPlayer.swf       height+22 pixels
     212    # FlowPlayerBlack.swf  height+16 pixels
     213    # FlowPlayerThermo.swf height+16 pixels
     214    # FlowPlayerWhite.swf  height+26 pixels
     215    my $flashwidth = $video_width;
     216    my $flashheight = $video_height + 22;
     217    if ($self->{'extractkeyframes'}) {
     218    $flashheight += 100;
     219    }
     220    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
     221    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
     222   
     223    my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
     224    my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
     225    my $base_url = "$video_server$video_prefix/collect/[collection]/index/assoc/[assocfilepath]/";
     226    my $base_url_safe = $self->url_safe($base_url);
     227    $doc_obj->add_utf8_metadata ($section, "baseurl",$base_url_safe);
     228   
     229    $self->{'oflash_file'} = $oflash_file;
     230    $self->{'oflash_filename'} = $oflash_filename;
     231
     232    return $streamable_regenerated;
     233}
     234
     235sub extract_thumbnail
     236{
     237    my $self = shift (@_);
     238    my ($doc_obj,$filename,$convertto_regenerated,$thumbnailtype,
     239    $thumbnail_width, $thumbnail_height) = @_;
     240
     241    my $section = $doc_obj->get_top_section();
     242
     243    my $output_dir   = $self->{'cached_dir'};
     244    my $ivideo_root  = $self->{'cached_file_root'};
     245
     246    my $verbosity = $self->{'verbosity'};
     247    my $outhandle = $self->{'outhandle'};
     248
     249
     250    # Generate the thumbnail with convert, a la ImagePlug
     251
     252    my $thumbnailfile = &util::filename_cat($output_dir,"$ivideo_root.$thumbnailtype");
     253   
     254   
     255    my $optionally_run_general_cmd = "run_uncached_general_cmd";
     256    if ($self->{'enable_cache'}) { 
     257    $optionally_run_general_cmd
     258    = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
     259    }
     260   
     261    my ($thumb_cmd ,$othumb_filename)
     262    = $self->keyframe_thumbnail_cmd($filename,$thumbnailfile,$thumbnail_width,$thumbnail_height);
     263   
     264    my $thumb_options = { 'verbosity' => $verbosity,
     265              'outhandle' => $outhandle,
     266              'message_prefix' => "Thumbnail",
     267              'message' => "Generating thumbnail" };
     268   
     269    my ($thumb_regenerated,$thumb_result,$thumb_had_error)
     270    = $self->$optionally_run_general_cmd($thumb_cmd,$thumbnailfile,$thumb_options);
     271   
     272    # Add the thumbnail as an associated file ...
     273    if (-e "$thumbnailfile") {
     274    $doc_obj->associate_file("$thumbnailfile", "thumbnail.$thumbnailtype",
     275                 "image/$thumbnailtype",$section);
     276    $doc_obj->add_metadata ($section, "ThumbType", $thumbnailtype);
     277    $doc_obj->add_metadata ($section, "Thumb", "thumbnail.$thumbnailtype");
     278   
     279    $doc_obj->add_utf8_metadata ($section, "thumbicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Thumb]\" width=[ThumbWidth] height=[ThumbHeight]>");
     280###     $doc_obj->add_utf8_metadata ($section, "thumbicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Thumb]\">");
     281    }
     282   
     283    # Extract Thumnail metadata from convert output
     284    if ($thumb_result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
     285    $doc_obj->add_metadata ($section, "ThumbWidth", $1);
     286    $doc_obj->add_metadata ($section, "ThumbHeight", $2);
     287    }
     288    else {
     289    # Two reasons for getting to here:
     290    #   1.thumbnail was generated by ffmpeg, not imagemagick convert
     291    #   2.thumbnail was cached, so imagemagick convert was not run
     292    # Either way, the solution is the same:
     293    # => run "identify $thumbnailfile" and parse result
     294   
     295    $thumb_result = `identify \"$thumbnailfile\"`;
     296   
     297    if ($thumb_result =~ m/([0-9]+)x([0-9]+)/) {
     298        $doc_obj->add_metadata ($section, "ThumbWidth", $1);
     299        $doc_obj->add_metadata ($section, "ThumbHeight", $2);
     300    }
     301    }
     302}
     303
     304
     305sub extract_keyframes_montage
     306{
     307    my $self = shift (@_);
     308    my ($doc_obj,$filename,$thumbnailtype) = @_;
     309
     310    my $section = $doc_obj->get_top_section();
     311
     312    my $output_dir   = $self->{'cached_dir'};
     313    my $ivideo_root  = $self->{'cached_file_root'};
     314
     315   
     316    # Generate the mosaic with 'montage'
     317    my $montagefile = &util::filename_cat($output_dir,"$ivideo_root\_montage.$thumbnailtype");
     318   
     319    my ($montage_cmd,$omontage_filename)
     320    = $self->keyframe_montage_cmd($filename,$montagefile);
     321   
     322    my $montage_options = { 'message_prefix' => "Montage",
     323                'message' => "Generating montage" };
     324   
     325    my ($montage_result,$montage_had_error)
     326    = $self->run_general_cmd($montage_cmd,$montage_options);
     327   
     328    # Add the montage as an associated file ...
     329    if (-e "$montagefile") {
     330    $doc_obj->associate_file("$montagefile", "montage.$thumbnailtype",
     331                 "image/$thumbnailtype",$section);
     332    $doc_obj->add_metadata ($section, "MontageType", $thumbnailtype);
     333    $doc_obj->add_metadata ($section, "Montage", "montage.$thumbnailtype");
     334   
     335    $doc_obj->add_utf8_metadata ($section, "montageicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Montage]\" >");
     336    }
     337}
     338
     339
     340
     341sub extract_screenview
     342{
     343    my $self = shift (@_);
     344    my ($doc_obj,$filename,$screenviewtype, $screenview_width,$screenview_height) = @_;
     345
     346    my $section = $doc_obj->get_top_section();
     347
     348    my $output_dir   = $self->{'cached_dir'};
     349    my $ivideo_root  = $self->{'cached_file_root'};
     350   
     351   
     352    # make the screenview image
     353
     354    my $screenviewfilename = &util::filename_cat($output_dir,"$ivideo_root.$screenviewtype");
     355
     356   
     357    my ($screenview_cmd,$oscreenview_filename)
     358    = $self->keyframe_thumbnail_cmd($filename,$screenviewfilename,$screenview_width,$screenview_height);
     359
     360    my $screenview_options = { 'message_prefix' => "Screenview",
     361                   'message' => "Generating screenview image" };
     362
     363    my ($result,$had_error)
     364    = $self->run_general_cmd($screenview_cmd,$screenview_options);
     365
     366    # get screenview dimensions, size and type
     367    if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
     368    $doc_obj->add_metadata ($section, "ScreenWidth", $1);
     369    $doc_obj->add_metadata ($section, "ScreenHeight", $2);
     370    }
     371    else {
     372    $doc_obj->add_metadata ($section, "ScreenWidth", $screenview_width);
     373    $doc_obj->add_metadata ($section, "ScreenHeight", $screenview_height);
     374    }
     375   
     376    #add the screenview as an associated file ...
     377    if (-e "$screenviewfilename") {
     378    $doc_obj->associate_file("$screenviewfilename", "screenview.$screenviewtype",
     379                 "image/$screenviewtype",$section);
     380    $doc_obj->add_metadata ($section, "ScreenType", $screenviewtype);
     381    $doc_obj->add_metadata ($section, "Screen", "screenview.$screenviewtype");
     382   
     383    $doc_obj->add_utf8_metadata ($section, "screenicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Screen]\" width=[ScreenWidth] height=[ScreenHeight]>");
     384    } else {
     385    my $outhandle = $self->{'outhandle'};
     386    print $outhandle "VideoPlugin: couldn't find \"$screenviewfilename\"\n";
     387    }
     388}
    258389
    259390
     
    284415    my ($video_type, $video_width, $video_height, $video_duration, $video_size,
    285416    $vcodec,$vfps,$atype,$afreq,$achan,$arate)
    286     = &videoconvert::identify($filename, $outhandle, $verbosity);
     417    = &VideoConverter::identify($filename, $outhandle, $verbosity);
    287418
    288419    if ($vfps eq "unknown") {
     
    305436    my $exp_duration = undef;
    306437   
    307     my $video_excerpt_duration = $self->{'video_excerpt_duration'};
    308 
    309     if ((defined $video_excerpt_duration) && ($video_excerpt_duration ne "")) {
    310     $exp_duration = $video_excerpt_duration;
     438    my $excerpt_duration = $self->{'excerpt_duration'};
     439
     440    if ((defined $excerpt_duration) && ($excerpt_duration ne "")) {
     441    $exp_duration = $excerpt_duration;
    311442    my ($hh,$mm,$ss,$ms) = ($exp_duration =~ m/^(\d\d):(\d\d):(\d\d)\.?(\d\d)?/);
    312443    my $excerpt_dur_in_secs = $hh * 3600 + $mm * 60 + $ss;
     
    330461
    331462    my $ascii_only_filenames = $self->{'use_ascii_only_filenames'};
    332     my $videoconvert
    333     = new videoconvert($base_dir,$filename,$verbosity,$outhandle,$exp_duration,$ascii_only_filenames);
    334     $self->{'videoconvert'} = $videoconvert;
     463    $self->init_cache_for_file($filename);
    335464
    336465    my $originalfilename = undef;
    337466    my $type = "unknown";
    338467
    339     my $output_dir = $videoconvert->{'cached_dir'};
    340     my $ivideo_root = $videoconvert->{'file_root'};
     468    my $output_dir = $self->{'cached_dir'};
     469    my $ivideo_root = $self->{'cached_file_root'};
    341470
    342471    my $convertto_regenerated = 0;
     
    355484    $filename = &util::filename_cat($output_dir,$file);
    356485 
    357     my $s_opt = $videoconvert->optional_frame_scale($converttosize,$video_width,$video_height);
     486    my $s_opt = $self->optional_frame_scale($converttosize,$video_width,$video_height);
    358487    my $exp_duration = $self->{'exp_duration'};
    359488    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
     
    373502    my $convertto_error;
    374503   
    375     my $convertto_options = { @{$videoconvert->{'ffmpeg_monitor'}},
     504    my $convertto_options = { @{$self->{'ffmpeg_monitor'}},
    376505                  'message_prefix' => "Convert to",
    377506                  'message' => "Converting video to $converttotype" };
    378507
    379508    ($convertto_regenerated,$convertto_result,$convertto_error)
    380         = $videoconvert->run_cached_general_cmd($convertto_command,$filename,$convertto_options);
     509        = $self->autorun_cached_general_cmd($convertto_command,$filename,$convertto_options);
    381510                           
    382511    $type = $converttotype;
     
    414543    $file = $file_unicode;
    415544    my $filemeta = $self->filename_to_utf8_metadata($file);
    416     my $filemeta_url_safe = $videoconvert->url_safe($filemeta);
     545    my $filemeta_url_safe = $self->url_safe($filemeta);
    417546
    418547    $doc_obj->add_utf8_metadata ($section, "Video", $filemeta_url_safe);
     
    454583
    455584    if ($self->{'extractkeyframes'}) {
    456     # Generate the keyframes with ffmpeg and hive
    457     my ($keyframe_cmd,$okeyframe_filename) = $videoconvert->keyframe_cmd($originalfilename || $filename);
    458 
    459     my $keyframe_options = { @{$videoconvert->{'ffmpeg_monitor'}},
    460                  'message_prefix' => "Keyframe",
    461                  'message' => "Extracting keyframes" };
    462 
    463     $videoconvert->run_cached_general_cmd($keyframe_cmd,$okeyframe_filename,$keyframe_options);
    464     $videoconvert->parse_shot_xml($self);
    465     $videoconvert->associate_keyframes($doc_obj,$section,$self);
     585    $self->extract_keyframes($doc_obj,$originalfilename,$filename);
    466586    }
    467587
    468588    my $streamable_regenerated = 0;
    469     my $optionally_run_general_cmd
    470     = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
    471 
    472     if ($self->{'enablestreaming'}) {
    473     # Generate the Flash FLV format for streaming purposes
    474 
    475     my $streaming_bitrate = $self->{'streamingbitrate'};
    476     my $streaming_size    = $self->{'streamingsize'};
    477 
    478     my $streaming_quality = "high";
    479 
    480     my ($stream_cmd,$oflash_filename,$oflash_file)
    481         = $videoconvert->stream_cmd($originalfilename || $filename,
    482                     $video_width,$video_height,
    483                     $streaming_quality,
    484                     $streaming_bitrate, $streaming_size);
    485 
    486 
    487     my $streamable_options = { @{$videoconvert->{'ffmpeg_monitor'}},
    488                    'message_prefix' => "Stream",
    489                    'message' => "Generating streamable video: $oflash_file" };
    490 
    491     my $streamable_result;
    492     my $streamable_had_error;
    493     ($streamable_regenerated,$streamable_result,$streamable_had_error)
    494         = $videoconvert->$optionally_run_general_cmd($stream_cmd,$oflash_filename,$streamable_options);
    495 
    496     if (!$streamable_had_error) {
    497         my ($streamseekable_cmd,$ostreamseekable_filename) = $videoconvert->streamseekable_cmd($oflash_filename);
    498 
    499         my $streamseekable_options = { @{$videoconvert->{'flvtool2_monitor'}},
    500                        'message_prefix' => "Stream Seekable",
    501                        'message' => "Reprocessing video stream to be seekable by timeline: $oflash_file" };
    502 
    503         if ($streamable_regenerated) {
    504         $videoconvert->run_general_cmd($streamseekable_cmd,$streamseekable_options);
    505         }
    506 
    507         my $streamable_url = $oflash_file;
    508         ## $streamable_url =~ s/ /%20/g;
    509         my $streamable_url_safe = $videoconvert->url_safe($streamable_url);
    510 
    511         $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
    512         $doc_obj->associate_file($oflash_filename,$oflash_file,"video/flash",
    513                      $section);
    514     }
    515 
    516     my $video_width = $doc_obj->get_metadata_element($section,"VideoWidth");
    517     my $video_height = $doc_obj->get_metadata_element($section,"VideoHeight");
    518    
    519     #
    520     # FlowPlayer.swf       height+22 pixels
    521     # FlowPlayerBlack.swf  height+16 pixels
    522     # FlowPlayerThermo.swf height+16 pixels
    523     # FlowPlayerWhite.swf  height+26 pixels
    524     my $flashwidth = $video_width;
    525     my $flashheight = $video_height + 22;
    526     if ($self->{'extractkeyframes'}) {
    527         $flashheight += 100;
    528     }
    529     $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
    530     $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
    531    
    532     my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
    533     my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
    534     my $base_url = "$video_server$video_prefix/collect/[collection]/index/assoc/[assocfilepath]/";
    535     my $base_url_safe = $videoconvert->url_safe($base_url);
    536     $doc_obj->add_utf8_metadata ($section, "baseurl",$base_url_safe);
    537    
    538     $self->{'oflash_file'} = $oflash_file;
    539     $self->{'oflash_filename'} = $oflash_filename;
    540     }
    541 
    542 
    543     # Make the thumbnail image
     589
     590    if ($self->{'enable_streaming'}) { 
     591    $streamable_regenerated
     592        = $self->enable_streaming($doc_obj,$originalfilename,$filename,
     593                      $convertto_regenerated,
     594                      $video_width,$video_height);
     595    }
     596
     597
    544598    my $thumbnailsize = $self->{'thumbnailsize'} || 100;
    545599    my $thumbnailtype = $self->{'thumbnailtype'} || 'jpg';
    546600
    547     my $thumbnailwidth;
    548     my $thumbnailheight;
    549 
    550     if ($video_width>$video_height) {
    551     my $scale_ratio = $video_height / $video_width;
    552     $thumbnailwidth = $thumbnailsize;
    553     $thumbnailheight = int($thumbnailsize * $scale_ratio);
    554     }
    555     else {
    556     my $scale_ratio = $video_width / $video_height;
    557     $thumbnailwidth = int($thumbnailsize * $scale_ratio);
    558     $thumbnailheight = $thumbnailsize;
    559     }
    560 
    561 
    562     my $thumbnailfile = &util::filename_cat($output_dir,"$ivideo_root.$thumbnailtype");
    563 
    564 
    565     if ($self->{'extractthumbnail'}) {
    566     # Generate the thumbnail with convert, a la ImagePlug
    567     my ($thumb_cmd ,$othumb_filename)
    568         = $videoconvert->keyframe_thumbnail_cmd($filename,$thumbnailfile,$thumbnailwidth,$thumbnailheight);
    569 
    570     my $thumb_options = { 'verbosity' => $verbosity,
    571                   'outhandle' => $outhandle,
    572                   'message_prefix' => "Thumbnail",
    573                   'message' => "Generating thumbnail" };
    574 
    575     my ($thumb_regenerated,$thumb_result,$thumb_had_error)
    576         = $videoconvert->$optionally_run_general_cmd($thumb_cmd,$thumbnailfile,$thumb_options);
    577 
    578     # Add the thumbnail as an associated file ...
    579     if (-e "$thumbnailfile") {
    580         $doc_obj->associate_file("$thumbnailfile", "thumbnail.$thumbnailtype",
    581                      "image/$thumbnailtype",$section);
    582         $doc_obj->add_metadata ($section, "ThumbType", $thumbnailtype);
    583         $doc_obj->add_metadata ($section, "Thumb", "thumbnail.$thumbnailtype");
    584 
    585         $doc_obj->add_utf8_metadata ($section, "thumbicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Thumb]\" width=[ThumbWidth] height=[ThumbHeight]>");
    586 ###     $doc_obj->add_utf8_metadata ($section, "thumbicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Thumb]\">");
    587     }
    588 
    589     # Extract Thumnail metadata from convert output
    590     if ($thumb_result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
    591         $doc_obj->add_metadata ($section, "ThumbWidth", $1);
    592         $doc_obj->add_metadata ($section, "ThumbHeight", $2);
     601
     602    if ($self->{'create_thumbnail'} eq "true") {
     603
     604    my $thumbnail_width;
     605    my $thumbnail_height;
     606   
     607    if ($video_width>$video_height) {
     608        my $scale_ratio = $video_height / $video_width;
     609        $thumbnail_width = $thumbnailsize;
     610        $thumbnail_height = int($thumbnailsize * $scale_ratio);
    593611    }
    594612    else {
    595         # Two reasons for getting to here:
    596         #   1.thumbnail was generated by ffmpeg, not imagemagick convert
    597         #   2.thumbnail was cached, so imagemagick convert was not run
    598         # Either way, the solution is the same:
    599         # => run "identify $thumbnailfile" and parse result
    600 
    601         $thumb_result = `identify \"$thumbnailfile\"`;
    602        
    603         if ($thumb_result =~ m/([0-9]+)x([0-9]+)/) {
    604         $doc_obj->add_metadata ($section, "ThumbWidth", $1);
    605         $doc_obj->add_metadata ($section, "ThumbHeight", $2);
    606         }
    607     }
     613        my $scale_ratio = $video_width / $video_height;
     614        $thumbnail_width = int($thumbnailsize * $scale_ratio);
     615        $thumbnail_height = $thumbnailsize;
     616    }
     617   
     618
     619    $self->extract_thumbnail($doc_obj,$filename,$convertto_regenerated,
     620                 $thumbnailtype,
     621                 $thumbnail_width,$thumbnail_height);
    608622    }
    609623
    610624
    611625    if ($self->{'extractkeyframes'}) {
    612 
    613     # Generate the mosaic with 'montage'
    614     my $montagefile = &util::filename_cat($output_dir,"$ivideo_root\_montage.$thumbnailtype");
    615 
    616     my ($montage_cmd,$omontage_filename)
    617         = $videoconvert->keyframe_montage_cmd($filename,$montagefile);
    618 
    619     my $montage_options = { 'message_prefix' => "Montage",
    620                 'message' => "Generating montage" };
    621 
    622     my ($montage_result,$montage_had_error)
    623         = $videoconvert->run_general_cmd($montage_cmd,$montage_options);
    624 
    625     # Add the montage as an associated file ...
    626     if (-e "$montagefile") {
    627         $doc_obj->associate_file("$montagefile", "montage.$thumbnailtype",
    628                      "image/$thumbnailtype",$section);
    629         $doc_obj->add_metadata ($section, "MontageType", $thumbnailtype);
    630         $doc_obj->add_metadata ($section, "Montage", "montage.$thumbnailtype");
    631 
    632         $doc_obj->add_utf8_metadata ($section, "montageicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Montage]\" >");
    633     }
    634     }
     626    $self->extract_keyframes_montage($doc_obj,$filename,$thumbnailtype);
     627    }
     628
     629    my $screenviewsize = $self->{'screenviewsize'};
     630    my $screenviewtype = $self->{'screenviewtype'} || 'jpeg';
    635631
    636632    # Make a screen-sized version of the picture if requested
    637     if ($self->{'extractscreenview'}) {
     633    if ($self->{'create_screenview'} eq "true") {
    638634
    639635    # To do: if the actual image smaller than the screenview size,
    640636    # we should use the original !
    641637
    642     my $screenviewsize = $self->{'screenviewsize'};
    643     my $screenviewtype = $self->{'screenviewtype'} || 'jpeg';
    644     my $screenviewfilename = &util::filename_cat($output_dir,"$ivideo_root.$screenviewtype");
    645 
    646     my $screenviewwidth;
    647     my $screenviewheight;
     638    my $screenview_width;
     639    my $screenview_height;
    648640   
    649641    if ($video_width>$video_height) {
    650642        my $scale_ratio = $video_height / $video_width;
    651         $screenviewwidth = $screenviewsize;
    652         $screenviewheight = int($screenviewsize * $scale_ratio);
     643        $screenview_width = $screenviewsize;
     644        $screenview_height = int($screenviewsize * $scale_ratio);
    653645    }
    654646    else {
    655647        my $scale_ratio = $video_width / $video_height;
    656         $screenviewwidth = int($screenviewsize * $scale_ratio);
    657         $screenviewheight = $screenviewsize;
    658     }
    659 
    660 
    661     # make the screenview image
    662 
    663     my ($screenview_cmd,$oscreenview_filename)
    664         = $videoconvert->keyframe_thumbnail_cmd($filename,$screenviewfilename,$screenviewwidth,$screenviewheight);
    665 
    666     my $screenview_options = { 'message_prefix' => "Screenview",
    667                    'message' => "Generating screenview image" };
    668 
    669     my ($result,$had_error)
    670         = $videoconvert->run_general_cmd($screenview_cmd,$screenview_options);
    671 
    672     # get screenview dimensions, size and type
    673         if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
    674         $doc_obj->add_metadata ($section, "ScreenWidth", $1);
    675         $doc_obj->add_metadata ($section, "ScreenHeight", $2);
    676     }
    677     else {
    678         $doc_obj->add_metadata ($section, "ScreenWidth", $video_width);
    679         $doc_obj->add_metadata ($section, "ScreenHeight", $video_height);
    680     }
    681 
    682     #add the screenview as an associated file ...
    683     if (-e "$screenviewfilename") {
    684         $doc_obj->associate_file("$screenviewfilename", "screenview.$screenviewtype",
    685                      "image/$screenviewtype",$section);
    686         $doc_obj->add_metadata ($section, "ScreenType", $screenviewtype);
    687         $doc_obj->add_metadata ($section, "Screen", "screenview.$screenviewtype");
    688 
    689         $doc_obj->add_utf8_metadata ($section, "screenicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[Screen]\" width=[ScreenWidth] height=[ScreenHeight]>");
    690     } else {
    691         print $outhandle "VideoPlugin: couldn't find \"$screenviewfilename\"\n";
    692     }
     648        $screenview_width = int($screenviewsize * $scale_ratio);
     649        $screenview_height = $screenviewsize;
     650    }
     651
     652
     653    $self->extract_screenview($doc_obj,$filename,
     654                  $screenviewtype,
     655                  $screenview_width,$screenview_height);
    693656    }
    694657
     
    703666    my ($pluginfo, $base_dir, $file, $block_hash, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
    704667
    705     my $outhandle = $self->{'outhandle'};
    706 
    707     # should we move this to read? What about secondary plugins?
    708     print STDERR "<Processing n='$file' p='$self->{'plugin_type'}'>\n" if ($gli);
    709     print $outhandle "$self->{'plugin_type'} processing $file\n"
    710         if $self->{'verbosity'} > 1;
    711 
    712     my ($filename_full_path, $filename_no_path) = &util::get_full_filenames($base_dir, $file);
    713 
    714     # create a new document
    715     my $doc_obj = new doc ($filename_full_path, "indexed_doc", $self->{'file_rename_method'});
    716 
    717 
    718     my $top_section = $doc_obj->get_top_section();
    719 
    720     ### <Video Specific> ###
    721     $doc_obj->set_OIDtype ($processor->{'OIDtype'}, $processor->{'OIDmetadata'});   
    722     ### </Video Specific> ###
    723 
    724 
    725     $doc_obj->add_utf8_metadata($top_section, "Plugin", "$self->{'plugin_type'}");
    726     $doc_obj->add_utf8_metadata($top_section, "FileSize", (-s $filename_full_path));
    727  
    728     # sets the UTF8 filename (Source) for display and sets the url ref to URL encoded version
    729     # of the UTF8 filename (SourceFile) for generated files
    730     $self->set_Source_metadata($doc_obj, $filename_no_path);
    731 
    732 
    733     # plugin specific stuff - what args do we need here??
    734     unless (defined ($self->process($pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli))) {
    735     print STDERR "<ProcessingError n='$file'>\n" if ($gli);
    736     return (-1,undef);
    737     }
    738    
    739     # include any metadata passed in from previous plugins
    740     # note that this metadata is associated with the top level section
    741     my $section = $doc_obj->get_top_section();
    742     # can we merge these two methods??
    743     $self->add_associated_files($doc_obj, $filename_full_path);
    744     $self->extra_metadata ($doc_obj, $section, $metadata);
    745     $self->auto_extract_metadata($doc_obj);
    746 
    747     # if we haven't found any Title so far, assign one
    748     # this was shifted to here from inside read()
    749     $self->title_fallback($doc_obj,$section,$filename_no_path);
    750    
    751     $self->add_OID($doc_obj);
    752 
    753 
    754     ### <Video Specific> ###
     668    my ($rv,$doc_obj) = $self->SUPER::read_into_doc_obj(@_);
     669
     670    if ($rv != 1) {
     671    return ($rv,$doc_obj);
     672    }
     673
    755674
    756675    if (($self->{'enablestreaming'}) && ($self->{'extractkeyframes'})) {
     676    my $section = $doc_obj->get_top_section();
    757677    my $oflash_filename = $self->{'oflash_filename'};
    758     my $videoconvert = $self->{'videoconvert'};
    759678    my ($streamkeyframes_cmd,$ostreamkeyframes_filename)
    760         = $videoconvert->streamkeyframes_cmd($oflash_filename,$doc_obj,$section);
     679        = $self->streamkeyframes_cmd($oflash_filename,$doc_obj,$section);
    761680
    762681    my $verbosity = $self->{'verbosity'};
    763682
    764     my $streamkeyframes_options = { @{$videoconvert->{'flvtool2_monitor'}},
     683    my $streamkeyframes_options = { @{$self->{'flvtool2_monitor'}},
    765684                    'message_prefix' => "Stream Keyframes",
    766685                    'message' => "Reprocessing video stream to add keyframes on timeline" };
    767 #### this used to be commented out!!!
    768     $videoconvert->run_general_cmd($streamkeyframes_cmd,$streamkeyframes_options);
    769     }
    770     ### </Video Specific> ###
    771    
    772     return (1,$doc_obj);
    773 }
    774 
    775 sub add_dummy_text {
    776     my $self = shift(@_);
    777     my ($doc_obj, $section) = @_;
    778 
    779     # add NoText metadata so we can hide this dummy text in format statements
    780     $doc_obj->add_metadata($section, "NoText", "1");
    781     $doc_obj->add_text($section, &gsprintf::lookup_string("{BasePlugin.dummy_text}",1));
    782    
    783 }
    784 
    785 
    786 
    787 
    788 # do plugin specific processing of doc_obj
    789 sub process {
    790     my $self = shift (@_);
    791     # options??
    792     my ($pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
    793 
    794     my $outhandle = $self->{'outhandle'};
    795 
    796     my ($filename_full_path, $filename_no_path) = &util::get_full_filenames($base_dir, $file);
    797 
    798 
    799     if ($self->{'ffmpeg_installed'}) {
    800     my $utf8_filename_no_path = $self->filepath_to_utf8($filename_no_path);
    801     my $url_encoded_filename = &util::rename_file($utf8_filename_no_path, $self->{'file_rename_method'});
    802 
    803 
    804     #run convert to get the thumbnail and extract size and type info
    805     my $result = $self->run_convert($base_dir, $filename_full_path,
    806                     $url_encoded_filename, $doc_obj);
    807    
    808     if (!defined $result) {
    809         if ($gli) {
    810         print STDERR "<ProcessingError n='$file'>\n";
    811         }
    812         print $outhandle "VideoPlugin: couldn't process \"$filename_full_path\"\n";
    813         return (-1,undef); # error during processing
    814     }
    815     }
    816     else {
    817     if ($gli) {
    818         &gsprintf(STDERR, "<Warning p='VideoPlugin' r='{VideoConverter.noconversionavailable}: {VideoConverter.".$self->{'no_image_conversion_reason'}."}'>");
    819     }
    820     # all we do is add the original video file as an associated file, and set up srclink etc
    821     my $assoc_file = $doc_obj->get_assocfile_from_sourcefile();
    822     my $section = $doc_obj->get_top_section();
    823 
    824     $doc_obj->associate_file($filename_full_path, $assoc_file, "", $section);
    825 
    826     $doc_obj->add_metadata ($section, "srclink", "<a href=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[SourceFile]\">");
    827     $doc_obj->add_metadata ($section, "/srclink", "</a>");
    828     $doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/[assocfilepath]/[SourceFile]\" width=\"100\">");
    829 
    830     }
    831     #we have no text - adds dummy text and NoText metadata
    832     $self->add_dummy_text($doc_obj, $doc_obj->get_top_section());
    833 
    834     return 1;
    835 
     686
     687    $self->run_general_cmd($streamkeyframes_cmd,$streamkeyframes_options);
     688    }
     689   
     690    return ($rv,$doc_obj);
    836691}
    837692
     
    908763
    909764
    910 
    911 sub Doctype {
     765sub StartDocument {$_[0]->{'PluginObj'}->xml_start_document(@_);}
     766sub XMLDecl {$_[0]->{'PluginObj'}->xml_xmldecl(@_);}
     767sub Entity {$_[0]->{'PluginObj'}->xml_entity(@_);}
     768sub Doctype {$_[0]->{'PluginObj'}->xml_doctype(@_);}
     769sub StartTag {$_[0]->{'PluginObj'}->xml_start_tag(@_);}
     770sub EndTag {$_[0]->{'PluginObj'}->xml_end_tag(@_);}
     771sub Text {$_[0]->{'PluginObj'}->xml_text(@_);}
     772sub PI {$_[0]->{'PluginObj'}->xml_pi(@_);}
     773sub EndDocument {$_[0]->{'PluginObj'}->xml_end_document(@_);}
     774sub Default {$_[0]->{'PluginObj'}->xml_default(@_);}
     775
     776
     777# This Char function overrides the one in XML::Parser::Stream to overcome a
     778# problem where $expat->{Text} is treated as the return value, slowing
     779# things down significantly in some cases.
     780sub Char {
     781    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
     782    $_[0]->{'Text'} .= $_[1];
     783    return undef;
     784}
     785
     786sub xml_start_document {
     787    my $self = shift(@_);
    912788    my ($expat, $name, $sysid, $pubid, $internal) = @_;
    913789
    914     # my $root_tag = $self->{'root_tag'};
     790}
     791
     792# Called for XML declarations
     793sub xml_xmldecl {
     794    my $self = shift(@_);
     795    my ($expat, $version, $encoding, $standalone) = @_;
     796}
     797
     798# Called for XML entities
     799sub xml_entity {
     800  my $self = shift(@_);
     801  my ($expat, $name, $val, $sysid, $pubid, $ndata) = @_;
     802}
     803
     804
     805# Called for DOCTYPE declarations - use die to bail out if this doctype
     806# is not meant for this plugin
     807sub xml_doctype {
     808    my $self = shift(@_);
     809    my ($expat, $name, $sysid, $pubid, $internal) = @_;
     810
     811    # This test used to be done in xml_start_document
     812    # Moved to here as seems more logical
    915813
    916814    if ($name !~ "seg") {   
    917     die "Root tag $name does not match expected <seg>";
    918     }
    919 }
    920 
    921 sub StartTag {
     815    die "VideoPlugin: Root tag $name does not match expected <seg>";
     816    }
     817}
     818
     819
     820sub xml_start_tag {
     821    my $self = shift(@_);
    922822    my ($expat, $element) = @_;
    923823
     
    931831    #$self->{'flowplayer_thumblist'} = "thumbs: \\[";
    932832
    933     my $output_dir = $self->{'videoconvert'}->{'cached_dir'};
     833    my $output_dir = $self->{'cached_dir'};
    934834    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
    935835
     
    945845    my $avg_frame_num = int(($pre_frame_num+$post_frame_num)/2.0)+1;
    946846
    947     my $output_dir = $self->{'videoconvert'}->{'cached_dir'};
    948     my $ivideo_root = $self->{'videoconvert'}->{'file_root'};
     847    my $output_dir = $self->{'cached_dir'};
     848    my $ivideo_root = $self->{'cached_file_root'};
    949849
    950850    my $keyframe_index = $self->{'keyframe_index'};
     
    1016916}
    1017917
    1018 sub EndTag {
     918sub xml_end_tag {
     919    my $self = shift(@_);
    1019920    my ($expat, $element) = @_;
    1020921
     
    1032933
    1033934
    1034 sub Text {
    1035     my $text = $_;
    1036 }
    1037 
    1038 # This Char function overrides the one in XML::Parser::Stream to overcome a
    1039 # problem where $expat->{Text} is treated as the return value, slowing
    1040 # things down significantly in some cases.
    1041 sub Char {
    1042   $_[0]->{'Text'} .= $_[1];
    1043   return undef;
    1044 }
     935
     936
     937
     938# Called just before start or end tags with accumulated non-markup text in
     939# the $_ variable.
     940sub xml_text {
     941    my $self = shift(@_);
     942    my ($expat) = @_;
     943}
     944
     945# Called for processing instructions. The $_ variable will contain a copy
     946# of the pi.
     947sub xml_pi {
     948    my $self = shift(@_);
     949    my ($expat, $target, $data) = @_;
     950}
     951
     952# Called at the end of the XML document.
     953sub xml_end_document {
     954    my $self = shift(@_);
     955    my ($expat) = @_;
     956
     957    $self->close_document();
     958}
     959
     960
     961# Called for any characters not handled by the above functions.
     962sub xml_default {
     963    my $self = shift(@_);
     964    my ($expat, $text) = @_;
     965}
     966
    1045967
    10469681;
Note: See TracChangeset for help on using the changeset viewer.