root/gs2-extensions/video-and-audio/trunk/src/perllib/plugins/VideoConverter.pm @ 24188

Revision 24188, 48.8 KB (checked in by max, 8 years ago)

Use MediaInfo? by default,
can now successfully seek into the video very fast in order to extract a frame,
for now grab a frame at 35% of the video for thumbnail and screenview

Line 
1###########################################################################
2#
3# VideoConverter - helper plugin that does video (and audio) 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
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24#
25###########################################################################
26package VideoConverter;
27
28use MultimediaConverter;
29
30
31use strict;
32no strict 'refs'; # allow filehandles to be variables and viceversa
33
34use gsprintf 'gsprintf';
35
36BEGIN {
37    @VideoConverter::ISA = ('MultimediaConverter');
38}
39
40
41my @thumb_arguments = (       
42      { 'name' => "create_thumbnail",
43    'desc' => "{ImageConverter.create_thumbnail}",
44    'type' => "enum",
45    'list' => [{'name' => "true", 'desc' => "{common.true}"},
46           {'name' => "false", 'desc' => "{common.false}"}],
47    'deft' => "true",
48    'reqd' => "no" },
49          { 'name' => "keep_original_video",
50    'desc' => "Copy the original video file in the collection as an associated file.",
51    'type' => "enum",
52    'list' => [{'name' => "true", 'desc' => "Include the original video file in the collection"},
53           {'name' => "false", 'desc' => "Do not copy the original video file in the collection"}],
54    'deft' => "false",
55    'reqd' => "no" },
56      { 'name' => "thumbnailsize",
57    'desc' => "{ImageConverter.thumbnailsize}",
58    'type' => "int",
59    'deft' => "100",
60    'range' => "1,",
61    'reqd' => "no" },
62      { 'name' => "thumbnailtype",
63    'desc' => "{ImageConverter.thumbnailtype}",
64    'type' => "string",
65    'deft' => "jpg",
66    'reqd' => "no" },
67      { 'name' => "noscaleup",
68    'desc' => "{ImageConverter.noscaleup}",
69    'type' => "flag",
70    'reqd' => "no" } );
71
72
73my @screenview_arguments = (
74      { 'name' => "create_screenview",
75    'desc' => "{ImageConverter.create_screenview}",
76    'type' => "enum",
77    'list' => [{'name' => "true", 'desc' => "{common.true}"},
78           {'name' => "false", 'desc' => "{common.false}"}],
79    'deft' => "true",
80    'reqd' => "no" },
81      { 'name' => "screenviewsize",
82    'desc' => "{ImageConverter.screenviewsize}",
83    'type' => "int",
84    'deft' => "720",
85    'range' => "1,",
86    'reqd' => "no" },
87      { 'name' => "screenviewtype",
88    'desc' => "{ImageConverter.screenviewtype}",
89    'type' => "string",
90    'deft' => "jpg",
91    'reqd' => "no" } );
92
93my $arguments = [
94      @thumb_arguments,
95      @screenview_arguments,
96
97      { 'name' => "converttotype",
98    'desc' => "{ImageConverter.converttotype}",
99    'type' => "string",
100    'deft' => "",
101    'reqd' => "no" },
102
103
104      { 'name' => "converttosize",
105    'desc' => "{VideoPlugin.converttosize}",
106    'type' => "int",
107    'deft' => "",
108##  'deft' => "352",
109    'reqd' => "no" },
110      { 'name' => "converttobitrate",
111    'desc' => "{VideoPlugin.converttobitrate}",
112    'type' => "string",
113    'deft' => "200k",
114    'reqd' => "no" },
115   
116      { 'name' => "create_keyframes",
117    'desc' => "{VideoPlugin.extractkeyframes}",
118    'type' => "enum",
119    'list' => [{'name' => "true", 'desc' => "{common.true}"},
120            {'name' => "false", 'desc' => "{common.false}"}],
121    'deft' => "false",
122    'reqd' => "no" },
123       { 'name' => "keyframes_algorithm",
124    'desc' => "{VideoPlugin.keyframesAlgorithm}",
125    'type' => "enum",
126    'list' => [{'name' => "mtn", 'desc' => "{keyframesAlgorithm.mtn}"},
127        {'name' => "ffkeyframe", 'desc' => "{keyframesAlgorithm.ffkeyframe}"}],
128    'deft' => "mtn",
129    'reqd' => "no" },
130   
131      { 'name' => "ffkeyframe_num_shots",
132    'desc' => "{VideoPlugin.keep_keyframes}",
133    'type' => "string",
134    'deft' => "all",
135    'reqd' => "no" },
136   
137     { 'name' => "mtn_skip_intro",
138    'desc' => "{VideoPlugin.mtnSkipIntro}",
139    'type' => "int",
140    'deft' => "0",
141    'reqd' => "no" },
142     { 'name' => "mtn_skip_end",
143    'desc' => "{VideoPlugin.mtnSkipEnd}",
144    'type' => "int",
145    'deft' => "0",
146    'reqd' => "no" },
147     { 'name' => "mtn_timestep",
148    'desc' => "{VideoPlugin.mtnTimestep}",
149    'type' => "int",
150    'deft' => "120",
151    'reqd' => "no" },
152     { 'name' => "mtn_detect_blanks",
153    'desc' => "{VideoPlugin.mtnDetectBlanks}",
154    'type' => "int",
155    'deft' => "80",
156    'range' => "0,100",
157    'reqd' => "no" },
158#   { 'name' => "mtn_detect_sharpness",
159#   'desc' => "{VideoPlugin.mtnDetectSharpness}",
160#   'type' => "enum",
161#   [{'name' => "off", 'desc' => "{mtnDetectSharpness.off}"},
162#   {'name' => "low", 'desc' => "{mtnDetectSharpness.low}"},
163#   {'name' => "medium", 'desc' => "{mtnDetectSharpness.medium}"},
164#   {'name' => "high", 'desc' => "{mtnDetectSharpness.high}"},
165#   {'name' => "highest", 'desc' => "{mtnDetectSharpness.highest}"}],
166#   'deft' => "highest",
167#   'reqd' => "no" },   
168   
169    { 'name' => "create_montage",
170    'desc' => "{VideoPlugin.createMontage}",
171    'type' => "enum",
172    'list' => [{'name' => "true", 'desc' => "{common.true}"},
173            {'name' => "false", 'desc' => "{common.false}"}],
174    'deft' => "false",
175    'reqd' => "no" },
176   
177      { 'name' => "streamingsize",
178    'desc' => "{VideoPlugin.streamingsize}",
179    'type' => "int",
180    'deft' => "352",
181    'reqd' => "no" },
182      { 'name' => "streamingbitrate",
183    'desc' => "{VideoPlugin.streamingbitrate}",
184    'type' => "string",
185    'deft' => "200k",
186    'reqd' => "no" },
187    { 'name' => "streamingHQsize",
188    'desc' => "{VideoPlugin.streamingsize}",
189    'type' => "int",
190    'deft' => "720",
191    'reqd' => "no" },
192    { 'name' => "streamingHQVideoBitrate",
193    'desc' => "{VideoPlugin.streamingbitrate}",
194    'type' => "int",
195    'deft' => "496",
196    'reqd' => "no" },
197    { 'name' => "streamingHQAudioBitrate",
198    'desc' => "{VideoPlugin.streamingbitrate}",
199    'type' => "int",
200    'deft' => "80",
201    'reqd' => "no" },
202    { 'name' => "videoDeinterlacingFilter",
203    'desc' => "Activate a deinterlacing filter to increase the quality of TV footage",
204    'type' => "enum",
205    'list' => [{'name' => "true", 'desc' => "{common.true}"},
206           {'name' => "false", 'desc' => "{common.false}"}],
207    'deft' => "false",
208    'reqd' => "no" },
209    { 'name' => "getMaximumMetadata",
210    'desc' => "Extract the maximum technical information of each video",
211    'type' => "enum",
212    'list' => [{'name' => "true", 'desc' => "{common.true}"},
213           {'name' => "false", 'desc' => "{common.false}"}],
214    'deft' => "false",
215    'reqd' => "no" },
216
217      { 'name' => "minimumsize",
218    'desc' => "{ImageConverter.minimumsize}",
219    'type' => "int",
220    'deft' => "100",
221    'range' => "1,",
222    'reqd' => "no" },
223
224         ];
225
226my $options = { 'name' => "VideoConverter",
227        'desc' => "{VideoConverter.desc}",
228        'abstract' => "yes",
229        'inherits' => "yes",
230        'args' => $arguments };
231
232sub new {
233    my ($class) = shift (@_);
234    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
235    push(@$pluginlist, $class);
236
237    push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
238    push(@{$hashArgOptLists->{"OptList"}},$options);
239
240    my $self = new MultimediaConverter($pluginlist, $inputargs, $hashArgOptLists, 1);
241
242
243    return bless $self, $class;
244
245}
246
247
248#  Here we use 'MediaInfo' for video and ask for a specific specification
249sub mediaInfo_Inform_Cmd {
250    my ($video, $parameter, $outhandle, $verbosity) = @_;
251   
252    # Use MediaInfo CLI to get the file spec according to the requested parameter
253    my $command = "mediainfo --Inform=\"$parameter\" \"$video\"";
254
255    print $outhandle "  $command\n" if ($verbosity > 2);
256    my $result = '';
257    $result = `$command 2>&1`;
258    chomp $result;
259    print $outhandle "  $result\n" if ($verbosity > 4);
260   
261    # Return the asked spec
262    return ($result);
263}
264
265# Here we use mediaInfo to get all the possible metadata in XML form that could then be parsed
266# the result will vary depending on the file type and how it was encoded
267sub mediaInfo_XML_Cmd {
268    my ($video, $outhandle, $verbosity) = @_;
269   
270    # Use MediaInfo CLI to get the file spec according to the requested parameter
271    my $command = "mediainfo --Output=XML \"$video\"";
272   
273    print $outhandle "  $command\n" if ($verbosity > 2);
274    my $result = '';
275    $result = `$command 2>&1`;
276    print $outhandle "  $result\n" if ($verbosity > 4);
277   
278    # Return the asked spec
279    return ($result);
280}
281
282# Here we parse the video specs contained in the XML text in order to create a metadata entry for each field
283# that mediainfo is giving back, this can vary from media file to media file.
284sub mediaInfo_parse_XML {
285    my ($xmlTxt, $outhandle, $verbosity) = @_;
286   
287    my @parts = split(/<track\s+type=\"(.*?)\">/is,$xmlTxt);
288   
289    shift @parts; # Skip preamble
290    my $metadata_table = {};
291   
292    while (@parts) {
293    my $type = shift(@parts);
294    my $vals = shift(@parts);
295    my @fieldlist=();
296    while ($vals =~ s/<(.*?)>(.*?)<\/\1>//) {
297        my $metaname = $1;
298        my $metaval  = $2;
299        my $fullmetaname = "mi.$type\^$metaname";
300        $metadata_table->{$fullmetaname}= $metaval;
301        push(@fieldlist,$fullmetaname);
302    }
303   
304    $metadata_table->{"mi.${type}Fields"}= join(",",@fieldlist);
305    }
306   
307    return $metadata_table;
308
309    while (@parts) {
310        my $type = shift(@parts);
311        my $vals = shift(@parts);
312        my @fieldlist=();
313        while ($vals =~ s/<(.*?)>(.*?)<\/\1>//) {
314          my $metaname = $1;
315          my $metaval  = $2;
316          my $fullmetaname = "mi.$type\^$metaname";
317          if($metaname ne "Complete_name") #ignore this field as it is pointing to the cache directory
318              {
319              $metadata_table->{$fullmetaname}= $metaval;
320              push(@fieldlist,$fullmetaname);
321              }
322        }
323        $metadata_table->{"mi.${type}Fields"}= join(",",@fieldlist);
324    }
325    return $metadata_table;
326
327}
328
329sub identifyMI {
330    my ($video, $outhandle, $verbosity) = @_;
331
332    # Use the MediaInfo command to get the file specs
333    my $command = "MediaInfo \"$video\"";
334
335    print $outhandle "  $command\n" if ($verbosity > 2);
336    my $result = '';
337    $result = `$command 2>&1`;
338    print $outhandle "  $result\n" if ($verbosity > 4);
339
340    # Read the type, width, and height etc. from media file
341    # This could be done in a more efficient way by only calling the application MediaInfo once and
342    # giving all the parameters inside a special macro file then parsing the results, however
343    # on most operating system when the application is called once it is then cached for subsequent calls.
344    # General info
345    my $vtype           = mediaInfo_Inform_Cmd($video,"General;%Format%",$outhandle,0); #Container of the video e.g. MPEG-TS
346    my $duration        = mediaInfo_Inform_Cmd($video,"General;%Duration%",$outhandle,0); #Duration of the video in ms e.g. 5545841
347    my $durationDisplay = mediaInfo_Inform_Cmd($video,"General;%Duration/String%",$outhandle,0); #Duration of the video in minutes and secs or hours and minutes e.g. 25m 12s or 2h 26m
348    my $filesize        = mediaInfo_Inform_Cmd($video,"General;%FileSize%",$outhandle,0); #File size in bytes e.g. 1024
349    my $filesizeDisplay = mediaInfo_Inform_Cmd($video,"General;%FileSize/String%",$outhandle,0); #File size with measure e.g. 25.6 MiB
350    my $orateDisplay    = mediaInfo_Inform_Cmd($video,"General;%OverallBitRate/String%",$outhandle,0); #General file bitrate with measure e.g. 7 538 Kbps
351    # Video info
352    my $vcodec          = mediaInfo_Inform_Cmd($video,"Video;%Format%",$outhandle,0); #Codec used for the video compression e.g. AVC
353    my $vrate           = mediaInfo_Inform_Cmd($video,"Video;%BitRate%",$outhandle,0); #Bitrate used for the video stream in bps e.g. 546165
354    my $width           = mediaInfo_Inform_Cmd($video,"Video;%Width%",$outhandle,0); #Width of the video in pixels e.g. 1920
355    my $height          = mediaInfo_Inform_Cmd($video,"Video;%Height%",$outhandle,0); #Height of the video in pixels e.g. 1080
356    my $fps             = mediaInfo_Inform_Cmd($video,"Video;%FrameRate%",$outhandle,0); #Video frames per second e.g. 30
357    # Audio info
358    my $acodec          = mediaInfo_Inform_Cmd($video,"Audio;%Format%",$outhandle,0); # Audio codec used for the compression e.g. AAC
359    my $afreq           = mediaInfo_Inform_Cmd($video,"Audio;%SamplingRate/String%",$outhandle,0); #Sampling rate used for audio encoding e.g. 48000
360    my $achan           = mediaInfo_Inform_Cmd($video,"Audio;%Channel(s)%",$outhandle,0); #Number of channels e.g. 2
361    my $arate           = mediaInfo_Inform_Cmd($video,"Audio;%BitRate%",$outhandle,0); #Audio bitrate for the audio stream in bps e.g. 65436
362    my $atracks         = mediaInfo_Inform_Cmd($video,"Audio;%StreamCount%",$outhandle,0); #number of audio tracks in this video file e.g. 1
363    # Subtitles info
364    my $stype           = mediaInfo_Inform_Cmd($video,"Text;%Format%",$outhandle,0); # Format used for the subtitles e.g. DVB Subtitle
365    my $slang           = mediaInfo_Inform_Cmd($video,"Text;%Language/String%",$outhandle,0); # Language used for the subtitles e.g. English
366       
367
368    my $xmlTxt =  mediaInfo_XML_Cmd ($video,$outhandle,0);
369    my $metadata_table = mediaInfo_parse_XML($xmlTxt,$outhandle,0);
370   
371    # Return the specs
372    my $identify_vals = { "vtype" => $vtype, "width" => $width, "height" => $height, "duration" => $duration, "filesize" => $filesize, "vcodec" => $vcodec,
373    "fps" => $fps, "acodec" => $acodec, "afreq" => $afreq, "achan" => $achan, "arate" => $arate, "metadata_table" => $metadata_table, "durationDisplay" => $durationDisplay,
374    "filesizeDisplay" => $filesizeDisplay, "orateDisplay" => $orateDisplay, "vrate" => $vrate, "stype" => $stype, "slang" => $slang, "atracks" => $atracks  };
375
376    return $identify_vals;
377}
378
379# Here we use 'ffmpeg' for video and ask for a specific specification
380# This is now deprecated this will be replaced by identifyMI in the future
381sub identify {
382    my ($video, $outhandle, $verbosity) = @_;
383
384    # Use the ffmpeg command to get the file specs
385    my $command = "ffmpeg -i \"$video\"";
386
387    print $outhandle "  $command\n" if ($verbosity > 2);
388    my $result = '';
389    $result = `$command 2>&1`;
390    print $outhandle "  $result\n" if ($verbosity > 4);
391
392    # Read the type, width, and height etc.
393    my $vtype =  'unknown';
394    my $vcodec = 'unknown';
395    my $width =  'unknown';
396    my $height = 'unknown';
397    my $fps    = 'unknown';
398
399    my $atype =  'unknown';
400    my $afreq =  'unknown';
401    my $achan =  'unknown';
402    my $arate =  'unknown';
403
404    my $video_safe = quotemeta $video;
405
406    # strip off everything up to filename
407    $result =~ s/^.*\'$video_safe\'://s;
408
409##    if ($result =~ m/Video: (.*?) fps/m) {
410    if ($result =~ m/^\s+Stream.*?Video: (.*?)$/m) {
411    my $video_info = $1;
412    $video_info =~ s/\s*\[.*?\]//g;
413
414    my @video_fields = split(/,\s*/,$video_info);
415   
416    $vtype = shift @video_fields;
417
418    if ($video_fields[0] !~ m/(\d+)x(\d+)/) {
419        $vcodec = shift @video_fields;
420    }
421    my $video_dim = shift @video_fields;
422
423    ($width,$height) = ($video_dim =~ m/(\d+)x(\d+)/);
424   
425    if ($video_fields[0] =~ m/(\d+)\s+tbr$/) {
426        $fps = $1;
427    }
428
429#   if ($video_info =~ m/([^,]+),(?: ([^,]+),)? (\d+)x(\d+),.*?(\d+\.\d+)/)
430#   {
431#       $vtype = $1;
432#       $vcodec = $2 if defined $2;
433#       $width = $3;
434#       $height = $4;
435#       $fps = $5;
436#   }
437    }
438
439    if ($result =~ m/Audio: (\w+), (\d+) Hz, (\w+)(?:, (\d+.*))?/m) {
440    $atype = $1;
441    $afreq = $2;
442    $achan = $3;
443    $arate = $4 if (defined $4);
444    }
445
446    # Read the duration
447    my $duration = "unknown";
448    if ($result =~ m/Duration: (\d+:\d+:\d+\.\d+)/m) {
449    $duration = $1;
450    }
451    print $outhandle "  file: $video:\t $vtype, $width, $height, $duration\n"
452    if ($verbosity > 2);
453
454    if ($verbosity >3) {
455    print $outhandle "\t video codec=$vcodec, fps = $fps\n";
456    print $outhandle "\t audio codec=$atype, freq = $afreq Hz, $achan, $arate\n";
457    }
458
459   
460    my $identify_vals = { "vtype" => $vtype, "width" => $width, "height" => $height, "duration" => $duration, "filesize" => -s $video, "vcodec" => $vcodec,
461    "fps" => $fps, "acodec" => $atype, "afreq" => $afreq, "achan" => $achan, "arate" => $arate };
462
463    return $identify_vals;
464   
465    # Return the specs
466    return ($vtype, $width, $height, $duration, -s $video,
467        $vcodec,$fps,$atype,$afreq,$achan,$arate);
468}
469
470
471sub vob_durations
472{
473    my ($media_base_dir,$title_num,$outhandle) = @_;
474
475    my $filter_re = sprintf("^VTS_%02d_[1-9]\\.VOB\$",$title_num);
476
477    my $duration_info = {};
478
479    if (opendir(VTSIN,$media_base_dir)) {
480    my @vts_title_vobs = grep { $_ =~ m/$filter_re/ } readdir(VTSIN);
481    closedir(VTSIN);
482
483    foreach my $v (@vts_title_vobs) {
484        my $full_v = &util::filename_cat($media_base_dir,$v);
485
486        my $identify_hash = identifyMI($full_v,$outhandle,0);
487       
488        my $duration = $identify_hash->{'duration'};
489
490        my ($vob_num) = ($v =~ m/^VTS_\d\d_(\d)\.VOB$/);
491
492        $duration_info->{$vob_num} = $duration;
493        print STDERR "**** $title_num: $title_num, storing {$vob_num} => $duration\n";
494
495    }
496
497    }
498    else {
499    print $outhandle "Warning: unable to read files in directory $media_base_dir\n";
500    }
501   
502    return $duration_info;
503
504}
505
506
507
508sub init_cache_for_file {
509    my $self = shift(@_);
510
511    my ($video_filename) = @_;
512
513    $self->SUPER::init_cache_for_file($video_filename);
514
515                   
516    my @flvtool2_monitor = ( 'monitor_init'   ,"convertutil::monitor_init_unbuffered",
517                 'monitor_line'   , "VideoConverter::flvtool2_monitor_line",
518                 'monitor_deinit' , "convertutil::monitor_deinit_unbuffered" );
519                   
520    $self->{'flvtool2_monitor'} = \@flvtool2_monitor;
521
522
523}
524
525
526
527sub optional_frame_scale
528{
529    my $self = shift (@_);
530    my ($orig_size,$video_width,$video_height) = @_;
531
532    my $s_opt = "";
533
534    if ($video_width > $video_height) {
535    if ($video_width > $orig_size) {
536        my $scale_factor = $orig_size/$video_width;
537        my $scaled_width = int($video_width * $scale_factor);
538        my $scaled_height = int($video_height * $scale_factor);
539
540        # round to be ensure multiple of 2 (needed by some codecs)
541        $scaled_width  = int($scaled_width/2)*2;
542        $scaled_height = int($scaled_height/2)*2;
543
544        $s_opt = "-s ${scaled_width}x${scaled_height}";
545    }
546    # else, video is smaller than requested size, don't scale up
547    }
548    else {
549    if ($video_height > $orig_size) {
550        my $scale_factor = $orig_size/$video_height;
551        my $scaled_width = int($video_width * $scale_factor);
552        my $scaled_height = int($video_height * $scale_factor);
553
554        # round to be ensure multiple of 2 (needed by some codecs)
555        $scaled_width  = int($scaled_width/2)*2;
556        $scaled_height = int($scaled_height/2)*2;
557
558        $s_opt = "-s ${scaled_width}x${scaled_height}";
559    }
560    # else, video is smaller than requested size, don't scale up
561   
562    }
563   
564    return $s_opt;
565}
566
567
568sub ffKeyframe_cmd
569{
570    my $self = shift (@_);
571    my ($ivideo_filename) = @_;
572
573    my $video_ext_dir = &util::filename_cat($ENV{'GSDLHOME'},"ext","video");
574
575    my $output_dir = $self->{'cached_dir'};
576    my $ivideo_root = $self->{'cached_file_root'};
577
578    my $oshot_filename = &util::filename_cat($output_dir,"shots.xml");
579
580    my $exp_duration = $self->{'exp_duration'};
581    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
582
583    my $main_opts = "-y $t_opt";
584
585    my $hive = &util::filename_cat($video_ext_dir,"lib","vhook","hive.so");
586
587    my $oflash_filename = &util::filename_cat($output_dir,"$ivideo_root\_keyframe.flv");
588
589    my $vhook_opts = "$hive  -o $oshot_filename -k $output_dir $ivideo_filename";
590
591    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
592    my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
593
594    my $ffmpeg_cmd = "ffkeyframe  $main_opts -vhook \"$vhook_opts\"   -i \"$ivideo_filename_gsdlenv\" -an -y \"$oflash_filename_gsdlenv\"";
595
596
597    return ($ffmpeg_cmd,$oflash_filename);
598}
599
600
601sub mtnKeyframe_cmd
602{
603    my $self = shift (@_);
604    my ($ivideo_filename) = @_;
605
606    my $video_ext_dir = &util::filename_cat($ENV{'GSDLHOME'},"ext","video");
607
608    my $output_dir = $self->{'cached_dir'};
609    my $ivideo_root = $self->{'cached_file_root'};
610
611    my $frames_output_dir = &util::filename_cat($output_dir,"frames");
612
613    my $main_opts = "-z -P -I -O \"$frames_output_dir\"";
614     
615    my $mtn_skip_intro_secs   = $self->{'mtn_skip_intro'};
616    my $mtn_skip_end_secs     = $self->{'mtn_skip_end'};
617    my $mtn_timestep_secs     = $self->{'mtn_timestep'};
618    my $mtn_detect_blank_perc = $self->{'mtn_detect_blanks'};
619   
620    my $mtn_detect_blank = $mtn_detect_blank_perc/100.0;
621   
622    my $keyframe_height;
623    if ($self->{'create_screenview'} eq "true") {
624        $keyframe_height = $self->{'screenviewsize'};
625    }
626    else {
627        # assume thumbnail size
628        $keyframe_height = $self->{'thumbnailsize'};
629    }
630       
631    $main_opts .= " -B $mtn_skip_intro_secs";
632    $main_opts .= " -E $mtn_skip_end_secs";
633    $main_opts .= " -s $mtn_timestep_secs";
634    $main_opts .= " -b $mtn_detect_blank";
635    $main_opts .= " -h $keyframe_height";
636   
637    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
638 
639    my $mtn_cmd = "mtn  $main_opts \"$ivideo_filename_gsdlenv\"";
640
641    my $output_s_filename = &util::filename_cat($frames_output_dir,$ivideo_root."_s.jpg");
642
643    return ($mtn_cmd,$output_s_filename);
644}
645
646
647sub get_ovideo_file
648{
649    my $self = shift (@_);
650    my ($stream_type) = @_;
651   
652    my $ivideo_root = $self->{'cached_file_root'};
653    my $ofile;
654   
655    if ($stream_type eq "flv")
656    {
657        $ofile = "${ivideo_root}_vstream.flv";
658    }
659    else
660    {
661        $ofile = "${ivideo_root}_vHQstream.mp4";
662    }
663   
664    return $ofile;
665}
666
667sub get_ovideo_filename
668{
669    my $self = shift (@_);
670    my ($stream_type) = @_;
671   
672    my $output_dir = $self->{'cached_dir'};
673
674    my $ofile = $self->get_ovideo_file($stream_type);
675       
676    my $ofilename = &util::filename_cat($output_dir,$ofile);
677   
678    return $ofilename;
679}
680
681# Generate the command to use with Handbrake to recompress a video using h264/aac compatible with Flash Player 10
682sub stream_mp4_video_cmd
683{
684    my $self = shift (@_);
685    my ($ivideo_filename,$streaming_HQ_size, $streaming_HQ_VideoBitrate,
686     $streaming_HQ_AudioBitrate) = @_;
687
688    my $output_dir = $self->{'cached_dir'};
689    my $ivideo_root = $self->{'cached_file_root'};
690
691    my $omp4_file = "${ivideo_root}_vHQstream.mp4";
692    my $omp4_filename = &util::filename_cat($output_dir,$omp4_file);
693
694
695    #my $exp_duration = $self->{'exp_duration'};
696    #my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
697
698    my $deinterlace = $self->{'videoDeinterlacingFilter'};
699    my $video_processing_parameters;   
700    # Use specific resizing algorythms depending if we need to downsize the video resolution or not
701    if(!$streaming_HQ_size || $streaming_HQ_size eq "fullsize") {
702        $video_processing_parameters = "--strict-anamorphic";
703    } else {
704        $video_processing_parameters = "-w $streaming_HQ_size --loose-anamorphic";
705    }
706    # Use the deinterlace video filter if enabled in the plugin
707    if ($deinterlace eq "true")
708    {
709        $video_processing_parameters .= " --decomb";
710    }
711
712    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
713    my $omp4_filename_gsdlenv = $self->gsdlhome_independent($omp4_filename);
714   
715    # Generate the pre and post video parameters for Handbrake v0.9.4
716    my $pre_opts = "-t 1 -c 1";
717    my $post_opts = "-f mp4 -O $video_processing_parameters -e x264 -b $streaming_HQ_VideoBitrate -a 1 -E faac -6 dpl2 -R Auto -B $streaming_HQ_AudioBitrate -D 0.0 -x ref=2:bframes=2:subq=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0";
718
719    my $handbrake_cmd = "HandbrakeCLI.exe -i \"$ivideo_filename_gsdlenv\" $pre_opts -o \"$omp4_filename_gsdlenv\" $post_opts";
720
721    #print STDERR "****\nHandbrake command: $handbrake_cmd\n****\n";
722   
723    return ($handbrake_cmd,$omp4_filename,$omp4_file);
724}
725
726
727
728sub stream_flv_video_cmd
729{
730    my $self = shift (@_);
731    my ($ivideo_filename,$video_width,$video_height,
732    $streaming_quality,
733    $streaming_bitrate,$streaming_size,
734    $opt_streaming_achan, $opt_streaming_arate) = @_;
735
736    my $streaming_achan
737    = (defined $opt_streaming_achan) ? $opt_streaming_achan : 2;
738
739    my $streaming_arate
740    = (defined $opt_streaming_arate) ? $opt_streaming_arate : 22050;
741
742    my $output_dir = $self->{'cached_dir'};
743    my $ivideo_root = $self->{'cached_file_root'};
744
745    my $oflash_file = "${ivideo_root}_vstream.flv";
746    my $oflash_filename = &util::filename_cat($output_dir,$oflash_file);
747
748    my $s_opt = "";
749    my $media_type = $self->{'media_type'};
750    if ($media_type ne "audio") {
751    $s_opt = $self->optional_frame_scale($streaming_size,$video_width,$video_height);
752    }
753
754
755    my $exp_duration = $self->{'exp_duration'};
756    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
757
758    my $main_opts = "-y $t_opt";
759
760    my $bitrate_opt = "-b $streaming_bitrate";
761    ### my $stream_opts = "-r 25 $s_opt";
762    my $stream_opts .= " $s_opt -ac $streaming_achan -ar $streaming_arate";
763
764    # -flags +ilme+ildct' and maybe '-flags +alt' for interlaced material, and try '-top 0/1'
765
766    my $all_opts = "$main_opts $stream_opts";
767
768    my $ffmpeg_cmd;
769
770    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
771    my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
772
773    if ($streaming_quality eq "high") {
774
775    my $pass_log_file = &util::filename_cat($output_dir,"$ivideo_root-logpass.txt");
776    if (-e $pass_log_file) {
777        &util::rm($pass_log_file);
778    }
779
780    my $pass_log_file_gsdlenv = $self->gsdlhome_independent($pass_log_file);
781
782    $all_opts .= " -passlogfile \"$pass_log_file_gsdlenv\"";
783
784    my $ffmpeg_cmd_pass1 = "ffmpeg -pass 1 -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
785
786    my $ffmpeg_cmd_pass2 = "ffmpeg -pass 2 -i \"$ivideo_filename_gsdlenv\" $all_opts $bitrate_opt -y \"$oflash_filename_gsdlenv\"";
787    $ffmpeg_cmd = "( $ffmpeg_cmd_pass1 && $ffmpeg_cmd_pass2 )";
788    }
789    else {
790    # single pass
791
792    $ffmpeg_cmd = "ffmpeg -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
793    }
794
795    return ($ffmpeg_cmd,$oflash_filename,$oflash_file);
796}
797
798
799
800
801sub stream_flv_audio_cmd
802{
803    # AudioConverter also has a routine for doing this
804    # => merge into one!
805    # **************
806
807    my $self = shift (@_);
808    my ($ivideo_filename, $opt_streaming_achan, $opt_streaming_arate) = @_;
809
810    # Convert either audio or video to streamable audio format
811
812    my $streaming_achan
813    = (defined $opt_streaming_achan) ? $opt_streaming_achan : 2;
814
815    my $streaming_arate
816    = (defined $opt_streaming_arate) ? $opt_streaming_arate : 22050;
817
818    my $output_dir = $self->{'cached_dir'};
819    my $ivideo_root = $self->{'cached_file_root'};
820
821    my $ofla_file = "${ivideo_root}_astream.flv";
822    my $ofla_filename = &util::filename_cat($output_dir,$ofla_file);
823
824    my $exp_duration = $self->{'exp_duration'};
825    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
826
827    my $main_opts = "-vn -y $t_opt";
828
829    my $stream_opts .= " -ac $streaming_achan -ar $streaming_arate";
830
831    my $all_opts = "$main_opts $stream_opts";
832
833    my $ffmpeg_cmd;
834
835    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
836    my $ofla_filename_gsdlenv = $self->gsdlhome_independent($ofla_filename);
837    $ffmpeg_cmd = "ffmpeg -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$ofla_filename_gsdlenv\"";
838
839    return ($ffmpeg_cmd,$ofla_filename,$ofla_file);
840}
841
842
843
844
845sub audio_excerpt_cmd
846{
847    my $self = shift (@_);
848    my ($ivoa_filename,$hh,$mm,$ss,$opt_excerpt_len) = @_;
849
850    # ivoa = input video or audio
851
852    my $time_encoded = "$hh:$mm:$ss";
853    my $time_encoded_file = "$hh$mm$ss";
854   
855   
856    my $output_dir = $self->{'cached_dir'};
857    my $ivoa_root = $self->{'cached_file_root'};
858
859    my $omp3_file = "${ivoa_root}_$time_encoded_file.mp3";
860    my $omp3_filename = &util::filename_cat($output_dir,$omp3_file);
861
862    my $all_opts = "-y -acodec mp3 -ss $time_encoded ";
863
864    if (defined $opt_excerpt_len) {
865    $all_opts .= "-t $opt_excerpt_len ";
866    }
867
868
869    my $ivoa_filename_gsdlenv = $self->gsdlhome_independent($ivoa_filename);
870    my $omp3_filename_gsdlenv = $self->gsdlhome_independent($omp3_filename);
871
872
873    my $ffmpeg_cmd = "ffmpeg -i \"$ivoa_filename_gsdlenv\" $all_opts  \"$omp3_filename_gsdlenv\"";
874
875    return ($ffmpeg_cmd,$omp3_filename,$omp3_file);
876}
877
878
879
880sub streamseekable_cmd
881{
882    my $self = shift (@_);
883    my ($oflash_filename) = @_;
884
885    my $output_dir = $self->{'cached_dir'};
886    my $ivideo_root = $self->{'cached_file_root'};
887
888    ## my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
889
890    my $flvtool_cmd = "flvtool2 -vUP \"$oflash_filename\"";
891
892    return ($flvtool_cmd,$oflash_filename);
893}
894
895
896sub streamkeyframes_cmd
897{
898    my $self = shift (@_);
899    my ($oflash_filename,$doc_obj,$section) = @_;
900
901    my $assocfilepath
902    = $doc_obj->get_metadata_element($section,"assocfilepath");
903
904    my $output_dir = $self->{'cached_dir'};
905
906    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
907 
908    my $flvtool_cmd = "flvtool2 -vAUtP \"$cue_filename\"  \"$oflash_filename\"";
909
910    return ($flvtool_cmd,$oflash_filename);
911}
912
913
914sub streamkeyframes_cmd_old
915{
916    my $self = shift (@_);
917    my ($oflash_filename,$doc_obj,$section) = @_;
918
919    my $assocfilepath
920    = $doc_obj->get_metadata_element($section,"assocfilepath");
921
922    my $output_dir = $self->{'cached_dir'};
923
924    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
925
926    my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
927    my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
928
929    my $collect = $ENV{'GSDLCOLLECTION'};
930 
931    print STDERR "**** Warning: need to remove dependency of GEXT_VIDEO_SERVER and _PREFIX\n";
932
933    my $flvtool_cmd = "flvtool2 -vAUtP \"$cue_filename\" -thumbLocation:$video_server$video_prefix/collect/$collect/index/assoc/$assocfilepath \"$oflash_filename\"";
934
935
936    return ($flvtool_cmd,$oflash_filename);
937}
938
939
940sub streamcuepts_cmd
941{
942    my $self = shift (@_);
943    my ($oflash_filename) = @_;
944
945    my $output_dir = $self->{'cached_dir'};
946
947    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
948
949    ##my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
950    ##my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
951
952    ## my $collect = $ENV{'GSDLCOLLECTION'};
953
954    ## my $thumbloc = "$video_server$video_prefix/collect/$collect";
955
956
957#    my $flvtool_cmd = "flvtool2 -vUAtP \"$cue_filename\" -thumbLocation:$thumbloc \"$oflash_filename\"";
958
959#    my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
960
961
962
963#    my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
964
965
966##    my $flvtool_cmd = "flvtool2 -vAt \"$cue_filename\" -UP \"$oflash_filename\" \"$output_dir/updated.flv\"";
967
968##    my $flvtool_cmd = "flvtool2 -vAtU \"$cue_filename\" \"$oflash_filename\" \"$output_dir/updated.flv\"";
969
970    my $flvtool_cmd = "flvtool2 -vAtUP \"$cue_filename\" \"$oflash_filename\"";
971
972    return ($flvtool_cmd,$oflash_filename);
973}
974
975
976sub keyframe_thumbnail_cmd
977{
978    my $self = shift (@_);
979    my ($ivideo_filename,$thumbnailfile,$thumbnailwidth,$thumbnailheight,$video_duration) = @_;
980
981    my $output_dir = $self->{'cached_dir'};
982    my $ivideo_root = $self->{'cached_file_root'};
983
984    my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
985
986
987    # Try for 4th keyframe, but fall back to 1st if doesn't exist
988    my $key_filename = "${key_filename_prefix}_0003.jpg";
989    $key_filename = "${key_filename_prefix}_0000.jpg" if (!-e $key_filename);
990
991    my $key_filename_gsdlenv = $self->gsdlhome_independent($key_filename);
992    my $thumbnailfile_gsdlenv = $self->gsdlhome_independent($thumbnailfile);
993
994    my $command;
995
996    if (-e $key_filename) {
997    $command = "convert -interlace plane -verbose -geometry $thumbnailwidth"
998        . "x$thumbnailheight \"$key_filename_gsdlenv\" \"$thumbnailfile_gsdlenv\"";
999    }
1000    else {
1001    # create_keyframe is either false, or else had a problem when running
1002    # => extract a from
1003    # my $frame_rate = 1.0 / 60.0;
1004   
1005    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
1006
1007     # If ever reused, then needs to change to newer hashmap method
1008     #my ($vtype, $width, $height, $duration, $vsize,
1009        #   $vcodec ,$fps ,$atype ,$afreq ,$achan ,$arate) = identify($ivideo_filename_gsdlenv,$outhandle,0);
1010   
1011    #print STDERR "***** grabbing keyframe as 50% of $video_duration\n";
1012    my $ss_opt = ($video_duration / 1000.0) * 0.35;
1013    #print STDERR "*** ssopt = $ss_opt\n";
1014   
1015    $command = "ffmpeg  -ss $ss_opt -i \"$ivideo_filename_gsdlenv\" -ss 4.5 -an -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -deinterlace -y \"$thumbnailfile_gsdlenv\"";
1016    #$command = "ffmpeg -ss 4.5 -i \"$ivideo_filename_gsdlenv\" -ss 4.5 -an -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -deinterlace -y \"$thumbnailfile_gsdlenv\"";
1017
1018    # fmpeg -i input.dv -r 1 -f image2 -s 120x96 images%05d.png
1019    }
1020
1021    return ($command,$thumbnailfile);
1022}
1023
1024
1025
1026
1027sub keyframe_montage_cmd
1028{
1029    my $self = shift (@_);
1030    my ($ivideo_filename,$montagefile) = @_;
1031
1032    my $output_dir = $self->{'cached_dir'};
1033    my $ivideo_root = $self->{'cached_file_root'};
1034
1035    my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
1036
1037    my $options = "-tile 10  -geometry 75x62+2+2";
1038
1039    my $command = "montage $options ${key_filename_prefix}_*.jpg \"$montagefile\"";
1040
1041    return ($command,$montagefile);
1042}
1043
1044
1045
1046sub parse_shot_xml
1047{
1048    my ($self) = shift(@_);
1049
1050    my $outhandle = $self->{'outhandle'};
1051    my $output_dir = $self->{'cached_dir'};
1052
1053    my $shots_filename = &util::filename_cat($output_dir,"shots.xml");
1054
1055    eval {
1056    $self->{'parser'}->parsefile($shots_filename);
1057    };
1058   
1059    if ($@) {
1060    print $outhandle "VideoConverter: skipping $shots_filename as not conformant to Hive shot syntax\n" if ($self->{'verbosity'} > 1);
1061    print $outhandle "\n Perl Error:\n $@\n" if ($self->{'verbosity'}>2);
1062    return 0;
1063    }
1064
1065}
1066
1067
1068sub parse_shot_dir
1069{
1070    my ($self) = shift(@_);
1071   
1072    my $outhandle = $self->{'outhandle'};
1073    my $output_dir = $self->{'cached_dir'};
1074   
1075    my $ivideo_root  = $self->{'cached_file_root'};
1076   
1077    my $frames_output_dir = &util::filename_cat($output_dir,"frames");
1078   
1079    my @jpeg_frames = ();
1080   
1081    if (opendir(FDIRIN, $frames_output_dir)) {
1082    @jpeg_frames = grep { $_ =~ /_\d+\.jpg$/ } readdir(FDIRIN);
1083    closedir(FDIRIN);
1084    }
1085    else {
1086    print STDERR "VideoConverter:: Failed to open directory $frames_output_dir:\n$!\n";
1087    return 0;
1088    }
1089   
1090    $self->{'keyframe_timeline'} = {};
1091   
1092    my $vfps = $self->{'video-fps'};
1093   
1094    my $keyframe_index = 1;
1095   
1096    foreach my $f (@jpeg_frames) {
1097    my ($hh,$mm,$ss) = ($f =~ m/_(\d{2})_(\d{2})_(\d{2})_\d+\.jpg$/);
1098    my $frame_num = (3600*$hh + 60*$mm + $ss) * $vfps;
1099   
1100    my $time_msec = (3600*$hh + 60*$mm + $ss) * 1000;
1101   
1102    my $timeline_rec = { 'name'=> "Keyframe $keyframe_index",
1103                 'keyframeindex' => $keyframe_index,
1104                 'timestamp' => $time_msec,
1105                 'thumb' => $f,
1106                 'keyframenum' => $keyframe_index };
1107   
1108    $self->{'keyframe_timeline'}->{$keyframe_index}=$timeline_rec;
1109   
1110    $keyframe_index++;
1111    }
1112   
1113    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
1114   
1115    $self->open_on_cue($cue_filename);
1116
1117    $self->output_distributed_keyframes($self->{'keyframe_timeline'},$self->{'ffkeyframe_num_shots'});
1118
1119    $self->close_on_cue();
1120   
1121    return 1;
1122}
1123
1124sub associate_keyframes_old
1125{
1126    my ($self) = shift(@_);
1127
1128    my ($doc_obj,$section) = @_;
1129
1130    my $output_dir = $self->{'cached_dir'};
1131
1132    my $count = 1;
1133    foreach my $kframe_file (@{$self->{'keyframe_fnames'}}) {
1134
1135    my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
1136    $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
1137                 $section);
1138    $count++;
1139    }
1140
1141    $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$self->{'keyframe_fnames'}}));
1142
1143
1144    # *****
1145    # $doc_obj->add_metadata ($section, "thumblist", $self->{'flowplayer_thumblist'});
1146
1147}
1148
1149sub associate_keyframes
1150{
1151    my ($self) = shift(@_);
1152
1153    my ($doc_obj,$topsection,$timeline) = @_;
1154
1155    my $output_dir = $self->{'cached_dir'};
1156   
1157    my $count = 1;
1158
1159    foreach my $t (sort { $timeline->{$a}->{'keyframeindex'} <=> $timeline->{$b}->{'keyframeindex'} } keys %$timeline)
1160    {
1161    my $kframe_file = $timeline->{$t}->{'thumb'};
1162    my $timestamp = $timeline->{$t}->{'timestamp'};
1163
1164    # create next sub-section to video "document"
1165    my $endchild = $doc_obj->insert_section($doc_obj->get_end_child($topsection));
1166    $doc_obj->add_utf8_metadata($endchild,"Title","Timestamp $timestamp");
1167    $doc_obj->add_utf8_metadata($endchild,"FrameNum",$t);
1168
1169    my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
1170    $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg",
1171                 "image/jpeg",
1172                 $endchild);
1173
1174    $doc_obj->add_utf8_metadata($endchild,"assockeyframe","keyframe$count.jpg");
1175
1176    $doc_obj->add_utf8_metadata($topsection,"KeyframeTimestamp",$timestamp);
1177    $doc_obj->add_utf8_metadata($topsection,"KeyframeFrameNum",$t);
1178
1179
1180
1181    $count++;
1182    }
1183
1184    #### $doc_obj->add_utf8_metadata($topsection,"NumKeyframes",scalar(@{$self->{'keyframe_fnames'}}));
1185
1186    $doc_obj->add_utf8_metadata($topsection,"NumKeyframes",scalar(keys %$timeline));
1187
1188
1189    # *****
1190    # $doc_obj->add_metadata ($topsection, "thumblist", $self->{'flowplayer_thumblist'});
1191}
1192
1193
1194
1195sub enable_audio_streaming
1196{
1197    my $self = shift (@_);
1198    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated) = @_;
1199
1200    my $section = $doc_obj->get_top_section();
1201
1202    my $output_dir   = $self->{'cached_dir'};
1203    my $ivideo_root  = $self->{'cached_file_root'};
1204   
1205    # Generate FLV audio-only format for streaming purposes
1206
1207    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1208    if ($self->{'enable_cache'}) {
1209    $optionally_run_general_cmd
1210        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1211    }
1212
1213   
1214    my $ifilename = $originalfilename || $filename;
1215
1216    my ($stream_cmd,$ofla_filename,$ofla_file)
1217    = $self->stream_flv_audio_cmd($ifilename);
1218   
1219   
1220    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
1221                   'message_prefix' => "Stream",
1222                   'message' => "Generating streamable audio: $ofla_file" };
1223   
1224
1225    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1226    = $self->$optionally_run_general_cmd($stream_cmd,
1227                         $ifilename,$ofla_filename,
1228                         $streamable_options);
1229
1230
1231    if (!$streamable_had_error) {
1232    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($ofla_filename);
1233   
1234    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
1235                       'message_prefix' => "Stream Seekable",
1236                       'message' => "Reprocessing audio stream to be seekable by timeline: $ofla_file" };
1237   
1238    if ($streamable_regenerated) {
1239        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
1240    }
1241   
1242    my $streamable_url = $ofla_file;
1243    my $streamable_url_safe = $self->url_safe($streamable_url);
1244
1245    $doc_obj->add_utf8_metadata ($section, "streamableaudio", $streamable_url_safe);
1246    $doc_obj->associate_file($ofla_filename,$ofla_file,"audio/flash",
1247                 $section);
1248    }
1249
1250    $doc_obj->add_metadata ($section, "audioflashwidth",    400);
1251    $doc_obj->add_metadata ($section, "audioflashheight",   22 + 100);
1252
1253    $self->{'ofla_file'} = $ofla_file;
1254    $self->{'ofla_filename'} = $ofla_filename;
1255
1256    return $streamable_regenerated;
1257}
1258
1259
1260
1261
1262
1263sub enable_video_streaming
1264{
1265    my $self = shift (@_);
1266    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1267    $video_width,$video_height) = @_;
1268
1269    my $section = $doc_obj->get_top_section();
1270
1271    my $output_dir   = $self->{'cached_dir'};
1272    my $ivideo_root  = $self->{'cached_file_root'};
1273   
1274    # Generate the Flash FLV format for streaming purposes
1275
1276    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1277    if ($self->{'enable_cache'}) {
1278    $optionally_run_general_cmd
1279        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1280    }
1281
1282
1283    my $streaming_bitrate = $self->{'streamingbitrate'};
1284    my $streaming_size    = $self->{'streamingsize'};
1285   
1286    my $streaming_quality = "high";
1287   
1288    my $ifilename = $originalfilename || $filename;
1289
1290    my ($stream_cmd,$oflash_filename,$oflash_file)
1291    = $self->stream_flv_video_cmd($ifilename,
1292                     $video_width,$video_height,
1293                     $streaming_quality,
1294                     $streaming_bitrate, $streaming_size);
1295   
1296   
1297    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
1298                   'message_prefix' => "Stream",
1299                   'message' => "Generating streamable video: $oflash_file" };
1300   
1301
1302    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1303    = $self->$optionally_run_general_cmd($stream_cmd,
1304                         $ifilename,$oflash_filename,
1305                         $streamable_options);
1306   
1307    if (!$streamable_had_error) {
1308    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($oflash_filename);
1309   
1310    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
1311                       'message_prefix' => "Stream Seekable",
1312                       'message' => "Reprocessing video stream to be seekable by timeline: $oflash_file" };
1313   
1314    if ($streamable_regenerated) {
1315        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
1316    }
1317   
1318    my $streamable_url = $oflash_file;
1319    my $streamable_url_safe = $self->url_safe($streamable_url);
1320   
1321    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1322    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/flash",
1323                 $section);
1324    }
1325
1326
1327    #
1328    # FlowPlayer.swf       height+22 pixels
1329    # FlowPlayerBlack.swf  height+16 pixels
1330    # FlowPlayerThermo.swf height+16 pixels
1331    # FlowPlayerWhite.swf  height+26 pixels
1332
1333    my $flashwidth = $video_width;
1334    my $flashheight = $video_height + 22;
1335
1336    if ($self->{'create_keyframes'} eq "true") {
1337    $flashheight += 100;
1338    }
1339
1340    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1341    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1342     
1343    $self->{'oflash_file'} = $oflash_file;
1344    $self->{'oflash_filename'} = $oflash_filename;
1345
1346    return $streamable_regenerated;
1347}
1348
1349sub enable_direct_streaming
1350{
1351    my $self = shift (@_);
1352    my ($doc_obj,$originalfilename,$filename,$file,
1353    $video_width,$video_height) = @_;
1354
1355    my $section = $doc_obj->get_top_section();
1356   
1357    my $ifilename = $originalfilename || $filename;
1358    #my $ifile = $self->gsdlhome_independent($ifilename);
1359    my $ifile = $file;
1360
1361    print STDERR "Using the original video file for direct streaming: $ifile\n";
1362
1363    my $streamable_url = $ifile;
1364    my $streamable_url_safe = $self->url_safe($streamable_url);
1365   
1366    my $outhandle = $self->{'outhandle'};
1367
1368    my $identify_vals = identifyMI($ifilename,$outhandle,0);
1369
1370    #Add the most common metadata extracted by MediaInfo from the streamable video file
1371    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFormat", $identify_vals->{'vtype'});
1372    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSize", $identify_vals->{'filesizeDisplay'});
1373    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSizeBytes", $identify_vals->{'filesize'});
1374    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingWidth", $identify_vals->{'width'});
1375    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingHeight", $identify_vals->{'height'});
1376    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDuration", $identify_vals->{'durationDisplay'});
1377    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDurationMs", $identify_vals->{'duration'});
1378    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFPS", $identify_vals->{'fps'});
1379    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoCodec", $identify_vals->{'vcodec'});
1380    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoBitrate", $identify_vals->{'vrate'});
1381    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioCodec", $identify_vals->{'acodec'});
1382    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioBitrate", $identify_vals->{'arate'});
1383    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioTracks", $identify_vals->{'atracks'});
1384    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingOverallBitrate", $identify_vals->{'orateDisplay'});
1385    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleType", $identify_vals->{'stype'});
1386    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleLanguage", $identify_vals->{'slang'});
1387   
1388    my $get_max_metadata = $self->{'getMaximumMetadata'};
1389    if ($get_max_metadata eq "true"){
1390        my $metadata_table = $identify_vals->{'metadata_table'};
1391        foreach my $metaname(keys %$metadata_table)
1392        {
1393            my $metaval = $identify_vals->{'metadata_table'}->{$metaname};
1394            $doc_obj->add_utf8_metadata ($section, $metaname, $metaval);
1395        }
1396    }
1397   
1398    #add the metadata for the resulting file that should be open inside the replayme video player
1399    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1400    $doc_obj->associate_file($ifilename,$ifile,"application/octet-stream",$section);
1401
1402    my $flashwidth = $video_width;
1403    my $flashheight = $video_height + 22;
1404
1405    if ($self->{'create_keyframes'} eq "true") {
1406    $flashheight += 100;
1407    }
1408
1409    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1410    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1411     
1412    $self->{'oflash_file'} = $ifile;
1413    $self->{'oflash_filename'} = $ifilename;
1414
1415}
1416
1417
1418sub enable_h264_streaming
1419{
1420    my $self = shift (@_);
1421    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1422    $video_width,$video_height) = @_;
1423   
1424
1425    my $section = $doc_obj->get_top_section();
1426
1427    my $output_dir   = $self->{'cached_dir'};
1428    my $ivideo_root  = $self->{'cached_file_root'};
1429   
1430    # Generate the H264 video file format for streaming purposes using the cache feature if used
1431
1432    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1433    if ($self->{'enable_cache'}) {
1434    $optionally_run_general_cmd
1435        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1436    }
1437
1438    my $streaming_HQ_size    = $self->{'streamingHQsize'};
1439    my $streaming_HQ_VideoBitrate    = $self->{'streamingHQVideoBitrate'};
1440    my $streaming_HQ_AudioBitrate    = $self->{'streamingHQAudioBitrate'};
1441
1442    my $ifilename = $originalfilename || $filename;
1443    my ($stream_cmd,$oflash_filename,$oflash_file)
1444    = $self->stream_mp4_video_cmd($ifilename,
1445                     $streaming_HQ_size,
1446                     $streaming_HQ_VideoBitrate,
1447                     $streaming_HQ_AudioBitrate);
1448   
1449   
1450    my $streamable_options = { @{$self->{'handbrake_monitor'}},
1451                   'message_prefix' => "MP4 Stream",
1452                   'message' => "Generating streamable MP4 video: $oflash_file" };
1453   
1454
1455    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1456    = $self->$optionally_run_general_cmd($stream_cmd,
1457                         $ifilename,$oflash_filename,
1458                         $streamable_options);
1459   
1460    if (!$streamable_had_error) {
1461
1462   
1463    my $streamable_url = $oflash_file;
1464    my $streamable_url_safe = $self->url_safe($streamable_url);
1465   
1466    my $outhandle = $self->{'outhandle'};
1467
1468    my $identify_vals = identifyMI($oflash_filename,$outhandle,0);
1469   
1470    #Add the most common metadata extracted by MediaInfo from the streamable video file
1471    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFormat", $identify_vals->{'vtype'});
1472    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSize", $identify_vals->{'filesizeDisplay'});
1473    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingWidth", $identify_vals->{'width'});
1474    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingHeight", $identify_vals->{'height'});
1475    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDuration", $identify_vals->{'durationDisplay'});
1476    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFPS", $identify_vals->{'fps'});
1477    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoCodec", $identify_vals->{'vcodec'});
1478    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoBitrate", $identify_vals->{'vrate'});
1479    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioCodec", $identify_vals->{'acodec'});
1480    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioBitrate", $identify_vals->{'arate'});
1481    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingOverallBitrate", $identify_vals->{'orateDisplay'});
1482    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleType", $identify_vals->{'stype'});
1483    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleLangue", $identify_vals->{'slang'});
1484   
1485    my $get_max_metadata = $self->{'getMaximumMetadata'};
1486    if ($get_max_metadata eq "true"){
1487        my $metadata_table = $identify_vals->{'metadata_table'};
1488        foreach my $metaname(keys %$metadata_table)
1489        {
1490            my $metaval = $identify_vals->{'metadata_table'}->{$metaname};
1491            $doc_obj->add_utf8_metadata ($section, $metaname, $metaval);
1492        }
1493    }
1494   
1495    #add the metadata for the resulting file that should be open inside the flash video player
1496    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1497    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/mp4",
1498                 $section);
1499    }
1500
1501    my $flashwidth = $video_width;
1502    my $flashheight = $video_height + 22;
1503
1504    if ($self->{'create_keyframes'} eq "true") {
1505    $flashheight += 100;
1506    }
1507
1508    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1509    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1510     
1511    $self->{'oflash_file'} = $oflash_file;
1512    $self->{'oflash_filename'} = $oflash_filename;
1513
1514    return $streamable_regenerated;
1515   
1516   
1517}
1518
1519sub enable_full_streaming
1520{
1521    my $self = shift (@_);
1522    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1523    $video_width,$video_height) = @_;
1524
1525    my $video_streamable_regenerated
1526    = $self->enable_video_streaming($doc_obj,$originalfilename,$filename,
1527                    $convertto_regenerated,
1528                    $video_width,$video_height);
1529
1530    my $audio_streamable_regenerated
1531    = $self->enable_audio_streaming($doc_obj,$originalfilename,$filename,
1532                    $convertto_regenerated);
1533
1534    return ($video_streamable_regenerated || $audio_streamable_regenerated);
1535}
1536
1537
1538
1539sub flvtool2_monitor_line
1540{
1541    my ($line) = @_;
1542
1543    my $had_error = 0;
1544    my $generate_dot = 1;
1545
1546    if ($line =~ m/\s+\- /) {
1547    # ignore tabulated output printed at end of command
1548    $generate_dot = 0;
1549    }
1550   
1551    if ($line =~ m/^Error:/i) {
1552    $had_error = 1;
1553    }
1554
1555    return ($had_error,$generate_dot);
1556}
1557
1558
1559
1560
1561
15621;
Note: See TracBrowser for help on using the browser.