source: extensions/gsdl-video/trunk/perllib/plugins/MultimediaConverter.pm@ 18543

Last change on this file since 18543 was 18543, checked in by davidb, 15 years ago

Renaming of videoconvert supporting package to supporting Plugin

File size: 18.6 KB
Line 
1##########################################################################
2#
3# videoconvert.pm -- utility to help convert video file
4#
5# Copyright (C) 1999 DigiLib Systems Limited, NZ
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20#
21###########################################################################
22
23
24package videoconvert;
25
26use strict;
27no strict 'refs'; # allow filehandles to be variables and viceversa
28
29use baseconvert;
30
31sub BEGIN {
32 @videoconvert::ISA = ('baseconvert');
33}
34
35
36# Discover the characteristics of a video file.
37# Equivalent step to that in ImagePlugin that uses ImageMagicks's 'indentify' utility
38# Here we use 'ffmpeg' for video but for consistency keep the Perl method name the same
39# as before
40
41
42sub identify {
43 my ($video, $outhandle, $verbosity) = @_;
44
45 # Use the ffmpeg command to get the file specs
46 my $command = "ffmpeg -i \"$video\"";
47
48 print $outhandle " $command\n" if ($verbosity > 2);
49 my $result = '';
50 $result = `$command 2>&1`;
51 print $outhandle " $result\n" if ($verbosity > 4);
52
53 # Read the type, width, and height etc.
54 my $vtype = 'unknown';
55 my $vcodec = 'unknown';
56 my $width = 'unknown';
57 my $height = 'unknown';
58 my $fps = 'unknown';
59
60 my $atype = 'unknown';
61 my $afreq = 'unknown';
62 my $achan = 'unknown';
63 my $arate = 'unknown';
64
65 my $video_safe = quotemeta $video;
66
67 # strip off everything up to filename
68 $result =~ s/^.*\'$video_safe\'://s;
69
70 if ($result =~ m/Video: (.*?) fps/m) {
71 my $video_info = $1;
72 if ($video_info =~ m/([^,]+),(?: ([^,]+),)? (\d+)x(\d+),.*?(\d+\.\d+)/)
73 {
74 $vtype = $1;
75 $vcodec = $2 if defined $2;
76 $width = $3;
77 $height = $4;
78 $fps = $5;
79 }
80 }
81
82## if ($result =~ m/Video: (\w+), (\w+), (\d+)x(\d+),.*?(\d+\.\d+) fps/m) {
83# if ($result =~ m/Video: ([^,]+),(?: ([^,]+),)? (\d+)x(\d+),.*?(\d+\.\d+) fps/m) {
84# $vtype = $1;
85# $vcodec = $2;
86# $width = $3;
87# $height = $4;
88# $fps = $5;
89# }
90
91 if ($result =~ m/Audio: (\w+), (\d+) Hz, (\w+)(?:, (\d+.*))?/m) {
92 $atype = $1;
93 $afreq = $2;
94 $achan = $3;
95 $arate = $4 if (defined $4);
96 }
97
98 # Read the duration
99 my $duration = "unknown";
100 if ($result =~ m/Duration: (\d+:\d+:\d+\.\d+)/m) {
101 $duration = $1;
102 }
103 print $outhandle " file: $video:\t $vtype, $width, $height, $duration\n"
104 if ($verbosity > 2);
105
106 if ($verbosity >3) {
107 print $outhandle "\t video codec=$vcodec, fps = $fps\n";
108 print $outhandle "\t audio codec=$atype, freq = $afreq Hz, $achan, $arate\n";
109 }
110
111 # Return the specs
112 return ($vtype, $width, $height, $duration, -s $video,
113 $vcodec,$fps,$atype,$afreq,$achan,$arate);
114}
115
116
117sub vob_durations
118{
119 my ($media_base_dir,$title_num,$outhandle) = @_;
120
121 my $filter_re = sprintf("^VTS_%02d_[1-9]\\.VOB\$",$title_num);
122
123 my $duration_info = {};
124
125 if (opendir(VTSIN,$media_base_dir)) {
126 my @vts_title_vobs = grep { $_ =~ m/$filter_re/ } readdir(VTSIN);
127 closedir(VTSIN);
128
129 foreach my $v (@vts_title_vobs) {
130 my $full_v = &util::filename_cat($media_base_dir,$v);
131
132 my ($vtype, $width, $height, $duration, $vsize,
133 $vcodec,$fps,$atype,$afreq,$achan,$arate) = identify($full_v,$outhandle,0);
134
135 my ($vob_num) = ($v =~ m/^VTS_\d\d_(\d)\.VOB$/);
136
137 $duration_info->{$vob_num} = $duration;
138 print STDERR "**** $title_num: $title_num, storing {$vob_num} => $duration\n";
139
140 }
141
142 }
143 else {
144 print $outhandle "Warning: unable to read files in directory $media_base_dir\n";
145 }
146
147 return $duration_info;
148
149}
150
151
152
153sub new {
154 my ($class) = shift @_;
155
156 my ($base_dir,$video_filename, $verbosity,$outhandle,
157 $exp_duration,$ascii_only_filenames) = @_;
158
159 my $self = new baseconvert($base_dir,$video_filename,$verbosity,$outhandle);
160
161 $self->{'exp_duration'} = $exp_duration;
162
163 if (defined $ascii_only_filenames && ($ascii_only_filenames)) {
164 my $file_root = $self->{'file_root'};
165 $self->{'file_root'} = ascii_only_filename($file_root);
166 }
167
168 my @ffmpeg_monitor = ( 'monitor_init' , "videoconvert::ffmpeg_monitor_init",
169 'monitor_line' , "videoconvert::ffmpeg_monitor_line",
170 'monitor_deinit' , "videoconvert::ffmpeg_monitor_deinit" );
171
172 my @flvtool2_monitor = ( 'monitor_init' ,"monitor_init_unbuffered",
173 'monitor_line' , "videoconvert::flvtool2_monitor_line",
174 'monitor_deinit' , "monitor_deinit_unbuffered" );
175
176 $self->{'ffmpeg_monitor'} = \@ffmpeg_monitor;
177 $self->{'flvtool2_monitor'} = \@flvtool2_monitor;
178
179
180 return bless $self, $class;
181}
182
183
184sub ascii_only_filename
185{
186 my ($file) = @_;
187
188 my $file_unicode = pack("U0C*", map { ord($_) } split(//,$file)); # force explicitly to unicode
189
190 my @ascii_only_chars
191 = map { $_ >= 128 # if non-ascii
192 ? ""
193 : chr($_) } unpack("U*", $file_unicode); # unpack Unicode characters
194
195 my $ascii_file = join("",@ascii_only_chars);
196
197 if ($ascii_file eq "") {
198 print STDERR "Warning: filename includes no ASCII characters\n";
199 print STDERR " Keeping as original filename\n";
200 $ascii_file = $file;
201 }
202
203 return $ascii_file;
204}
205
206
207sub remove_difficult_chars
208{
209 my $self = shift @_;
210
211 my ($file) = @_;
212
213 # remove problematic characters from filename that make using it in a URL difficult
214
215 my $file_unicode = pack("U0C*", map { ord($_) } split(//,$file)); # force explicitly to unicode
216
217 my $url = $file_unicode;
218 $url =~ s/\x{2018}|\x{2019}|\x{201C}|\x{201D}//g; # remove smart quotes as cause problem in URL for video server
219 $url =~ s/\x{2013}/\-/g; # change en-dash to '-' as again causes problems for video server
220
221 return $url;
222}
223
224
225sub url_safe
226{
227 my $self = shift @_;
228
229 my ($file) = @_;
230
231 my @url_utf8_chars
232 = map { $_ >= 128 # if non-ascii
233 ? "%" . sprintf("%02X", $_)
234 : chr($_) } unpack("U*", $file); # unpack Unicode characters
235
236 my $url = join("",@url_utf8_chars);
237
238
239 return $url;
240}
241
242
243
244sub gsdlhome_independent
245{
246 my $self = shift @_;
247 my ($filename) = @_;
248
249 my $gsdlhome = $ENV{'GSDLHOME'};
250 my $filename_gsdlenv = $filename;
251 $filename_gsdlenv =~ s@^$gsdlhome@\$GSDLHOME@;
252
253 return $filename_gsdlenv;
254}
255
256
257
258sub optional_frame_scale
259{
260 my $self = shift (@_);
261 my ($orig_size,$video_width,$video_height) = @_;
262
263 my $s_opt = "";
264 if ($video_width > $video_height) {
265 if ($video_width > $orig_size) {
266 my $scale_factor = $orig_size/$video_width;
267 my $scaled_width = int($video_width * $scale_factor);
268 my $scaled_height = int($video_height * $scale_factor);
269
270 # round to be ensure multiple of 2 (needed by some codecs)
271 $scaled_width = int($scaled_width/2)*2;
272 $scaled_height = int($scaled_height/2)*2;
273
274 $s_opt = "-s ${scaled_width}x${scaled_height}";
275 }
276 # else, video is smaller than requested size, don't scale up
277 }
278 else {
279 if ($video_height > $orig_size) {
280 my $scale_factor = $orig_size/$video_height;
281 my $scaled_width = int($video_width * $scale_factor);
282 my $scaled_height = int($video_height * $scale_factor);
283
284 # round to be ensure multiple of 2 (needed by some codecs)
285 $scaled_width = int($scaled_width/2)*2;
286 $scaled_height = int($scaled_height/2)*2;
287
288 $s_opt = "-s ${scaled_width}x${scaled_height}";
289 }
290 # else, video is smaller than requested size, don't scale up
291
292 }
293
294 return $s_opt;
295}
296
297
298sub keyframe_cmd
299{
300 my $self = shift (@_);
301 my ($ivideo_filename) = @_;
302
303 my $video_ext_dir = &util::filename_cat($ENV{'GSDLHOME'},"ext","video");
304
305 my $output_dir = $self->{'cached_dir'};
306 my $ivideo_root = $self->{'file_root'};
307
308 my $oshot_filename = &util::filename_cat($output_dir,"shots.xml");
309
310 my $exp_duration = $self->{'exp_duration'};
311 my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
312
313 my $main_opts = "-y $t_opt";
314
315 my $hive = &util::filename_cat($video_ext_dir,"lib","vhook","hive.so");
316
317 my $oflash_filename = &util::filename_cat($output_dir,"$ivideo_root\_keyframe.flv");
318
319 my $vhook_opts = "$hive -o $oshot_filename -k $output_dir $ivideo_filename";
320
321 my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
322 my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
323
324 my $ffmpeg_cmd = "ffkeyframe $main_opts -vhook \"$vhook_opts\" -i \"$ivideo_filename_gsdlenv\" -an -y \"$oflash_filename_gsdlenv\"";
325
326
327 return ($ffmpeg_cmd,$oflash_filename);
328}
329
330
331sub stream_cmd
332{
333 my $self = shift (@_);
334 my ($ivideo_filename,$video_width,$video_height,
335 $streaming_quality,
336 $streaming_bitrate,$streaming_size,
337 $opt_streaming_achan, $opt_streaming_arate) = @_;
338
339 my $streaming_achan
340 = (defined $opt_streaming_achan) ? $opt_streaming_achan : 2;
341
342 my $streaming_arate
343 = (defined $opt_streaming_arate) ? $opt_streaming_arate : 22050;
344
345 my $output_dir = $self->{'cached_dir'};
346 my $ivideo_root = $self->{'file_root'};
347
348 my $oflash_file = "${ivideo_root}_stream.flv";
349 my $oflash_filename = &util::filename_cat($output_dir,$oflash_file);
350
351 my $s_opt = $self->optional_frame_scale($streaming_size,$video_width,$video_height);
352
353 my $exp_duration = $self->{'exp_duration'};
354 my $t_opt = (defined $exp_duration) ? "-t $exp_duration" : "";
355
356 my $main_opts = "-y $t_opt";
357
358 my $bitrate_opt = "-b $streaming_bitrate";
359 ### my $stream_opts = "-r 25 $s_opt";
360 my $stream_opts .= " $s_opt -ac $streaming_achan -ar $streaming_arate";
361
362 # -flags +ilme+ildct' and maybe '-flags +alt' for interlaced material, and try '-top 0/1'
363
364 my $all_opts = "$main_opts $stream_opts";
365
366 my $ffmpeg_cmd;
367
368 my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
369 my $oflash_filename_gsdlenv = $self->gsdlhome_independent($oflash_filename);
370
371 if ($streaming_quality eq "high") {
372
373 my $pass_log_file = &util::filename_cat($output_dir,"$ivideo_root-logpass.txt");
374 if (-e $pass_log_file) {
375 &util::rm($pass_log_file);
376 }
377
378 my $pass_log_file_gsdlenv = $self->gsdlhome_independent($pass_log_file);
379
380 $all_opts .= " -passlogfile \"$pass_log_file_gsdlenv\"";
381
382 my $ffmpeg_cmd_pass1 = "ffmpeg -pass 1 -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
383
384 my $ffmpeg_cmd_pass2 = "ffmpeg -pass 2 -i \"$ivideo_filename_gsdlenv\" $all_opts $bitrate_opt -y \"$oflash_filename_gsdlenv\"";
385 $ffmpeg_cmd = "( $ffmpeg_cmd_pass1 ; $ffmpeg_cmd_pass2 )";
386 }
387 else {
388 # single pass
389
390 $ffmpeg_cmd = "ffmpeg -i \"$ivideo_filename_gsdlenv\" $all_opts -y \"$oflash_filename_gsdlenv\"";
391 }
392
393 return ($ffmpeg_cmd,$oflash_filename,$oflash_file);
394}
395
396
397
398sub audio_excerpt_cmd
399{
400 my $self = shift (@_);
401 my ($ivoa_filename,$hh,$mm,$ss,$opt_excerpt_len) = @_;
402
403 # ivoa = input video or audio
404
405 my $time_encoded = "$hh:$mm:$ss";
406 my $time_encoded_file = "$hh$mm$ss";
407
408
409 my $output_dir = $self->{'cached_dir'};
410 my $ivoa_root = $self->{'file_root'};
411
412 my $omp3_file = "${ivoa_root}_$time_encoded_file.mp3";
413 my $omp3_filename = &util::filename_cat($output_dir,$omp3_file);
414
415 my $all_opts = "-y -acodec mp3 -ss $time_encoded ";
416
417 if (defined $opt_excerpt_len) {
418 $all_opts .= "-t $opt_excerpt_len ";
419 }
420
421
422 my $ivoa_filename_gsdlenv = $self->gsdlhome_independent($ivoa_filename);
423 my $omp3_filename_gsdlenv = $self->gsdlhome_independent($omp3_filename);
424
425
426 my $ffmpeg_cmd = "ffmpeg -i \"$ivoa_filename_gsdlenv\" $all_opts \"$omp3_filename_gsdlenv\"";
427
428 return ($ffmpeg_cmd,$omp3_filename,$omp3_file);
429}
430
431
432
433sub streamseekable_cmd
434{
435 my $self = shift (@_);
436 my ($oflash_filename) = @_;
437
438 my $output_dir = $self->{'cached_dir'};
439 my $ivideo_root = $self->{'file_root'};
440
441 my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
442
443 my $flvtool_cmd = "flvtool2 -vUP \"$oflash_filename\"";
444
445 return ($flvtool_cmd,$oflash_filename);
446}
447
448
449sub streamkeyframes_cmd
450{
451 my $self = shift (@_);
452 my ($oflash_filename,$doc_obj,$section) = @_;
453
454 my $assocfilepath
455 = $doc_obj->get_metadata_element($section,"assocfilepath");
456
457 my $output_dir = $self->{'cached_dir'};
458
459 my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
460
461 my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
462 my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
463
464 my $collect = $ENV{'GSDLCOLLECTION'};
465
466 my $flvtool_cmd = "flvtool2 -vAUtP \"$cue_filename\" -thumbLocation:$video_server$video_prefix/collect/$collect/index/assoc/$assocfilepath \"$oflash_filename\"";
467
468
469 return ($flvtool_cmd,$oflash_filename);
470}
471
472
473sub streamcuepts_cmd
474{
475 my $self = shift (@_);
476 my ($oflash_filename) = @_;
477
478 my $output_dir = $self->{'cached_dir'};
479
480 my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
481
482 my $video_server = $ENV{'GEXT_VIDEO_SERVER'};
483 my $video_prefix = $ENV{'GEXT_VIDEO_PREFIX'};
484
485 my $collect = $ENV{'GSDLCOLLECTION'};
486 my $thumbloc = "$video_server$video_prefix/collect/$collect";
487
488
489# my $flvtool_cmd = "flvtool2 -vUAtP \"$cue_filename\" -thumbLocation:$thumbloc \"$oflash_filename\"";
490
491# my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
492
493
494
495# my $flvtool_cmd = "flvtool2 -vUAt \"$cue_filename\" \"$oflash_filename\"";
496
497
498## my $flvtool_cmd = "flvtool2 -vAt \"$cue_filename\" -UP \"$oflash_filename\" \"$output_dir/updated.flv\"";
499
500## my $flvtool_cmd = "flvtool2 -vAtU \"$cue_filename\" \"$oflash_filename\" \"$output_dir/updated.flv\"";
501
502 my $flvtool_cmd = "flvtool2 -vAtUP \"$cue_filename\" \"$oflash_filename\"";
503
504 return ($flvtool_cmd,$oflash_filename);
505}
506
507
508sub keyframe_thumbnail_cmd
509{
510 my $self = shift (@_);
511 my ($ivideo_filename,$thumbnailfile,$thumbnailwidth,$thumbnailheight) = @_;
512
513 my $output_dir = $self->{'cached_dir'};
514 my $ivideo_root = $self->{'file_root'};
515
516 my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
517
518
519 # Try for 4th keyframe, but fall back to 1st if doesn't exist
520 my $key_filename = "${key_filename_prefix}_0003.jpg";
521 $key_filename = "${key_filename_prefix}_0000.jpg" if (!-e $key_filename);
522
523 my $key_filename_gsdlenv = $self->gsdlhome_independent($key_filename);
524 my $thumbnailfile_gsdlenv = $self->gsdlhome_independent($thumbnailfile);
525
526 my $command;
527
528 if (-e $key_filename) {
529 $command = "convert -interlace plane -verbose -geometry $thumbnailwidth"
530 . "x$thumbnailheight \"$key_filename_gsdlenv\" \"$thumbnailfile_gsdlenv\"";
531 }
532 else {
533 # extractkeyframe has either not been switched on, or else had
534 # a problem when running
535 # => extract a from
536 # my $frame_rate = 1.0 / 60.0;
537
538 my $ivideo_filename_gsdlenv = $self->gsdlhome_independent($ivideo_filename);
539
540
541
542 $command = "ffmpeg -i \"$ivideo_filename_gsdlenv\" -ss 12.5 -vframes 1 -f image2 -s ${thumbnailwidth}x${thumbnailheight} -y \"$thumbnailfile_gsdlenv\"";
543
544 # fmpeg -i input.dv -r 1 -f image2 -s 120x96 images%05d.png
545 }
546
547 return ($command,$thumbnailfile);
548}
549
550
551sub keyframe_montage_cmd
552{
553 my $self = shift (@_);
554 my ($ivideo_filename,$montagefile) = @_;
555
556 my $output_dir = $self->{'cached_dir'};
557 my $ivideo_root = $self->{'file_root'};
558
559 my $key_filename_prefix = &util::filename_cat($output_dir,$ivideo_root);
560
561 my $options = "-tile 10 -geometry 75x62+2+2";
562
563 my $command = "montage $options ${key_filename_prefix}_*.jpg \"$montagefile\"";
564
565 return ($command,$montagefile);
566}
567
568
569
570sub parse_shot_xml
571{
572 my ($self) = shift(@_);
573
574 my ($plugin) = @_;
575
576 my $outhandle = $self->{'outhandle'};
577 my $output_dir = $self->{'cached_dir'};
578
579 my $shots_filename = &util::filename_cat($output_dir,"shots.xml");
580
581 eval {
582 $plugin->{'parser'}->parsefile($shots_filename);
583 };
584
585 if ($@) {
586 print $outhandle "videoconvert.pm: skipping $shots_filename as not conformant to Hive shot syntax\n" if ($self->{'verbosity'} > 1);
587 print $outhandle "\n Perl Error:\n $@\n" if ($self->{'verbosity'}>2);
588 return 0;
589 }
590
591}
592
593sub associate_keyframes_old
594{
595 my ($self) = shift(@_);
596
597 my ($doc_obj,$section,$plugin) = @_;
598
599 my $output_dir = $self->{'cached_dir'};
600
601 my $count = 1;
602 foreach my $kframe_file (@{$plugin->{'keyframe_fnames'}}) {
603
604 my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
605 $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
606 $section);
607 $count++;
608 }
609
610 $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$plugin->{'keyframe_fnames'}}));
611
612
613 # *****
614 # $doc_obj->add_metadata ($section, "thumblist", $plugin->{'flowplayer_thumblist'});
615
616}
617
618sub associate_keyframes
619{
620 my ($self) = shift(@_);
621
622 my ($doc_obj,$section,$plugin) = @_;
623
624 my $output_dir = $self->{'cached_dir'};
625 my $timeline = $plugin->{'keyframe_timeline'};
626
627 my $count = 1;
628
629 foreach my $t (sort { $timeline->{$a}->{'keyframeindex'} <=> $timeline->{$b}->{'keyframeindex'} } keys %$timeline)
630 {
631 my $kframe_file = $timeline->{$t}->{'thumb'};
632 my $timestamp = $timeline->{$t}->{'timestamp'};
633
634 my $kframe_filename = &util::filename_cat($output_dir,$kframe_file);
635 $doc_obj->associate_file($kframe_filename,"keyframe$count.jpg","image/jpeg",
636 $section);
637 $doc_obj->add_utf8_metadata($section,"KeyframeTimestamp",$timestamp);
638
639 $count++;
640 }
641
642 $doc_obj->add_utf8_metadata($section,"NumKeyframes",scalar(@{$plugin->{'keyframe_fnames'}}));
643
644
645 # *****
646 # $doc_obj->add_metadata ($section, "thumblist", $plugin->{'flowplayer_thumblist'});
647}
648
649
650
651sub ffmpeg_monitor_init
652{
653 my $saved_record_sep = $/;
654 $/ = "\r";
655
656 my $saved_buffer_len = $|;
657 $| = 1;
658
659 my $saved_rec = { 'saved_record_sep' => $saved_record_sep,
660 'saved_buffer_len' => $saved_buffer_len };
661
662 return $saved_rec;
663}
664
665
666
667sub ffmpeg_monitor_deinit
668{
669 my ($saved_rec) = @_;
670
671 my $saved_record_sep = $saved_rec->{'saved_record_sep'};
672 my $saved_buffer_len = $saved_rec->{'saved_buffer_len'};
673
674 $/ = $saved_record_sep;
675 $| = $saved_buffer_len;
676}
677
678
679sub ffmpeg_monitor_line
680{
681 my ($line) = @_;
682
683 my $had_error = 0;
684 my $generate_dot = 0;
685
686 if ($line =~ m/^frame=/)
687 {
688 $generate_dot = 1;
689 }
690
691 return ($had_error,$generate_dot);
692}
693
694
695sub flvtool2_monitor_line
696{
697 my ($line) = @_;
698
699 my $had_error = 0;
700 my $generate_dot = 1;
701
702 if ($line =~ m/\s+\- /) {
703 # ignore tabulated output printed at end of command
704 $generate_dot = 0;
705 }
706
707 if ($line =~ m/^Error:/i) {
708 $had_error = 1;
709 }
710
711 return ($had_error,$generate_dot);
712}
713
714
715
716
717
7181;
Note: See TracBrowser for help on using the repository browser.