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

Revision 25346, 49.2 KB (checked in by davidb, 8 years ago)

Updates to code that take account of changes in the central PM modules

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 -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##  $command = "ffmpeg -i \"$ivideo_filename_gsdlenv\"  -ss 10.5 -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -deinterlace -y \"$thumbnailfile_gsdlenv\"";
1019
1020    $command = "ffmpeg -i \"$ivideo_filename_gsdlenv\"  -ss 16.5 -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -deinterlace -y \"$thumbnailfile_gsdlenv\"";
1021
1022
1023    # fmpeg -i input.dv -r 1 -f image2 -s 120x96 images%05d.png
1024    }
1025
1026    return ($command,$thumbnailfile);
1027}
1028
1029
1030
1031
1032sub keyframe_montage_cmd
1033{
1034    my $self = shift (@_);
1035    my ($ivideo_filename,$montagefile) = @_;
1036
1037    my $output_dir = $self->{'cached_dir'};
1038    my $ivideo_root = $self->{'cached_file_root'};
1039
1040    my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
1041
1042    my $options = "-tile 10  -geometry 75x62+2+2";
1043
1044    my $command = "montage $options ${key_filename_prefix}_*.jpg \"$montagefile\"";
1045
1046    return ($command,$montagefile);
1047}
1048
1049
1050
1051sub parse_shot_xml
1052{
1053    my ($self) = shift(@_);
1054
1055    my $outhandle = $self->{'outhandle'};
1056    my $output_dir = $self->{'cached_dir'};
1057
1058    my $shots_filename = &util::filename_cat($output_dir,"shots.xml");
1059
1060    eval {
1061    $self->{'parser'}->parsefile($shots_filename);
1062    };
1063   
1064    if ($@) {
1065    print $outhandle "VideoConverter: skipping $shots_filename as not conformant to Hive shot syntax\n" if ($self->{'verbosity'} > 1);
1066    print $outhandle "\n Perl Error:\n $@\n" if ($self->{'verbosity'}>2);
1067    return 0;
1068    }
1069
1070}
1071
1072
1073sub parse_shot_dir
1074{
1075    my ($self) = shift(@_);
1076   
1077    my $outhandle = $self->{'outhandle'};
1078    my $output_dir = $self->{'cached_dir'};
1079   
1080    my $ivideo_root  = $self->{'cached_file_root'};
1081   
1082    my $frames_output_dir = &util::filename_cat($output_dir,"frames");
1083   
1084    my @jpeg_frames = ();
1085   
1086    if (opendir(FDIRIN, $frames_output_dir)) {
1087    @jpeg_frames = grep { $_ =~ /_\d+\.jpg$/ } readdir(FDIRIN);
1088    closedir(FDIRIN);
1089    }
1090    else {
1091    print STDERR "VideoConverter:: Failed to open directory $frames_output_dir:\n$!\n";
1092    return 0;
1093    }
1094   
1095    $self->{'keyframe_timeline'} = {};
1096   
1097    my $vfps = $self->{'video-fps'};
1098   
1099    my $keyframe_index = 1;
1100   
1101    foreach my $f (@jpeg_frames) {
1102    my ($hh,$mm,$ss) = ($f =~ m/_(\d{2})_(\d{2})_(\d{2})_\d+\.jpg$/);
1103    my $frame_num = (3600*$hh + 60*$mm + $ss) * $vfps;
1104   
1105    my $time_msec = (3600*$hh + 60*$mm + $ss) * 1000;
1106   
1107    my $timeline_rec = { 'name'=> "Keyframe $keyframe_index",
1108                 'keyframeindex' => $keyframe_index,
1109                 'timestamp' => $time_msec,
1110                 'thumb' => $f,
1111                 'keyframenum' => $keyframe_index };
1112   
1113    $self->{'keyframe_timeline'}->{$keyframe_index}=$timeline_rec;
1114   
1115    $keyframe_index++;
1116    }
1117   
1118    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
1119   
1120    $self->open_on_cue($cue_filename);
1121
1122    $self->output_distributed_keyframes($self->{'keyframe_timeline'},$self->{'ffkeyframe_num_shots'});
1123
1124    $self->close_on_cue();
1125   
1126    return 1;
1127}
1128
1129sub associate_keyframes_old
1130{
1131    my ($self) = shift(@_);
1132
1133    my ($doc_obj,$section) = @_;
1134
1135    my $output_dir = $self->{'cached_dir'};
1136
1137    my $count = 1;
1138    foreach my $kframe_file (@{$self->{'keyframe_fnames'}}) {
1139
1140    my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
1141    $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
1142                 $section);
1143    $count++;
1144    }
1145
1146    $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$self->{'keyframe_fnames'}}));
1147
1148
1149    # *****
1150    # $doc_obj->add_metadata ($section, "thumblist", $self->{'flowplayer_thumblist'});
1151
1152}
1153
1154sub associate_keyframes
1155{
1156    my ($self) = shift(@_);
1157
1158    my ($doc_obj,$topsection,$timeline) = @_;
1159
1160    my $output_dir = $self->{'cached_dir'};
1161   
1162    my $count = 1;
1163
1164    foreach my $t (sort { $timeline->{$a}->{'keyframeindex'} <=> $timeline->{$b}->{'keyframeindex'} } keys %$timeline)
1165    {
1166    my $kframe_file = $timeline->{$t}->{'thumb'};
1167    my $timestamp = $timeline->{$t}->{'timestamp'};
1168
1169    # create next sub-section to video "document"
1170    my $endchild = $doc_obj->insert_section($doc_obj->get_end_child($topsection));
1171    $doc_obj->add_utf8_metadata($endchild,"Title","Timestamp $timestamp");
1172    $doc_obj->add_utf8_metadata($endchild,"FrameNum",$t);
1173
1174    my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
1175    $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg",
1176                 "image/jpeg",
1177                 $endchild);
1178
1179    $doc_obj->add_utf8_metadata($endchild,"assockeyframe","keyframe$count.jpg");
1180
1181    $doc_obj->add_utf8_metadata($topsection,"KeyframeTimestamp",$timestamp);
1182    $doc_obj->add_utf8_metadata($topsection,"KeyframeFrameNum",$t);
1183
1184
1185
1186    $count++;
1187    }
1188
1189    #### $doc_obj->add_utf8_metadata($topsection,"NumKeyframes",scalar(@{$self->{'keyframe_fnames'}}));
1190
1191    $doc_obj->add_utf8_metadata($topsection,"NumKeyframes",scalar(keys %$timeline));
1192
1193
1194    # *****
1195    # $doc_obj->add_metadata ($topsection, "thumblist", $self->{'flowplayer_thumblist'});
1196}
1197
1198
1199
1200sub enable_audio_streaming
1201{
1202    my $self = shift (@_);
1203    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated) = @_;
1204
1205    my $section = $doc_obj->get_top_section();
1206
1207    my $output_dir   = $self->{'cached_dir'};
1208    my $ivideo_root  = $self->{'cached_file_root'};
1209   
1210    # Generate FLV audio-only format for streaming purposes
1211
1212    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1213    if ($self->{'enable_cache'}) {
1214    $optionally_run_general_cmd
1215        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1216    }
1217
1218   
1219    my $ifilename = $originalfilename || $filename;
1220
1221    my ($stream_cmd,$ofla_filename,$ofla_file)
1222    = $self->stream_flv_audio_cmd($ifilename);
1223   
1224   
1225    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
1226                   'message_prefix' => "Stream",
1227                   'message' => "Generating streamable audio: $ofla_file" };
1228   
1229
1230    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1231    = $self->$optionally_run_general_cmd($stream_cmd,
1232                         $ifilename,$ofla_filename,
1233                         $streamable_options);
1234
1235
1236    if (!$streamable_had_error) {
1237    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($ofla_filename);
1238   
1239    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
1240                       'message_prefix' => "Stream Seekable",
1241                       'message' => "Reprocessing audio stream to be seekable by timeline: $ofla_file" };
1242   
1243    if ($streamable_regenerated) {
1244        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
1245    }
1246   
1247    my $streamable_url = $ofla_file;
1248    my $streamable_url_safe = $self->url_safe($streamable_url);
1249
1250    $doc_obj->add_utf8_metadata ($section, "streamableaudio", $streamable_url_safe);
1251    $doc_obj->associate_file($ofla_filename,$ofla_file,"audio/flash",
1252                 $section);
1253    }
1254
1255    $doc_obj->add_metadata ($section, "audioflashwidth",    400);
1256    $doc_obj->add_metadata ($section, "audioflashheight",   22 + 100);
1257
1258    $self->{'ofla_file'} = $ofla_file;
1259    $self->{'ofla_filename'} = $ofla_filename;
1260
1261    return $streamable_regenerated;
1262}
1263
1264
1265
1266
1267
1268sub enable_video_streaming
1269{
1270    my $self = shift (@_);
1271    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1272    $video_width,$video_height) = @_;
1273
1274    my $section = $doc_obj->get_top_section();
1275
1276    my $output_dir   = $self->{'cached_dir'};
1277    my $ivideo_root  = $self->{'cached_file_root'};
1278   
1279    # Generate the Flash FLV format for streaming purposes
1280
1281    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1282    if ($self->{'enable_cache'}) {
1283    $optionally_run_general_cmd
1284        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1285    }
1286
1287
1288    my $streaming_bitrate = $self->{'streamingbitrate'};
1289    my $streaming_size    = $self->{'streamingsize'};
1290   
1291    my $streaming_quality = "high";
1292   
1293    my $ifilename = $originalfilename || $filename;
1294
1295    my ($stream_cmd,$oflash_filename,$oflash_file)
1296    = $self->stream_flv_video_cmd($ifilename,
1297                     $video_width,$video_height,
1298                     $streaming_quality,
1299                     $streaming_bitrate, $streaming_size);
1300   
1301   
1302    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
1303                   'message_prefix' => "Stream",
1304                   'message' => "Generating streamable video: $oflash_file" };
1305   
1306
1307    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1308    = $self->$optionally_run_general_cmd($stream_cmd,
1309                         $ifilename,$oflash_filename,
1310                         $streamable_options);
1311   
1312    if (!$streamable_had_error) {
1313    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($oflash_filename);
1314   
1315    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
1316                       'message_prefix' => "Stream Seekable",
1317                       'message' => "Reprocessing video stream to be seekable by timeline: $oflash_file" };
1318   
1319    if ($streamable_regenerated) {
1320        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
1321    }
1322   
1323    my $streamable_url = $oflash_file;
1324    my $streamable_url_safe = $self->url_safe($streamable_url);
1325   
1326    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1327    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/flash",
1328                 $section);
1329    }
1330
1331
1332    #
1333    # FlowPlayer.swf       height+22 pixels
1334    # FlowPlayerBlack.swf  height+16 pixels
1335    # FlowPlayerThermo.swf height+16 pixels
1336    # FlowPlayerWhite.swf  height+26 pixels
1337
1338    my $flashwidth = $video_width;
1339    my $flashheight = $video_height + 22;
1340
1341    if ($self->{'create_keyframes'} eq "true") {
1342    $flashheight += 100;
1343    }
1344
1345    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1346    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1347     
1348    $self->{'oflash_file'} = $oflash_file;
1349    $self->{'oflash_filename'} = $oflash_filename;
1350
1351    return $streamable_regenerated;
1352}
1353
1354sub enable_direct_streaming
1355{
1356    my $self = shift (@_);
1357    my ($doc_obj,$originalfilename,$filename,$file,
1358    $video_width,$video_height) = @_;
1359
1360    my $section = $doc_obj->get_top_section();
1361   
1362    my $ifilename = $originalfilename || $filename;
1363    #my $ifile = $self->gsdlhome_independent($ifilename);
1364    my $ifile = $file;
1365
1366    print STDERR "Using the original video file for direct streaming: $ifile\n";
1367
1368    my $streamable_url = $ifile;
1369    my $streamable_url_safe = $self->url_safe($streamable_url);
1370   
1371    my $outhandle = $self->{'outhandle'};
1372
1373    my $identify_vals = identifyMI($ifilename,$outhandle,0);
1374
1375    #Add the most common metadata extracted by MediaInfo from the streamable video file
1376    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFormat", $identify_vals->{'vtype'});
1377    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSize", $identify_vals->{'filesizeDisplay'});
1378    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSizeBytes", $identify_vals->{'filesize'});
1379    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingWidth", $identify_vals->{'width'});
1380    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingHeight", $identify_vals->{'height'});
1381    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDuration", $identify_vals->{'durationDisplay'});
1382    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDurationMs", $identify_vals->{'duration'});
1383    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFPS", $identify_vals->{'fps'});
1384    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoCodec", $identify_vals->{'vcodec'});
1385    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoBitrate", $identify_vals->{'vrate'});
1386    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioCodec", $identify_vals->{'acodec'});
1387    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioBitrate", $identify_vals->{'arate'});
1388    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioTracks", $identify_vals->{'atracks'});
1389    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingOverallBitrate", $identify_vals->{'orateDisplay'});
1390    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleType", $identify_vals->{'stype'});
1391    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleLanguage", $identify_vals->{'slang'});
1392   
1393    my $get_max_metadata = $self->{'getMaximumMetadata'};
1394    if ($get_max_metadata eq "true"){
1395        my $metadata_table = $identify_vals->{'metadata_table'};
1396        foreach my $metaname(keys %$metadata_table)
1397        {
1398            my $metaval = $identify_vals->{'metadata_table'}->{$metaname};
1399            $doc_obj->add_utf8_metadata ($section, $metaname, $metaval);
1400        }
1401    }
1402   
1403    #add the metadata for the resulting file that should be open inside the replayme video player
1404    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1405    $doc_obj->associate_file($ifilename,$ifile,"application/octet-stream",$section);
1406
1407    my $flashwidth = $video_width;
1408    my $flashheight = $video_height + 22;
1409
1410    if ($self->{'create_keyframes'} eq "true") {
1411    $flashheight += 100;
1412    }
1413
1414    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1415    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1416     
1417    $self->{'oflash_file'} = $ifile;
1418    $self->{'oflash_filename'} = $ifilename;
1419
1420}
1421
1422
1423sub enable_h264_streaming
1424{
1425    my $self = shift (@_);
1426    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1427    $video_width,$video_height) = @_;
1428   
1429
1430    my $section = $doc_obj->get_top_section();
1431
1432    my $output_dir   = $self->{'cached_dir'};
1433    my $ivideo_root  = $self->{'cached_file_root'};
1434   
1435    # Generate the H264 video file format for streaming purposes using the cache feature if used
1436
1437    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1438    if ($self->{'enable_cache'}) {
1439    $optionally_run_general_cmd
1440        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1441    }
1442
1443    my $streaming_HQ_size    = $self->{'streamingHQsize'};
1444    my $streaming_HQ_VideoBitrate    = $self->{'streamingHQVideoBitrate'};
1445    my $streaming_HQ_AudioBitrate    = $self->{'streamingHQAudioBitrate'};
1446
1447    my $ifilename = $originalfilename || $filename;
1448    my ($stream_cmd,$oflash_filename,$oflash_file)
1449    = $self->stream_mp4_video_cmd($ifilename,
1450                     $streaming_HQ_size,
1451                     $streaming_HQ_VideoBitrate,
1452                     $streaming_HQ_AudioBitrate);
1453   
1454   
1455    my $streamable_options = { @{$self->{'handbrake_monitor'}},
1456                   'message_prefix' => "MP4 Stream",
1457                   'message' => "Generating streamable MP4 video: $oflash_file" };
1458   
1459
1460    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1461    = $self->$optionally_run_general_cmd($stream_cmd,
1462                         $ifilename,$oflash_filename,
1463                         $streamable_options);
1464   
1465    if (!$streamable_had_error) {
1466
1467   
1468    my $streamable_url = $oflash_file;
1469    my $streamable_url_safe = $self->url_safe($streamable_url);
1470   
1471    my $outhandle = $self->{'outhandle'};
1472
1473    my $identify_vals = identifyMI($oflash_filename,$outhandle,0);
1474   
1475    #Add the most common metadata extracted by MediaInfo from the streamable video file
1476    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFormat", $identify_vals->{'vtype'});
1477    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSize", $identify_vals->{'filesizeDisplay'});
1478    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingWidth", $identify_vals->{'width'});
1479    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingHeight", $identify_vals->{'height'});
1480    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDuration", $identify_vals->{'durationDisplay'});
1481    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFPS", $identify_vals->{'fps'});
1482    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoCodec", $identify_vals->{'vcodec'});
1483    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoBitrate", $identify_vals->{'vrate'});
1484    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioCodec", $identify_vals->{'acodec'});
1485    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioBitrate", $identify_vals->{'arate'});
1486    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingOverallBitrate", $identify_vals->{'orateDisplay'});
1487    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleType", $identify_vals->{'stype'});
1488    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingSubtitleLangue", $identify_vals->{'slang'});
1489   
1490    my $get_max_metadata = $self->{'getMaximumMetadata'};
1491    if ($get_max_metadata eq "true"){
1492        my $metadata_table = $identify_vals->{'metadata_table'};
1493        foreach my $metaname(keys %$metadata_table)
1494        {
1495            my $metaval = $identify_vals->{'metadata_table'}->{$metaname};
1496            $doc_obj->add_utf8_metadata ($section, $metaname, $metaval);
1497        }
1498    }
1499   
1500    #add the metadata for the resulting file that should be open inside the flash video player
1501    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1502    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/mp4",
1503                 $section);
1504    }
1505
1506    my $flashwidth = $video_width;
1507    my $flashheight = $video_height + 22;
1508
1509    if ($self->{'create_keyframes'} eq "true") {
1510    $flashheight += 100;
1511    }
1512
1513    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1514    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1515     
1516    $self->{'oflash_file'} = $oflash_file;
1517    $self->{'oflash_filename'} = $oflash_filename;
1518
1519    return $streamable_regenerated;
1520   
1521   
1522}
1523
1524sub enable_full_streaming
1525{
1526    my $self = shift (@_);
1527    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1528    $video_width,$video_height) = @_;
1529
1530    my $video_streamable_regenerated
1531    = $self->enable_video_streaming($doc_obj,$originalfilename,$filename,
1532                    $convertto_regenerated,
1533                    $video_width,$video_height);
1534
1535    my $audio_streamable_regenerated
1536    = $self->enable_audio_streaming($doc_obj,$originalfilename,$filename,
1537                    $convertto_regenerated);
1538
1539    return ($video_streamable_regenerated || $audio_streamable_regenerated);
1540}
1541
1542
1543
1544sub flvtool2_monitor_line
1545{
1546    my ($line) = @_;
1547
1548    my $had_error = 0;
1549    my $generate_dot = 1;
1550
1551    if ($line =~ m/\s+\- /) {
1552    # ignore tabulated output printed at end of command
1553    $generate_dot = 0;
1554    }
1555   
1556    if ($line =~ m/^Error:/i) {
1557    $had_error = 1;
1558    }
1559
1560    return ($had_error,$generate_dot);
1561}
1562
1563
1564
1565
1566
15671;
Note: See TracBrowser for help on using the browser.