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

Revision 23292, 40.9 KB (checked in by max, 10 years ago)

Add direct streaming option to use the original video file directly without any processing. Depending on the format of the imported video file, VLC player may be required (flash is fussy regarding formats and containers).

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      { 'name' => "extract_keyframes",
116    'desc' => "{VideoPlugin.extractkeyframes}",
117    'type' => "flag",
118    'deft' => "0",
119    'reqd' => "no" },
120      { 'name' => "keep_keyframes",
121    'desc' => "{VideoPlugin.keep_keyframes}",
122    'type' => "string",
123    'deft' => "all",
124    'reqd' => "no" },
125      { 'name' => "streamingsize",
126    'desc' => "{VideoPlugin.streamingsize}",
127    'type' => "int",
128    'deft' => "352",
129    'reqd' => "no" },
130      { 'name' => "streamingbitrate",
131    'desc' => "{VideoPlugin.streamingbitrate}",
132    'type' => "string",
133    'deft' => "200k",
134    'reqd' => "no" },
135    { 'name' => "streamingHQsize",
136    'desc' => "{VideoPlugin.streamingsize}",
137    'type' => "int",
138    'deft' => "720",
139    'reqd' => "no" },
140    { 'name' => "streamingHQVideoBitrate",
141    'desc' => "{VideoPlugin.streamingbitrate}",
142    'type' => "int",
143    'deft' => "496",
144    'reqd' => "no" },
145    { 'name' => "streamingHQAudioBitrate",
146    'desc' => "{VideoPlugin.streamingbitrate}",
147    'type' => "int",
148    'deft' => "80",
149    'reqd' => "no" },
150    { 'name' => "videoDeinterlacingFilter",
151    'desc' => "Activate a deinterlacing filter to increase the quality of TV footage",
152    'type' => "enum",
153    'list' => [{'name' => "true", 'desc' => "{common.true}"},
154           {'name' => "false", 'desc' => "{common.false}"}],
155    'deft' => "false",
156    'reqd' => "no" },
157    { 'name' => "getMaximumMetadata",
158    'desc' => "Extract the maximum technical information of each video",
159    'type' => "enum",
160    'list' => [{'name' => "true", 'desc' => "{common.true}"},
161           {'name' => "false", 'desc' => "{common.false}"}],
162    'deft' => "false",
163    'reqd' => "no" },
164
165      { 'name' => "minimumsize",
166    'desc' => "{ImageConverter.minimumsize}",
167    'type' => "int",
168    'deft' => "100",
169    'range' => "1,",
170    'reqd' => "no" },
171
172         ];
173
174my $options = { 'name' => "VideoConverter",
175        'desc' => "{VideoConverter.desc}",
176        'abstract' => "yes",
177        'inherits' => "yes",
178        'args' => $arguments };
179
180sub new {
181    my ($class) = shift (@_);
182    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
183    push(@$pluginlist, $class);
184
185    push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
186    push(@{$hashArgOptLists->{"OptList"}},$options);
187
188    my $self = new MultimediaConverter($pluginlist, $inputargs, $hashArgOptLists, 1);
189
190
191    return bless $self, $class;
192
193}
194
195
196
197
198# Discover the characteristics of a video file.
199
200#  Equivalent step to that in ImagePlugin that uses ImageMagicks's
201#  'indentify' utility
202
203#  Here we use 'MediaInfo' for video but for consistency keep the Perl
204#  method name the same as before
205
206sub mediaInfo_Inform_Cmd {
207    my ($video, $parameter, $outhandle, $verbosity) = @_;
208   
209    # Use MediaInfo CLI to get the file spec according to the requested parameter
210    my $command = "mediainfo --Inform=\"$parameter\" \"$video\"";
211
212    print $outhandle "  $command\n" if ($verbosity > 2);
213    my $result = '';
214    $result = `$command 2>&1`;
215    chomp $result;
216    print $outhandle "  $result\n" if ($verbosity > 4);
217   
218    # Return the asked spec
219    return ($result);
220}
221
222# Here we use mediaInfo to get all the possible metadata in XML form that could then be parsed
223#the result will vary depending on the file type and how it was encoded
224sub mediaInfo_XML_Cmd {
225    my ($video, $outhandle, $verbosity) = @_;
226   
227    # Use MediaInfo CLI to get the file spec according to the requested parameter
228    my $command = "mediainfo --Output=XML \"$video\"";
229   
230    print $outhandle "  $command\n" if ($verbosity > 2);
231    my $result = '';
232    $result = `$command 2>&1`;
233    print $outhandle "  $result\n" if ($verbosity > 4);
234   
235    # Return the asked spec
236    return ($result);
237}
238
239#Here we parse the video specs contained in the XML text in order to create a metadata entry for each field
240sub mediaInfo_parse_XML {
241    my ($xmlTxt, $outhandle, $verbosity) = @_;
242   
243    my @parts = split(/<track\s+type=\"(.*?)\">/is,$xmlTxt);
244   
245    shift @parts; # Skip preamble
246    my $metadata_table = {};
247   
248    while (@parts) {
249    my $type = shift(@parts);
250    my $vals = shift(@parts);
251    my @fieldlist=();
252    while ($vals =~ s/<(.*?)>(.*?)<\/\1>//) {
253        my $metaname = $1;
254        my $metaval  = $2;
255        my $fullmetaname = "mi.$type\^$metaname";
256        $metadata_table->{$fullmetaname}= $metaval;
257        push(@fieldlist,$fullmetaname);
258    }
259   
260    $metadata_table->{"mi.${type}Fields"}= join(",",@fieldlist);
261    }
262   
263    return $metadata_table;
264
265    while (@parts) {
266        my $type = shift(@parts);
267        my $vals = shift(@parts);
268        my @fieldlist=();
269        while ($vals =~ s/<(.*?)>(.*?)<\/\1>//) {
270          my $metaname = $1;
271          my $metaval  = $2;
272          my $fullmetaname = "mi.$type\^$metaname";
273          if($metaname ne "Complete_name") #ignore this field as it is pointing to the cache directory
274              {
275              $metadata_table->{$fullmetaname}= $metaval;
276              push(@fieldlist,$fullmetaname);
277              }
278        }
279        $metadata_table->{"mi.${type}Fields"}= join(",",@fieldlist);
280    }
281    return $metadata_table;
282
283}
284
285sub identifyMI {
286    my ($video, $outhandle, $verbosity) = @_;
287
288    # Use the ffmpeg command to get the file specs
289    my $command = "ffmpeg -i \"$video\"";
290
291    print $outhandle "  $command\n" if ($verbosity > 2);
292    my $result = '';
293    $result = `$command 2>&1`;
294    print $outhandle "  $result\n" if ($verbosity > 4);
295
296    # Read the type, width, and height etc.
297    # This could be done in a more efficient way by only calling the application mediainfo once and
298    # giving all the parameters then parsing the results, however on most operating system
299    # once the application is called once it is then cached for subsequent calls.
300    my $vtype =  mediaInfo_Inform_Cmd($video,"General;%Format%",$outhandle,0);
301    my $duration = mediaInfo_Inform_Cmd($video,"General;%Duration%",$outhandle,0);
302    my $durationDisplay = mediaInfo_Inform_Cmd($video,"General;%Duration/String1%",$outhandle,0);
303    my $filesize = mediaInfo_Inform_Cmd($video,"General;%FileSize/String%",$outhandle,0);
304    my $vcodec = mediaInfo_Inform_Cmd($video,"Video;%Format%",$outhandle,0);
305    my $vrate = mediaInfo_Inform_Cmd($video,"Video;%BitRate%",$outhandle,0);
306    my $width =  mediaInfo_Inform_Cmd($video,"Video;%Width%",$outhandle,0);
307    my $height = mediaInfo_Inform_Cmd($video,"Video;%Height%",$outhandle,0);
308    my $fps    = mediaInfo_Inform_Cmd($video,"Video;%FrameRate%",$outhandle,0);
309    my $atype =  mediaInfo_Inform_Cmd($video,"Audio;%Format%",$outhandle,0);
310    my $afreq =  mediaInfo_Inform_Cmd($video,"Audio;%SamplingRate/String%",$outhandle,0);
311    my $achan =  mediaInfo_Inform_Cmd($video,"Audio;%Channel(s)%",$outhandle,0);
312    my $arate =  mediaInfo_Inform_Cmd($video,"Audio;%BitRate%",$outhandle,0);
313
314    my $xmlTxt =  mediaInfo_XML_Cmd ($video,$outhandle,0);
315    my $metadata_table = mediaInfo_parse_XML($xmlTxt,$outhandle,0);
316   
317    # Return the specs
318    return ($vtype,$width,$height,$duration,$durationDisplay,$filesize,
319        $vcodec,$vrate,$fps,$atype,$afreq,$achan,$arate,$metadata_table);
320}
321
322
323sub identify {
324    my ($video, $outhandle, $verbosity) = @_;
325
326    # Use the ffmpeg command to get the file specs
327    my $command = "ffmpeg -i \"$video\"";
328
329    print $outhandle "  $command\n" if ($verbosity > 2);
330    my $result = '';
331    $result = `$command 2>&1`;
332    print $outhandle "  $result\n" if ($verbosity > 4);
333
334    # Read the type, width, and height etc.
335    my $vtype =  'unknown';
336    my $vcodec = 'unknown';
337    my $width =  'unknown';
338    my $height = 'unknown';
339    my $fps    = 'unknown';
340
341    my $atype =  'unknown';
342    my $afreq =  'unknown';
343    my $achan =  'unknown';
344    my $arate =  'unknown';
345
346    my $video_safe = quotemeta $video;
347
348    # strip off everything up to filename
349    $result =~ s/^.*\'$video_safe\'://s;
350
351##    if ($result =~ m/Video: (.*?) fps/m) {
352    if ($result =~ m/^\s+Stream.*?Video: (.*?)$/m) {
353    my $video_info = $1;
354    $video_info =~ s/\s*\[.*?\]//g;
355
356    my @video_fields = split(/,\s*/,$video_info);
357   
358    $vtype = shift @video_fields;
359
360    if ($video_fields[0] !~ m/(\d+)x(\d+)/) {
361        $vcodec = shift @video_fields;
362    }
363    my $video_dim = shift @video_fields;
364
365    ($width,$height) = ($video_dim =~ m/(\d+)x(\d+)/);
366   
367    if ($video_fields[0] =~ m/(\d+)\s+tbr$/) {
368        $fps = $1;
369    }
370
371#   if ($video_info =~ m/([^,]+),(?: ([^,]+),)? (\d+)x(\d+),.*?(\d+\.\d+)/)
372#   {
373#       $vtype = $1;
374#       $vcodec = $2 if defined $2;
375#       $width = $3;
376#       $height = $4;
377#       $fps = $5;
378#   }
379    }
380
381    if ($result =~ m/Audio: (\w+), (\d+) Hz, (\w+)(?:, (\d+.*))?/m) {
382    $atype = $1;
383    $afreq = $2;
384    $achan = $3;
385    $arate = $4 if (defined $4);
386    }
387
388    # Read the duration
389    my $duration = "unknown";
390    if ($result =~ m/Duration: (\d+:\d+:\d+\.\d+)/m) {
391    $duration = $1;
392    }
393    print $outhandle "  file: $video:\t $vtype, $width, $height, $duration\n"
394    if ($verbosity > 2);
395
396    if ($verbosity >3) {
397    print $outhandle "\t video codec=$vcodec, fps = $fps\n";
398    print $outhandle "\t audio codec=$atype, freq = $afreq Hz, $achan, $arate\n";
399    }
400
401    # Return the specs
402    return ($vtype, $width, $height, $duration, -s $video,
403        $vcodec,$fps,$atype,$afreq,$achan,$arate);
404}
405
406
407sub vob_durations
408{
409    my ($media_base_dir,$title_num,$outhandle) = @_;
410
411    my $filter_re = sprintf("^VTS_%02d_[1-9]\\.VOB\$",$title_num);
412
413    my $duration_info = {};
414
415    if (opendir(VTSIN,$media_base_dir)) {
416    my @vts_title_vobs = grep { $_ =~ m/$filter_re/ } readdir(VTSIN);
417    closedir(VTSIN);
418
419    foreach my $v (@vts_title_vobs) {
420        my $full_v = &util::filename_cat($media_base_dir,$v);
421
422        my ($vtype, $width, $height, $duration, $durationDisplay, $vsize,
423        $vcodec,$vrate,$fps,$atype,$afreq,$achan,$arate) = identify($full_v,$outhandle,0);
424
425        my ($vob_num) = ($v =~ m/^VTS_\d\d_(\d)\.VOB$/);
426
427        $duration_info->{$vob_num} = $duration;
428        print STDERR "**** $title_num: $title_num, storing {$vob_num} => $duration\n";
429
430    }
431
432    }
433    else {
434    print $outhandle "Warning: unable to read files in directory $media_base_dir\n";
435    }
436   
437    return $duration_info;
438
439}
440
441
442
443sub init_cache_for_file {
444    my $self = shift(@_);
445
446    my ($video_filename) = @_;
447
448    $self->SUPER::init_cache_for_file($video_filename);
449
450                   
451    my @flvtool2_monitor = ( 'monitor_init'   ,"convertutil::monitor_init_unbuffered",
452                 'monitor_line'   , "VideoConverter::flvtool2_monitor_line",
453                 'monitor_deinit' , "convertutil::monitor_deinit_unbuffered" );
454                   
455    $self->{'flvtool2_monitor'} = \@flvtool2_monitor;
456
457
458}
459
460
461
462sub optional_frame_scale
463{
464    my $self = shift (@_);
465    my ($orig_size,$video_width,$video_height) = @_;
466
467    my $s_opt = "";
468
469    if ($video_width > $video_height) {
470    if ($video_width > $orig_size) {
471        my $scale_factor = $orig_size/$video_width;
472        my $scaled_width = int($video_width * $scale_factor);
473        my $scaled_height = int($video_height * $scale_factor);
474
475        # round to be ensure multiple of 2 (needed by some codecs)
476        $scaled_width  = int($scaled_width/2)*2;
477        $scaled_height = int($scaled_height/2)*2;
478
479        $s_opt = "-s ${scaled_width}x${scaled_height}";
480    }
481    # else, video is smaller than requested size, don't scale up
482    }
483    else {
484    if ($video_height > $orig_size) {
485        my $scale_factor = $orig_size/$video_height;
486        my $scaled_width = int($video_width * $scale_factor);
487        my $scaled_height = int($video_height * $scale_factor);
488
489        # round to be ensure multiple of 2 (needed by some codecs)
490        $scaled_width  = int($scaled_width/2)*2;
491        $scaled_height = int($scaled_height/2)*2;
492
493        $s_opt = "-s ${scaled_width}x${scaled_height}";
494    }
495    # else, video is smaller than requested size, don't scale up
496   
497    }
498   
499    return $s_opt;
500}
501
502
503sub keyframe_cmd
504{
505    my $self = shift (@_);
506    my ($ivideo_filename) = @_;
507
508    my $video_ext_dir = &util::filename_cat($ENV{'GSDLHOME'},"ext","video");
509
510    my $output_dir = $self->{'cached_dir'};
511    my $ivideo_root = $self->{'cached_file_root'};
512
513    my $oshot_filename = &util::filename_cat($output_dir,"shots.xml");
514
515    my $exp_duration = $self->{'exp_duration'};
516    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
517
518    my $main_opts = "-y $t_opt";
519
520    my $hive = &util::filename_cat($video_ext_dir,"lib","vhook","hive.so");
521
522    my $oflash_filename = &util::filename_cat($output_dir,"$ivideo_root\_keyframe.flv");
523
524    my $vhook_opts = "$hive  -o $oshot_filename -k $output_dir $ivideo_filename";
525
526    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
527    my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
528
529    my $ffmpeg_cmd = "ffkeyframe  $main_opts -vhook \"$vhook_opts\"   -i \"$ivideo_filename_gsdlenv\" -an -y \"$oflash_filename_gsdlenv\"";
530
531
532    return ($ffmpeg_cmd,$oflash_filename);
533}
534
535sub get_ovideo_file
536{
537    my $self = shift (@_);
538    my ($stream_type) = @_;
539   
540    my $ivideo_root = $self->{'cached_file_root'};
541    my $ofile;
542   
543    if ($stream_type eq "flv")
544    {
545        $ofile = "${ivideo_root}_vstream.flv";
546    }
547    else
548    {
549        $ofile = "${ivideo_root}_vHQstream.mp4";
550    }
551   
552    return $ofile;
553}
554
555sub get_ovideo_filename
556{
557    my $self = shift (@_);
558    my ($stream_type) = @_;
559   
560    my $output_dir = $self->{'cached_dir'};
561
562    my $ofile = $self->get_ovideo_file($stream_type);
563       
564    my $ofilename = &util::filename_cat($output_dir,$ofile);
565   
566    return $ofilename;
567}
568
569# Generate the command to use with Handbrake to recompress a video using h264/aac compatible with Flash Player 10
570sub stream_mp4_video_cmd
571{
572    my $self = shift (@_);
573    my ($ivideo_filename,$streaming_HQ_size, $streaming_HQ_VideoBitrate,
574     $streaming_HQ_AudioBitrate) = @_;
575
576    my $output_dir = $self->{'cached_dir'};
577    my $ivideo_root = $self->{'cached_file_root'};
578
579    my $omp4_file = "${ivideo_root}_vHQstream.mp4";
580    my $omp4_filename = &util::filename_cat($output_dir,$omp4_file);
581
582
583    #my $exp_duration = $self->{'exp_duration'};
584    #my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
585
586    my $deinterlace = $self->{'videoDeinterlacingFilter'};
587    my $video_processing_parameters;   
588    # Use specific resizing algorythms depending if we need to downsize the video resolution or not
589    if(!$streaming_HQ_size || $streaming_HQ_size eq "fullsize") {
590        $video_processing_parameters = "--strict-anamorphic";
591    } else {
592        $video_processing_parameters = "-w $streaming_HQ_size --loose-anamorphic";
593    }
594    # Use the deinterlace video filter if enabled in the plugin
595    if ($deinterlace eq "true")
596    {
597        $video_processing_parameters .= " --decomb";
598    }
599
600    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
601    my $omp4_filename_gsdlenv = $self->gsdlhome_independent($omp4_filename);
602   
603    # Generate the pre and post video parameters for Handbrake v0.9.4
604    my $pre_opts = "-t 1 -c 1";
605    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";
606
607    my $handbrake_cmd = "HandbrakeCLI.exe -i \"$ivideo_filename_gsdlenv\" $pre_opts -o \"$omp4_filename_gsdlenv\" $post_opts";
608
609    #print STDERR "****\nHandbrake command: $handbrake_cmd\n****\n";
610   
611    return ($handbrake_cmd,$omp4_filename,$omp4_file);
612}
613
614
615
616sub stream_flv_video_cmd
617{
618    my $self = shift (@_);
619    my ($ivideo_filename,$video_width,$video_height,
620    $streaming_quality,
621    $streaming_bitrate,$streaming_size,
622    $opt_streaming_achan, $opt_streaming_arate) = @_;
623
624    my $streaming_achan
625    = (defined $opt_streaming_achan) ? $opt_streaming_achan : 2;
626
627    my $streaming_arate
628    = (defined $opt_streaming_arate) ? $opt_streaming_arate : 22050;
629
630    my $output_dir = $self->{'cached_dir'};
631    my $ivideo_root = $self->{'cached_file_root'};
632
633    my $oflash_file = "${ivideo_root}_vstream.flv";
634    my $oflash_filename = &util::filename_cat($output_dir,$oflash_file);
635
636    my $s_opt = "";
637    my $media_type = $self->{'media_type'};
638    if ($media_type ne "audio") {
639    $s_opt = $self->optional_frame_scale($streaming_size,$video_width,$video_height);
640    }
641
642
643    my $exp_duration = $self->{'exp_duration'};
644    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
645
646    my $main_opts = "-y $t_opt";
647
648    my $bitrate_opt = "-b $streaming_bitrate";
649    ### my $stream_opts = "-r 25 $s_opt";
650    my $stream_opts .= " $s_opt -ac $streaming_achan -ar $streaming_arate";
651
652    # -flags +ilme+ildct' and maybe '-flags +alt' for interlaced material, and try '-top 0/1'
653
654    my $all_opts = "$main_opts $stream_opts";
655
656    my $ffmpeg_cmd;
657
658    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
659    my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
660
661    if ($streaming_quality eq "high") {
662
663    my $pass_log_file = &util::filename_cat($output_dir,"$ivideo_root-logpass.txt");
664    if (-e $pass_log_file) {
665        &util::rm($pass_log_file);
666    }
667
668    my $pass_log_file_gsdlenv = $self->gsdlhome_independent($pass_log_file);
669
670    $all_opts .= " -passlogfile \"$pass_log_file_gsdlenv\"";
671
672    my $ffmpeg_cmd_pass1 = "ffmpeg -pass 1 -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
673
674    my $ffmpeg_cmd_pass2 = "ffmpeg -pass 2 -i \"$ivideo_filename_gsdlenv\" $all_opts $bitrate_opt -y \"$oflash_filename_gsdlenv\"";
675    $ffmpeg_cmd = "( $ffmpeg_cmd_pass1 && $ffmpeg_cmd_pass2 )";
676    }
677    else {
678    # single pass
679
680    $ffmpeg_cmd = "ffmpeg -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
681    }
682
683    return ($ffmpeg_cmd,$oflash_filename,$oflash_file);
684}
685
686
687
688
689sub stream_flv_audio_cmd
690{
691    # AudioConverter also has a routine for doing this
692    # => merge into one!
693    # **************
694
695    my $self = shift (@_);
696    my ($ivideo_filename, $opt_streaming_achan, $opt_streaming_arate) = @_;
697
698    # Convert either audio or video to streamable audio format
699
700    my $streaming_achan
701    = (defined $opt_streaming_achan) ? $opt_streaming_achan : 2;
702
703    my $streaming_arate
704    = (defined $opt_streaming_arate) ? $opt_streaming_arate : 22050;
705
706    my $output_dir = $self->{'cached_dir'};
707    my $ivideo_root = $self->{'cached_file_root'};
708
709    my $ofla_file = "${ivideo_root}_astream.flv";
710    my $ofla_filename = &util::filename_cat($output_dir,$ofla_file);
711
712    my $exp_duration = $self->{'exp_duration'};
713    my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
714
715    my $main_opts = "-vn -y $t_opt";
716
717    my $stream_opts .= " -ac $streaming_achan -ar $streaming_arate";
718
719    my $all_opts = "$main_opts $stream_opts";
720
721    my $ffmpeg_cmd;
722
723    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
724    my $ofla_filename_gsdlenv = $self->gsdlhome_independent($ofla_filename);
725    $ffmpeg_cmd = "ffmpeg -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$ofla_filename_gsdlenv\"";
726
727    return ($ffmpeg_cmd,$ofla_filename,$ofla_file);
728}
729
730
731
732
733sub audio_excerpt_cmd
734{
735    my $self = shift (@_);
736    my ($ivoa_filename,$hh,$mm,$ss,$opt_excerpt_len) = @_;
737
738    # ivoa = input video or audio
739
740    my $time_encoded = "$hh:$mm:$ss";
741    my $time_encoded_file = "$hh$mm$ss";
742   
743   
744    my $output_dir = $self->{'cached_dir'};
745    my $ivoa_root = $self->{'cached_file_root'};
746
747    my $omp3_file = "${ivoa_root}_$time_encoded_file.mp3";
748    my $omp3_filename = &util::filename_cat($output_dir,$omp3_file);
749
750    my $all_opts = "-y -acodec mp3 -ss $time_encoded ";
751
752    if (defined $opt_excerpt_len) {
753    $all_opts .= "-t $opt_excerpt_len ";
754    }
755
756
757    my $ivoa_filename_gsdlenv = $self->gsdlhome_independent($ivoa_filename);
758    my $omp3_filename_gsdlenv = $self->gsdlhome_independent($omp3_filename);
759
760
761    my $ffmpeg_cmd = "ffmpeg -i \"$ivoa_filename_gsdlenv\" $all_opts  \"$omp3_filename_gsdlenv\"";
762
763    return ($ffmpeg_cmd,$omp3_filename,$omp3_file);
764}
765
766
767
768sub streamseekable_cmd
769{
770    my $self = shift (@_);
771    my ($oflash_filename) = @_;
772
773    my $output_dir = $self->{'cached_dir'};
774    my $ivideo_root = $self->{'cached_file_root'};
775
776    ## my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
777
778    my $flvtool_cmd = "flvtool2 -vUP \"$oflash_filename\"";
779
780    return ($flvtool_cmd,$oflash_filename);
781}
782
783
784sub streamkeyframes_cmd
785{
786    my $self = shift (@_);
787    my ($oflash_filename,$doc_obj,$section) = @_;
788
789    my $assocfilepath
790    = $doc_obj->get_metadata_element($section,"assocfilepath");
791
792    my $output_dir = $self->{'cached_dir'};
793
794    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
795 
796    my $flvtool_cmd = "flvtool2 -vAUtP \"$cue_filename\"  \"$oflash_filename\"";
797
798    return ($flvtool_cmd,$oflash_filename);
799}
800
801
802sub streamkeyframes_cmd_old
803{
804    my $self = shift (@_);
805    my ($oflash_filename,$doc_obj,$section) = @_;
806
807    my $assocfilepath
808    = $doc_obj->get_metadata_element($section,"assocfilepath");
809
810    my $output_dir = $self->{'cached_dir'};
811
812    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
813
814    my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
815    my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
816
817    my $collect = $ENV{'GSDLCOLLECTION'};
818 
819    print STDERR "**** Warning: need to remove dependency of GEXT_VIDEO_SERVER and _PREFIX\n";
820
821    my $flvtool_cmd = "flvtool2 -vAUtP \"$cue_filename\" -thumbLocation:$video_server$video_prefix/collect/$collect/index/assoc/$assocfilepath \"$oflash_filename\"";
822
823
824    return ($flvtool_cmd,$oflash_filename);
825}
826
827
828sub streamcuepts_cmd
829{
830    my $self = shift (@_);
831    my ($oflash_filename) = @_;
832
833    my $output_dir = $self->{'cached_dir'};
834
835    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
836
837    ##my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
838    ##my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
839
840    ## my $collect = $ENV{'GSDLCOLLECTION'};
841
842    ## my $thumbloc = "$video_server$video_prefix/collect/$collect";
843
844
845#    my $flvtool_cmd = "flvtool2 -vUAtP \"$cue_filename\" -thumbLocation:$thumbloc \"$oflash_filename\"";
846
847#    my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
848
849
850
851#    my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
852
853
854##    my $flvtool_cmd = "flvtool2 -vAt \"$cue_filename\" -UP \"$oflash_filename\" \"$output_dir/updated.flv\"";
855
856##    my $flvtool_cmd = "flvtool2 -vAtU \"$cue_filename\" \"$oflash_filename\" \"$output_dir/updated.flv\"";
857
858    my $flvtool_cmd = "flvtool2 -vAtUP \"$cue_filename\" \"$oflash_filename\"";
859
860    return ($flvtool_cmd,$oflash_filename);
861}
862
863
864sub keyframe_thumbnail_cmd
865{
866    my $self = shift (@_);
867    my ($ivideo_filename,$thumbnailfile,$thumbnailwidth,$thumbnailheight) = @_;
868
869    my $output_dir = $self->{'cached_dir'};
870    my $ivideo_root = $self->{'cached_file_root'};
871
872    my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
873
874
875    # Try for 4th keyframe, but fall back to 1st if doesn't exist
876    my $key_filename = "${key_filename_prefix}_0003.jpg";
877    $key_filename = "${key_filename_prefix}_0000.jpg" if (!-e $key_filename);
878
879    my $key_filename_gsdlenv = $self->gsdlhome_independent($key_filename);
880    my $thumbnailfile_gsdlenv = $self->gsdlhome_independent($thumbnailfile);
881
882    my $command;
883
884    if (-e $key_filename) {
885    $command = "convert -interlace plane -verbose -geometry $thumbnailwidth"
886        . "x$thumbnailheight \"$key_filename_gsdlenv\" \"$thumbnailfile_gsdlenv\"";
887    }
888    else {
889    # extract_keyframe has either not been switched on, or else had
890    # a problem when running
891    # => extract a from
892    # my $frame_rate = 1.0 / 60.0;
893   
894    my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
895
896    $command = "ffmpeg -i \"$ivideo_filename_gsdlenv\"  -ss 3.5 -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -y \"$thumbnailfile_gsdlenv\"";
897
898    # fmpeg -i input.dv -r 1 -f image2 -s 120x96 images%05d.png
899    }
900
901    return ($command,$thumbnailfile);
902}
903
904
905sub keyframe_montage_cmd
906{
907    my $self = shift (@_);
908    my ($ivideo_filename,$montagefile) = @_;
909
910    my $output_dir = $self->{'cached_dir'};
911    my $ivideo_root = $self->{'cached_file_root'};
912
913    my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
914
915    my $options = "-tile 10  -geometry 75x62+2+2";
916
917    my $command = "montage $options ${key_filename_prefix}_*.jpg \"$montagefile\"";
918
919    return ($command,$montagefile);
920}
921
922
923
924sub parse_shot_xml
925{
926    my ($self) = shift(@_);
927
928    my $outhandle = $self->{'outhandle'};
929    my $output_dir = $self->{'cached_dir'};
930
931    my $shots_filename = &util::filename_cat($output_dir,"shots.xml");
932
933    eval {
934    $self->{'parser'}->parsefile($shots_filename);
935    };
936   
937    if ($@) {
938    print $outhandle "VideoConverter: skipping $shots_filename as not conformant to Hive shot syntax\n" if ($self->{'verbosity'} > 1);
939    print $outhandle "\n Perl Error:\n $@\n" if ($self->{'verbosity'}>2);
940    return 0;
941    }
942
943}
944
945sub associate_keyframes_old
946{
947    my ($self) = shift(@_);
948
949    my ($doc_obj,$section) = @_;
950
951    my $output_dir = $self->{'cached_dir'};
952
953    my $count = 1;
954    foreach my $kframe_file (@{$self->{'keyframe_fnames'}}) {
955
956    my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
957    $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
958                 $section);
959    $count++;
960    }
961
962    $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$self->{'keyframe_fnames'}}));
963
964
965    # *****
966    # $doc_obj->add_metadata ($section, "thumblist", $self->{'flowplayer_thumblist'});
967
968}
969
970sub associate_keyframes
971{
972    my ($self) = shift(@_);
973
974    my ($doc_obj,$topsection,$timeline) = @_;
975
976    my $output_dir = $self->{'cached_dir'};
977   
978    my $count = 1;
979
980    foreach my $t (sort { $timeline->{$a}->{'keyframeindex'} <=> $timeline->{$b}->{'keyframeindex'} } keys %$timeline)
981    {
982    my $kframe_file = $timeline->{$t}->{'thumb'};
983    my $timestamp = $timeline->{$t}->{'timestamp'};
984
985    # create next sub-section to video "document"
986    my $endchild = $doc_obj->insert_section($doc_obj->get_end_child($topsection));
987    $doc_obj->add_utf8_metadata($endchild,"Title","Timestamp $timestamp");
988    $doc_obj->add_utf8_metadata($endchild,"FrameNum",$t);
989
990    my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
991    $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg",
992                 "image/jpeg",
993                 $endchild);
994
995    $doc_obj->add_utf8_metadata($endchild,"assockeyframe","keyframe$count.jpg");
996
997    $doc_obj->add_utf8_metadata($topsection,"KeyframeTimestamp",$timestamp);
998    $doc_obj->add_utf8_metadata($topsection,"KeyframeFrameNum",$t);
999
1000
1001
1002    $count++;
1003    }
1004
1005    #### $doc_obj->add_utf8_metadata($topsection,"NumKeyframes",scalar(@{$self->{'keyframe_fnames'}}));
1006
1007    $doc_obj->add_utf8_metadata($topsection,"NumKeyframes",scalar(keys %$timeline));
1008
1009
1010    # *****
1011    # $doc_obj->add_metadata ($topsection, "thumblist", $self->{'flowplayer_thumblist'});
1012}
1013
1014
1015
1016sub enable_audio_streaming
1017{
1018    my $self = shift (@_);
1019    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated) = @_;
1020
1021    my $section = $doc_obj->get_top_section();
1022
1023    my $output_dir   = $self->{'cached_dir'};
1024    my $ivideo_root  = $self->{'cached_file_root'};
1025   
1026    # Generate FLV audio-only format for streaming purposes
1027
1028    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1029    if ($self->{'enable_cache'}) {
1030    $optionally_run_general_cmd
1031        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1032    }
1033
1034   
1035    my $ifilename = $originalfilename || $filename;
1036
1037    my ($stream_cmd,$ofla_filename,$ofla_file)
1038    = $self->stream_flv_audio_cmd($ifilename);
1039   
1040   
1041    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
1042                   'message_prefix' => "Stream",
1043                   'message' => "Generating streamable audio: $ofla_file" };
1044   
1045
1046    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1047    = $self->$optionally_run_general_cmd($stream_cmd,
1048                         $ifilename,$ofla_filename,
1049                         $streamable_options);
1050
1051
1052    if (!$streamable_had_error) {
1053    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($ofla_filename);
1054   
1055    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
1056                       'message_prefix' => "Stream Seekable",
1057                       'message' => "Reprocessing audio stream to be seekable by timeline: $ofla_file" };
1058   
1059    if ($streamable_regenerated) {
1060        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
1061    }
1062   
1063    my $streamable_url = $ofla_file;
1064    my $streamable_url_safe = $self->url_safe($streamable_url);
1065
1066    $doc_obj->add_utf8_metadata ($section, "streamableaudio", $streamable_url_safe);
1067    $doc_obj->associate_file($ofla_filename,$ofla_file,"audio/flash",
1068                 $section);
1069    }
1070
1071    $doc_obj->add_metadata ($section, "audioflashwidth",    400);
1072    $doc_obj->add_metadata ($section, "audioflashheight",   22 + 100);
1073
1074    $self->{'ofla_file'} = $ofla_file;
1075    $self->{'ofla_filename'} = $ofla_filename;
1076
1077    return $streamable_regenerated;
1078}
1079
1080
1081
1082
1083
1084sub enable_video_streaming
1085{
1086    my $self = shift (@_);
1087    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1088    $video_width,$video_height) = @_;
1089
1090    my $section = $doc_obj->get_top_section();
1091
1092    my $output_dir   = $self->{'cached_dir'};
1093    my $ivideo_root  = $self->{'cached_file_root'};
1094   
1095    # Generate the Flash FLV format for streaming purposes
1096
1097    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1098    if ($self->{'enable_cache'}) {
1099    $optionally_run_general_cmd
1100        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1101    }
1102
1103
1104    my $streaming_bitrate = $self->{'streamingbitrate'};
1105    my $streaming_size    = $self->{'streamingsize'};
1106   
1107    my $streaming_quality = "high";
1108   
1109    my $ifilename = $originalfilename || $filename;
1110
1111    my ($stream_cmd,$oflash_filename,$oflash_file)
1112    = $self->stream_flv_video_cmd($ifilename,
1113                     $video_width,$video_height,
1114                     $streaming_quality,
1115                     $streaming_bitrate, $streaming_size);
1116   
1117   
1118    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
1119                   'message_prefix' => "Stream",
1120                   'message' => "Generating streamable video: $oflash_file" };
1121   
1122
1123    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1124    = $self->$optionally_run_general_cmd($stream_cmd,
1125                         $ifilename,$oflash_filename,
1126                         $streamable_options);
1127   
1128    if (!$streamable_had_error) {
1129    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($oflash_filename);
1130   
1131    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
1132                       'message_prefix' => "Stream Seekable",
1133                       'message' => "Reprocessing video stream to be seekable by timeline: $oflash_file" };
1134   
1135    if ($streamable_regenerated) {
1136        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
1137    }
1138   
1139    my $streamable_url = $oflash_file;
1140    my $streamable_url_safe = $self->url_safe($streamable_url);
1141   
1142    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1143    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/flash",
1144                 $section);
1145    }
1146
1147
1148    #
1149    # FlowPlayer.swf       height+22 pixels
1150    # FlowPlayerBlack.swf  height+16 pixels
1151    # FlowPlayerThermo.swf height+16 pixels
1152    # FlowPlayerWhite.swf  height+26 pixels
1153
1154    my $flashwidth = $video_width;
1155    my $flashheight = $video_height + 22;
1156
1157    if ($self->{'extract_keyframes'}) {
1158    $flashheight += 100;
1159    }
1160
1161    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1162    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1163     
1164    $self->{'oflash_file'} = $oflash_file;
1165    $self->{'oflash_filename'} = $oflash_filename;
1166
1167    return $streamable_regenerated;
1168}
1169
1170sub enable_direct_streaming
1171{
1172    my $self = shift (@_);
1173    my ($doc_obj,$originalfilename,$filename,$file,
1174    $video_width,$video_height) = @_;
1175
1176    my $section = $doc_obj->get_top_section();
1177   
1178    my $ifilename = $originalfilename || $filename;
1179    #my $ifile = $self->gsdlhome_independent($ifilename);
1180    my $ifile = $file;
1181
1182    print STDERR "Using the original video file for direct streaming: $ifile\n";
1183
1184    my $streamable_url = $ifile;
1185    my $streamable_url_safe = $self->url_safe($streamable_url);
1186   
1187    my $outhandle = $self->{'outhandle'};
1188
1189    my ($vtype, $width, $height, $duration, $durationDisplay, $vsize,
1190        $vcodec,$vrate,$fps,$atype,$afreq,$achan,$arate,$metadata_table) = identifyMI($ifilename,$outhandle,0);
1191    #Add the most common metadata extracted by MediaInfo from the streamable video file
1192    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFormat", $vtype);
1193    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSize", $vsize);
1194    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingWidth", $width);
1195    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingHeight", $height);
1196    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDuration", $durationDisplay);
1197    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFPS", $fps);
1198    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoCodec", $vcodec);
1199    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoBitrate", $vrate);
1200    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioCodec", $atype);
1201    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioBitrate", $arate);
1202    #$doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFileBitrate", $vrate + $arate);
1203   
1204    my $get_max_metadata = $self->{'getMaximumMetadata'};
1205    if ($get_max_metadata eq "true"){
1206        foreach my $metaname(keys %$metadata_table)
1207        {
1208            my $metaval = $metadata_table->{$metaname};
1209            $doc_obj->add_utf8_metadata ($section, $metaname, $metaval);
1210        }
1211    }
1212   
1213    #add the metadata for the resulting file that should be open inside the flash video player
1214    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1215    $doc_obj->associate_file($ifilename,$ifile,"application/octet-stream",$section);
1216
1217    my $flashwidth = $video_width;
1218    my $flashheight = $video_height + 22;
1219
1220    if ($self->{'extract_keyframes'}) {
1221    $flashheight += 100;
1222    }
1223
1224    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1225    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1226     
1227    $self->{'oflash_file'} = $ifile;
1228    $self->{'oflash_filename'} = $ifilename;
1229
1230}
1231
1232
1233sub enable_h264_streaming
1234{
1235    my $self = shift (@_);
1236    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1237    $video_width,$video_height) = @_;
1238   
1239
1240    my $section = $doc_obj->get_top_section();
1241
1242    my $output_dir   = $self->{'cached_dir'};
1243    my $ivideo_root  = $self->{'cached_file_root'};
1244   
1245    # Generate the H264 video file format for streaming purposes using the cache feature if used
1246
1247    my $optionally_run_general_cmd = "run_uncached_general_cmd";
1248    if ($self->{'enable_cache'}) {
1249    $optionally_run_general_cmd
1250        = ($convertto_regenerated) ? "regenerate_general_cmd" : "run_cached_general_cmd";
1251    }
1252
1253    my $streaming_HQ_size    = $self->{'streamingHQsize'};
1254    my $streaming_HQ_VideoBitrate    = $self->{'streamingHQVideoBitrate'};
1255    my $streaming_HQ_AudioBitrate    = $self->{'streamingHQAudioBitrate'};
1256
1257    my $ifilename = $originalfilename || $filename;
1258    my ($stream_cmd,$oflash_filename,$oflash_file)
1259    = $self->stream_mp4_video_cmd($ifilename,
1260                     $streaming_HQ_size,
1261                     $streaming_HQ_VideoBitrate,
1262                     $streaming_HQ_AudioBitrate);
1263   
1264   
1265    my $streamable_options = { @{$self->{'handbrake_monitor'}},
1266                   'message_prefix' => "MP4 Stream",
1267                   'message' => "Generating streamable MP4 video: $oflash_file" };
1268   
1269
1270    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
1271    = $self->$optionally_run_general_cmd($stream_cmd,
1272                         $ifilename,$oflash_filename,
1273                         $streamable_options);
1274   
1275    if (!$streamable_had_error) {
1276
1277   
1278    my $streamable_url = $oflash_file;
1279    my $streamable_url_safe = $self->url_safe($streamable_url);
1280   
1281    my $outhandle = $self->{'outhandle'};
1282
1283    my ($vtype, $width, $height, $duration, $durationDisplay, $vsize,
1284        $vcodec,$vrate,$fps,$atype,$afreq,$achan,$arate,$metadata_table) = identifyMI($oflash_filename,$outhandle,0);
1285    #Add the most common metadata extracted by MediaInfo from the streamable video file
1286    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFormat", $vtype);
1287    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoFileSize", $vsize);
1288    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingWidth", $width);
1289    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingHeight", $height);
1290    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingDuration", $durationDisplay);
1291    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFPS", $fps);
1292    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoCodec", $vcodec);
1293    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingVideoBitrate", $vrate);
1294    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioCodec", $atype);
1295    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingAudioBitrate", $arate);
1296    $doc_obj->add_utf8_metadata ($section, "tv.HQStreamingFileBitrate", $vrate + $arate);
1297   
1298    my $get_max_metadata = $self->{'getMaximumMetadata'};
1299    if ($get_max_metadata eq "true"){
1300        foreach my $metaname(keys %$metadata_table)
1301        {
1302            my $metaval = $metadata_table->{$metaname};
1303            $doc_obj->add_utf8_metadata ($section, $metaname, $metaval);
1304        }
1305    }
1306   
1307    #add the metadata for the resulting file that should be open inside the flash video player
1308    $doc_obj->add_utf8_metadata ($section, "streamablevideo", $streamable_url_safe);
1309    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/mp4",
1310                 $section);
1311    }
1312
1313
1314
1315
1316    my $flashwidth = $video_width;
1317    my $flashheight = $video_height + 22;
1318
1319    if ($self->{'extract_keyframes'}) {
1320    $flashheight += 100;
1321    }
1322
1323    $doc_obj->add_metadata ($section, "flashwidth",    $flashwidth);
1324    $doc_obj->add_metadata ($section, "flashheight",   $flashheight);
1325     
1326    $self->{'oflash_file'} = $oflash_file;
1327    $self->{'oflash_filename'} = $oflash_filename;
1328
1329    return $streamable_regenerated;
1330   
1331   
1332}
1333
1334sub enable_full_streaming
1335{
1336    my $self = shift (@_);
1337    my ($doc_obj,$originalfilename,$filename,$convertto_regenerated,
1338    $video_width,$video_height) = @_;
1339
1340    my $video_streamable_regenerated
1341    = $self->enable_video_streaming($doc_obj,$originalfilename,$filename,
1342                    $convertto_regenerated,
1343                    $video_width,$video_height);
1344
1345    my $audio_streamable_regenerated
1346    = $self->enable_audio_streaming($doc_obj,$originalfilename,$filename,
1347                    $convertto_regenerated);
1348
1349    return ($video_streamable_regenerated || $audio_streamable_regenerated);
1350}
1351
1352
1353
1354sub flvtool2_monitor_line
1355{
1356    my ($line) = @_;
1357
1358    my $had_error = 0;
1359    my $generate_dot = 1;
1360
1361    if ($line =~ m/\s+\- /) {
1362    # ignore tabulated output printed at end of command
1363    $generate_dot = 0;
1364    }
1365   
1366    if ($line =~ m/^Error:/i) {
1367    $had_error = 1;
1368    }
1369
1370    return ($had_error,$generate_dot);
1371}
1372
1373
1374
1375
1376
13771;
Note: See TracBrowser for help on using the browser.