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

Last change on this file since 23292 was 23292, checked in by max, 13 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).

File size: 40.9 KB
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 repository browser.