root/extensions/gsdl-video/trunk/perllib/plugins/TimedHTMLPlugin.pm @ 19785

Revision 19785, 24.3 KB (checked in by davidb, 10 years ago)

General improvements to processing audio and for TIMEDHTMLPLugin to process files that have been edited by OpenOffice?

Line 
1###########################################################################
2#
3# TimedHTMLPlug.pm --
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) 1999 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###########################################################################
26
27
28package TimedHTMLPlugin;
29
30use HTMLPlugin;
31use VideoConverter;
32
33sub BEGIN {
34    @TimedHTMLPlugin::ISA = ('HTMLPlugin', 'VideoConverter');
35}
36
37
38use strict; # every perl program should have this!
39no strict 'refs'; # make an exception so we can use variables as filehandles
40
41my $arguments =
42    [
43      { 'name' => "video_excerpt_duration",
44    'desc' => "{VideoPlug.video_excerpt_duration}",
45    'type' => "string",
46    'reqd' => "no" }
47      ];
48
49
50
51
52my $options = { 'name'     => "TimedHTMLPlugin",
53        'desc'     => "{TimedHTMLPlugin.desc}",
54        'abstract' => "no",
55        'inherits' => "yes",
56            'args'     => $arguments };
57
58
59sub new {
60    my ($class) = shift (@_);
61    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
62    push(@$pluginlist, $class);
63   
64    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
65    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
66   
67    new VideoConverter($pluginlist, $inputargs, $hashArgOptLists);
68   
69    my $self = (defined $hashArgOptLists)
70    ? new HTMLPlugin($pluginlist,$inputargs,$hashArgOptLists)
71    : new HTMLPlugin($pluginlist,$inputargs);
72 
73    my $collect_dir = $ENV{'GSDLCOLLECTDIR'};
74
75    my $collect_bin = &util::filename_cat($collect_dir,"bin");
76    my $collect_script = &util::filename_cat($collect_bin,"script");
77   
78    $ENV{'PATH'} .= ":" if (defined $ENV{'PATH'});
79    $ENV{'PATH'} .= "$collect_bin:$collect_script";
80
81    return bless $self, $class;
82}
83
84sub begin {
85    my $self = shift (@_);
86    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
87
88    $self->SUPER::begin(@_);
89    $self->VideoConverter::begin(@_);
90}
91
92
93sub init {
94    my $self = shift (@_);
95    my ($verbosity, $outhandle, $failhandle) = @_;
96
97    $self->SUPER::init(@_);
98    $self->VideoConverter::init(@_);
99}
100
101
102sub html_to_text
103{
104    my ($self, $text) = @_;
105
106    $text =~ s/<\/?[^>]*>//g;
107
108    $text =~ s/&nbsp;/ /g;
109
110    $text =~ s/\s+/ /gs;
111    $text =~ s/^\s+//;
112    $text =~ s/\s+$//;
113
114    return $text;
115}
116
117
118sub extract_metadata_table
119{
120    my ($self, $textref) = @_;
121
122    my $metatable_store = {};
123
124    my $metatable_re = "<table([^>]*)>(.*?<p[^>]+class=\"?Metadata\"?[^>]*>.*?)<\\/table>";
125
126    if ($$textref =~ m/$metatable_re/gsi) {
127    my $metatable_attr = $1;
128    my $metatable_body = $2;
129
130    my @tr_list = ($metatable_body =~ m/(<tr[^>]*>.*?<\/tr>)/gsi);
131
132    my @filtered_tr_list = ();
133
134    foreach my $tr (@tr_list) {
135
136        my $in_filtered_tr = 1;
137
138        my @td_list = ($tr =~ m/<td[^>]*>(.*?)<\/td>/gsi);
139        my $td_list_num = scalar(@td_list);
140       
141        if ($td_list_num == 2) {
142        my $meta_name  = $self->html_to_text($td_list[0]);
143        my $meta_value = $self->html_to_text($td_list[1]);
144       
145        $meta_name =~ s/\s*//g;
146       
147
148        if ($meta_value =~ m/^(\s*|\?+)$/) {
149            $in_filtered_tr = 0;
150        }
151        else {
152            my $meta_name_label = $meta_name;
153            $meta_name_label =~ s/\s+//g;
154
155            $metatable_store->{$meta_name_label} = $meta_value;
156
157            if ($meta_name_label =~ m/^GS\./) {
158            # even though we want to store this as metadata, we
159            # don't want this going into table presented at top of document
160            $in_filtered_tr = 0;
161            }
162
163        }
164        }
165        else {
166        print STDERR "Warning: Metadata table does not consist of two cells (metadata name : metadata value)\n";
167        print STDERR "         Skipping\n";
168        }
169
170
171        if ($in_filtered_tr) {
172        push(@filtered_tr_list,$tr);
173        }
174    }
175
176    my $filtered_tr_block = join("\n",@filtered_tr_list);
177    my $filtered_table = "<table$metatable_attr>$filtered_tr_block</table>";
178
179
180    ### my $metatable_re = "<table[^>]*>.*?<p class=\"?Metadata\"?>.*?<\\/table>";
181
182### print STDERR "*** filtered table = $filtered_table\n";
183
184    $$textref =~ s/$metatable_re/$filtered_table/si;
185   
186    }
187
188    return $metatable_store;
189
190}
191
192
193
194
195
196my $only_num = 0;
197my $only_limit = 100;
198
199sub hms_to_secs
200{
201    my $self = shift @_;
202    my ($hh,$mm,$ss) = @_;
203
204    return $hh*3600 + $mm*60 + $ss;
205}
206
207
208
209sub timed_event
210{
211    my $self = shift (@_);
212
213    my ($front, $tape, $hh, $mm, $ss, $back) = @_;
214
215    my $time_encoded = "$hh:$mm:$ss";
216    my $time_encoded_file = "$hh$mm$ss";
217
218    print STDERR "***** time endocde = $time_encoded\n";
219
220    my $time_pos = $self->{'time_pos'};
221    my $time_num = scalar(@{$self->{'time_seq'}});
222
223####    my $videoconvert = $self->{'videoconvert'};
224
225    # excerpt from tim_pos -> time_pos + 2;
226    my $adv_time_pos = $time_pos+2;
227    $adv_time_pos = $time_num-1 if ($adv_time_pos>=$time_num);
228
229    my $adv_time_elem = $self->{'time_seq'}->[$adv_time_pos];
230
231#    print STDERR "*** ", substr($adv_time_elem,0,800), "\n";
232
233    my ($atape,$ah,$am,$as) = ($adv_time_elem =~ m/(T\d+:) ?(\d\d):(\d\d):(\d\d)(?:\:\d\d)?/);
234
235    my $excerpt_len = undef;
236    my $time_in_secs     = $self->hms_to_secs($hh,$mm,$ss);
237
238    if (!defined $tape) {
239    if (defined $self->{'ptape'}) {
240        $tape = $self->{'ptape'};
241    }
242    else {
243        print STDERR "Warning: First time offset does not define tape side\n";
244        print STDERR "         Defaulting to 1\n";
245        $tape = "T1:";
246    }
247    }
248
249    if (!defined $atape) {
250    $atape = "T1";
251    }
252
253#    print STDERR "**** atape = $atape\n";
254#    print STDERR "*** tape = $tape\n";
255
256    if ($atape eq $tape) {
257    my $adv_time_in_secs = $self->hms_to_secs($ah,$am,$as);
258
259    $excerpt_len = $adv_time_in_secs - $time_in_secs;
260    }
261
262    my $collect_dir = $ENV{'GSDLCOLLECTDIR'};
263
264    my $media_type = $self->{'media_type'};
265    my $media_dir  = $self->{'media_dir'};
266    my $media_root = $self->{'media_root'};
267
268    my $media_base_dir = $self->{'media_base_dir'};
269
270    my $mp3_html;   
271    my $avi_html;
272
273    my $tape_num = "1";
274
275    if (defined $media_type) {
276
277    my $src_file;
278    my $src_filename;
279
280    if ($media_type eq "video") {
281        $src_file = "$media_root\_01_$tape_num.VOB";
282        $src_filename
283        = &util::filename_cat($media_base_dir, $src_file);
284    }
285    elsif ($media_type =~ m/^audio$/) {
286        $src_file = "$media_root\_Tape$tape_num.mp3";
287        $src_filename
288        = &util::filename_cat($media_base_dir, $src_file);
289    }
290    else {
291        print STDERR "Warning: Unrecognised media type: $media_type\n";
292    }
293
294
295    # Embed link to allow video to stream from marked time event
296    if ($media_type eq "video") {
297
298        # video excerpt
299           
300        $avi_html .= "<a class=\"mm\" href=\"javascript:videoplayerseek($hh,$mm,$ss)\"><img border=1 src=\"_httpvideoimages_/ivideo.gif\"></a>";
301
302        # save 'time-stamp' as metadata???         
303
304    }
305   
306    # Do similar for audio.
307    #   Obviously, pure audio needs to be handled here, but also
308    #   video (and link in to its audio track)
309
310    if ($media_type =~ m/^(video|audio)$/) {
311
312       
313        my ($voa_root) = ($src_file =~ m/^(.*)\..*?$/);
314   
315        my $mp3_url = "javascript:audioplayerseek($hh,$mm,$ss)";
316        $mp3_html = "<a class=\"mm\" href=\"$mp3_url\"><img border=1 src=\"_httpvideoimages_/iaudio.gif\"></a>";
317
318#       my $baseexcerpt_url = "_httpcollection_/index/assoc/{If}{[assocfilepath],[assocfilepath],[parent(Top):assocfilepath]}";
319       
320        }
321    }
322    else {
323    print STDERR "Warning: no media type defined.\n";
324    }
325
326
327    $only_num++;
328
329    $self->{'time_pos'}++;
330
331    my $table = "<table width=\"100%\" cellspacing=\"1\" cellpadding=\"0\"><tr valign=\"middle\">";
332    $table .= "<td>$avi_html</td>" if (defined $avi_html);
333    $table .= "<td>$mp3_html</td>";
334    $table .= "<td>$time_encoded</td>";
335    $table .= "</tr></table>";
336
337    # my $line = "$front$avi_html&nbsp;$mp3_html&nbsp;$time_encoded$back";
338
339    my $line = "$front$table$back";
340
341    # Remember tape prefix for next call
342    $self->{'ptape'} = $tape;
343
344    return $line;
345}
346
347
348sub hyperlink_timing_info
349{
350    my ($self, $textref) = @_;
351
352    my $media_type = $self->{'media_type'};
353    my $media_dir  = $self->{'media_dir'};
354    my $media_root = $self->{'media_root'};
355
356
357
358    ##my $front_re = "<p class=Timing>(?:<span\\s+.*?>)?";
359    my $front_re = "<p[^>]+class=\"?Timing(?:-.*?)?\"?[^>]*>(?:<span\\s+.*?>)?";
360    my $tape_re  = "T\\d+:";
361    my $tt_re = "\\d\\d";
362    my $back_re = ".*?(?:<\\/span>\\s*)?(?:<\\/p>)";
363
364    my $time_match_re = "$front_re$tt_re:$tt_re:$tt_re$back_re(?:\:$tt_re)?";
365    # my $time_sub_re   = "($front_re)($tape_re)? ?($tt_re):($tt_re):($tt_re)(?:\:$tt_re)?($back_re)";
366
367    my $tape_match_re   = "$front_re($tape_re)? ?$tt_re:$tt_re:$tt_re(?:\:$tt_re)?$back_re";
368    my $tape_sub_re   = "($front_re)($tt_re):($tt_re):($tt_re)(?:\:$tt_re)?($back_re)";
369
370
371
372    my @time_seq = ($$textref =~ m/$time_match_re/sgi);
373
374    print STDERR "***** got ", scalar(@time_seq), " matches\n";
375
376    # artifically add tape information into all time indexes
377    my $extrapolate_tape = "";
378    my $num_seq = scalar(@time_seq);
379    for (my $i=0; $i<$num_seq; $i++) {
380    my ($curr_tape) = ($time_seq[$i] =~ m/$tape_match_re/sgi);
381    if (!defined $curr_tape) {
382        $time_seq[$i] =~ s/$tape_sub_re/$1$extrapolate_tape$2:$3:$4$5/sgi;
383    }
384    else {
385        if ($curr_tape ne $extrapolate_tape) {
386        $extrapolate_tape = $curr_tape;
387        }
388    }
389    }
390
391
392    $self->{'time_seq'} = \@time_seq;
393    $self->{'time_pos'} = 0;
394
395    # my $front_re = "<p[^>]+class=\"?Timing(?:-.*?)?\"?[^>]*>(?:<span\\s+.*?>)?";
396
397    $$textref =~ s/($front_re)(T\d+:)? ?(\d\d):(\d\d):(\d\d)(?:\:\d\d)?.*?((?:<\/span>)?\s*<\/p>)/$self->timed_event($1,$2,$3,$4,$5,$6)/sgie;
398
399    ##$$textref =~ s/(<p class=Timing><span\s+.*?>)(T\d+:)? ?(\d\d):(\d\d):(\d\d)(?:\:\d\d)?.*?(<\/span>)/$self->timed_event($1,$2,$3,$4,$5,$6)/sgie;
400
401
402    # knock out any div tags as they interfere with document broken up into sections
403    $$textref =~ s/<\/?div.*?>//gi;
404
405    # Embedded word style infomation is lost by HTMLPlug => make Question
406    # style use HTML italics
407
408    $$textref =~ s/<p class=\"Question\">(.*?)<\/p>/<p><i>$1<\/i><\/p>/gsi;
409
410}
411
412
413
414sub store_block_files
415{
416    my $self =shift (@_);
417    my ($filename_full_path, $block_hash) = @_;
418
419    # Would be better if this were tied to particular HTML docs that
420    # this plugin has processed.
421
422    # For now block all files native to DVD format
423
424    if (($filename_full_path =~ m/\.(IFO|BUP)$/)        # block info and backup-info data
425    || ($filename_full_path =~ m/VIDEO_TS\..*?$/)   # block top-level files
426    || ($filename_full_path =~ m/VTS_\d\d_\d\.VOB$/) #
427    ) {
428   
429    $block_hash->{'file_blocks'}->{$filename_full_path} = 1;
430    }
431}
432
433sub read_block {
434    my $self = shift (@_); 
435 
436    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
437
438    print STDERR "***** TimedHTMLPlugin read_block\n";
439
440    my $filename = $file;
441    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
442
443    if (($filename =~ m/\.(IFO|BUP)$/)        # block info and backup-info data
444    || ($filename =~ m/VIDEO_TS\..*?$/)   # block top-level files
445    || ($filename =~ m/VTS_\d\d_\d\.VOB$/) #
446    ) {
447    $self->{'num_blocked'} ++;
448    return (0,undef); # blocked
449    }
450
451
452#####   || ($filename =~ m/VTS_\d\d_0\.VOB$/) # block menu item for this track
453
454
455    if (defined $self->{'file_blocks'}->{$filename} && $self->{'file_blocks'}->{$filename} == 1){
456    $self->{'num_blocked'} ++;
457    return (0,undef); # blocked
458    }
459
460
461    if (defined $self->{'re_file_block'}) {
462    my $re_file_blocks = $self->{'re_file_block'};
463    foreach my $re_file_block (@$re_file_blocks) {
464###     print STDERR "**** re file block: $filename =~ m $re_file_block\n";
465        if ($filename =~ m/$re_file_block/) {
466###     print STDERR "*** blocking $filename\n";
467
468        $self->{'num_blocked'} ++;
469        return (0,undef); # blocked
470        }
471    }
472    }
473
474
475    return $self->SUPER::read_block(@_);
476
477}
478
479
480sub read_file {
481    my $self = shift @_;
482    my ($filename, $encoding, $language, $textref) = @_;
483
484    $only_num = 0;
485
486    $self->SUPER::read_file(@_);
487
488    my $metatable_store = $self->extract_metadata_table($textref);
489    $self->{'metatable_store'} = $metatable_store;
490
491    my ($root, $dirname, $suffix)
492        = &File::Basename::fileparse($filename, "\\.[^\\.]+\$");
493   
494    # media defaults
495    my $media_type = undef;
496    my $media_dir  = $root;
497    ## my $media_root = "VTS_%02d_%02d";
498    my $media_root = "VTS";
499
500    if (defined $metatable_store->{'GS.Media'}) {
501    $media_type = $metatable_store->{'GS.Media'};
502    $media_type = lc($media_type);
503    }
504    if (defined $metatable_store->{'GS.MediaDirectory'}) {
505    $media_dir = $metatable_store->{'GS.MediaDirectory'};
506    }
507    if (defined $metatable_store->{'GS.MediaRoot'}) {
508    $media_root = $metatable_store->{'GS.MediaRoot'};
509    }
510
511    $self->{'media_type'} = $media_type;
512    $self->{'media_dir'}  = $media_dir;
513    $self->{'media_root'} = $media_root;
514
515    my $media_base_dir = &util::filename_cat($dirname,$media_dir);
516    $self->{'media_base_dir'} = $media_base_dir;
517
518    $self->{'vob_duration_info'} = &VideoConverter::vob_durations($media_base_dir,"1",$self->{'outhandle'});
519
520##    $self->hyperlink_timing_info($textref);
521
522    # Convert entities to their UTF8 equivalents
523    $$textref =~ s/&(lt|gt|amp|quot|nbsp);/&z$1;/go;
524    $$textref =~ s/&([^;]+);/&ghtml::getcharequiv($1,1)/gseo;
525    $$textref =~ s/&z(lt|gt|amp|quot|nbsp);/&$1;/go;
526}
527
528
529sub streamable_video
530{
531    my $self = shift (@_);
532
533    my ($base_dir,$filename,$doc_obj,$section) = @_;
534
535    my $outhandle = $self->{'outhandle'};
536    my $verbosity = $self->{'verbosity'};
537
538    my $media_base_dir = $self->{'media_base_dir'};
539
540    #---
541    # Determine size of input video
542
543    my $collect_dir = $ENV{'GSDLCOLLECTDIR'};
544
545    my $media_type = $self->{'media_type'};
546    my $media_dir  = $self->{'media_dir'};
547    my $media_root = $self->{'media_root'};
548
549    my $tape_num = "1";
550
551    my $src_file;
552    my $src_filename;
553
554    if ($media_type eq "video") {
555    $src_file = "$media_root\_01_$tape_num.VOB";
556    $src_filename
557        = &util::filename_cat($media_base_dir, $src_file);
558    }
559    elsif ($media_type =~ m/^audio$/) {
560    $src_file = "$media_root\_Tape$tape_num.mp3";
561    $src_filename
562        = &util::filename_cat($media_base_dir, $src_file);
563    }
564    else {
565    print STDERR "Warning: Unrecognised media type: $media_type\n";
566    }
567
568    if (-e $src_filename) {
569    $self->{'file_blocks'}->{$src_filename} = 1;
570
571    my $re_file_block = $src_filename;
572    $re_file_block =~ s/_01_$tape_num.VOB$/_\\d+_\\d+.VOB\$/;
573   
574   
575    push(@{$self->{'re_file_block'}},$re_file_block);
576    }
577
578    my ($video_type, $video_width, $video_height, $video_duration, $video_size,
579    $vcodec,$vfps,$atype,$afreq,$achan,$arate)
580    = &VideoConverter::identify($src_filename, $outhandle, $verbosity);
581
582    if ($vfps eq "unknown") {
583    print $outhandle "Unknown framerate, defaulting to 25 frames per second.\n";
584    $vfps = 25;
585    }
586
587###    print STDERR "*** video duration = $video_duration\n";
588    my ($dur_hour,$dur_min,$dur_sec)
589    = ($video_duration =~ m/(\d+):(\d+):(\d+\.\d+)/);
590    my $total_dur_secs = $dur_hour*3600 + $dur_min*60 + $dur_sec;
591
592    $self->{'video-fps'} = $vfps;
593    $self->{'num-total-frames'} = $total_dur_secs * $vfps;
594
595
596    # shorten duration prcessed for experimentation purposes
597    my $exp_duration = undef;
598
599    my $video_excerpt_duration = $self->{'video_excerpt_duration'};
600
601    print STDERR "**** video/audio duration (secs) = $total_dur_secs\n";
602
603
604    if ((defined $video_excerpt_duration) && ($video_excerpt_duration ne "")) {
605    $exp_duration = $video_excerpt_duration;
606    my ($hh,$mm,$ss,$ms) = ($exp_duration =~ m/^(\d\d):(\d\d):(\d\d)\.?(\d\d)?/);
607    my $excerpt_dur_in_secs = $hh * 3600 + $mm * 60 + $ss;
608
609    if ($excerpt_dur_in_secs < $total_dur_secs) {
610        $self->{'num-total-frames'} = $excerpt_dur_in_secs * $vfps; # override calculation for full length duration
611    }
612    else {
613        # clip is already shorter than requested video excerpt duration
614        # set exp_duration back to undefined
615        $exp_duration = undef;
616    }
617    }
618
619    print $outhandle "TimedHTMLPlug: Preparing video files associated with $filename for HTMLPlug\n";
620
621    if (defined $exp_duration)
622    {
623    print $outhandle "Only encoding first $exp_duration of video.\n";
624    $self->{'exp_duration'} = $exp_duration;
625    }
626
627   
628###    my $videoconvert
629### = new videoconvert($base_dir,$src_filename,$verbosity,$outhandle,$exp_duration);
630###    $self->{'videoconvert'} = $videoconvert;
631# ******
632
633    $self->init_cache_for_file($src_filename);
634
635    #---
636    # Generate the Flash FLV format for streaming purposes
637
638    my $streaming_bitrate = "256k"; # used to be 192k
639    my $streaming_size    = "360"; # used to be 352 (CIF?)
640    my $streaming_achan   = "1";
641    my $streaming_arate   = "44100";
642    my $streaming_quality = "high";
643
644    #---
645    # Convert video to flash
646    #---
647    my ($stream_cmd,$oflash_filename,$oflash_file)
648    = $self->stream_cmd($src_filename,
649                $video_width,$video_height,
650                $streaming_quality, $streaming_bitrate, $streaming_size,
651                $streaming_achan, $streaming_arate);
652
653    my $streamable_options = { @{$self->{'ffmpeg_monitor'}},
654                   'message_prefix' => "Stream",
655                   'message' => "Generating streamable video: $oflash_file" };
656
657    my ($streamable_regenerated,$streamable_result,$streamable_had_error)
658    = $self->run_cached_general_cmd($stream_cmd,$oflash_filename,$streamable_options);
659
660    $self->{'streamable_regenerated'} = $streamable_regenerated;
661
662    if (!$streamable_had_error) {
663    #---
664    # Make video seekable
665    #---
666    my ($streamseekable_cmd,$ostreamseekable_filename) = $self->streamseekable_cmd($oflash_filename);
667   
668    my $streamseekable_options = { @{$self->{'flvtool2_monitor'}},
669                       'message_prefix' => "Stream Seekable",
670                       'message' => "Reprocessing video stream to be seekable by timeline: $oflash_file" };
671
672    if ($streamable_regenerated) {
673        $self->run_general_cmd($streamseekable_cmd,$streamseekable_options);
674    }
675
676    my $streamable_url = $oflash_file;
677##  $streamable_url =~ s/ /%20/g;
678
679    $doc_obj->add_metadata ($section, "streamablevideo", $streamable_url);
680    $doc_obj->associate_file($oflash_filename,$oflash_file,"video/flash",
681                 $section);
682    }
683
684    #
685    # FlowPlayer.swf       height+22 pixels
686    # FlowPlayerBlack.swf  height+16 pixels
687    # FlowPlayerThermo.swf height+16 pixels
688    # FlowPlayerWhite.swf  height+26 pixels
689    if ($media_type eq "audio") {
690    $doc_obj->add_metadata ($section, "flashwidth",    $video_width);
691    $doc_obj->add_metadata ($section, "flashheight",   22 + 100);
692    }
693    else {
694    $doc_obj->add_metadata ($section, "flashwidth",    $video_width);
695    $doc_obj->add_metadata ($section, "flashheight",   $video_height + 22 + 100);
696    }
697
698   
699    my $base_url = "_httpstreamserverprefix_/collect/[collection]/index/assoc/{If}{[assocfilepath],[assocfilepath],[parent(Top):assocfilepath]}/";
700
701    $doc_obj->add_metadata ($section, "baseurl",$base_url);
702   
703    $self->{'oflash_file'} = $oflash_file;
704    $self->{'oflash_filename'} = $oflash_filename;
705
706}
707
708
709
710sub add_cuepoints
711{
712    my ($self) = shift @_;
713    my ($doc_obj) = @_;
714
715    my $section = $doc_obj->get_top_section();
716    my $chapters = $doc_obj->get_children($section);
717
718
719    # open file
720    my $output_dir = $self->{'cached_dir'};
721    my $cue_filename = &util::filename_cat($output_dir,"on_cue.xml");
722
723    open(CUEOUT,">$cue_filename")
724    || die "Unable to open $cue_filename: $!\n";
725    print CUEOUT "<tags>\n";
726
727
728    my $cc = 0;
729
730    foreach my $chap (@$chapters)
731    {
732    $cc++;
733
734    my $chap_text = $doc_obj->get_text($chap);
735
736    my @cuepoints
737        = ($chap_text =~ m/<p class=Timing><span\s+.*?>(?:T\d+:)? ?(\d\d:\d\d:\d\d)(?:\:\d\d)?/gsi);
738
739    my $count = 0;
740
741    foreach my $cuepoint (@cuepoints)
742    {       
743        my ($hh,$mm,$ss) = ($cuepoint =~ m/(\d\d):(\d\d):(\d\d)/);
744
745        my $cuept_insecs = $self->hms_to_secs($hh,$mm,$ss);
746
747        if ($cuept_insecs < 2) {
748        $cuept_insecs += 2;
749        }
750        my $cuept_inmsecs = 1000 * $cuept_insecs;
751       
752        $doc_obj->add_metadata($section,"cuepoint",$cuept_inmsecs);
753        my $chap_title = $doc_obj->get_metadata_element($chap,"Title");
754
755        # Navigation point (used in seeking)
756#       print CUEOUT "  <metatag event=\"onCuePoint\" overwrite=\"true\">\n";
757#       print CUEOUT "    <name>$chap_title</name>\n";
758#       print CUEOUT "    <timestamp>$cuept_inmsecs</timestamp>\n";
759#       print CUEOUT "    <parameters>\n";
760#       print CUEOUT "      <thumb>dummy</thumb>\n";
761#       print CUEOUT "      <sectionnum>$chap</sectionnum>\n";
762#       print CUEOUT "      <subsectionnum>$count</subsectionnum>\n";
763#       print CUEOUT "      <cuept>$cuept_inmsecs</cuept>\n";
764#       print CUEOUT "    </parameters>\n";
765#       print CUEOUT "    <type>navigation</type>\n";
766#       print CUEOUT "  </metatag>\n";
767
768
769#       print CUEOUT "  <metatag event=\"onCuePoint\" overwrite=\"true\">\n";
770#       print CUEOUT "    <name>$chap_title</name>\n";
771#       print CUEOUT "    <timestamp>$cuept_inmsecs</timestamp>\n";
772#       print CUEOUT "    <parameters>\n";
773#       print CUEOUT "      <thumb>foo.jpg</thumb>\n";
774#       print CUEOUT "    </parameters>\n";
775#       print CUEOUT "    <type>navigation</type>\n";
776#       print CUEOUT "  </metatag>\n";
777
778        if ($count==0)
779        {
780        # Event (used to hook in to javascipt callback)
781        # Only do for the first in each chapter
782
783        print CUEOUT "  <metatag event=\"onCuePoint\" overwrite=\"true\">\n";
784##      print CUEOUT "    <name>Test $cc</name>\n";
785        print CUEOUT "    <name>$chap_title</name>\n";
786        print CUEOUT "    <timestamp>$cuept_inmsecs</timestamp>\n";
787        print CUEOUT "    <parameters>\n";
788        print CUEOUT "      <cuept>$cuept_inmsecs</cuept>\n";
789        print CUEOUT "      <sectionnum>$chap</sectionnum>\n";
790        print CUEOUT "    </parameters>\n";
791        print CUEOUT "    <type>event</type>\n";
792##      print CUEOUT "    <type>actionscript</type>\n";
793        print CUEOUT "  </metatag>\n";
794        }
795
796        $count++;
797    }
798    }
799
800
801    print CUEOUT "</tags>\n";
802    close(CUEOUT);
803
804####    my $videoconvert = $self->{'videoconvert'};
805    my $oflash_filename = $self->{'oflash_filename'};
806    my $oflash_file = $self->{'oflash_file'};
807
808    my ($streamcuepts_cmd,$ostreamcuepts_filename) = $self->streamcuepts_cmd($oflash_filename);
809
810    my $verbosity = $self->{'verbosity'};
811    my $outhandle = $self->{'outhandle'};
812
813    my $streamcuepts_options = { @{$self->{'flvtool2_monitor'}},
814                 'message_prefix' => "Stream Cue Points",
815                 'message' => "Reprocessing video stream to add cuepoints on timeline: $oflash_file" };
816
817    my $streamable_regenerated = $self->{'streamable_regenerated'};
818
819    if ($streamable_regenerated) {
820    $self->run_general_cmd($streamcuepts_cmd,$streamcuepts_options);
821    }
822
823   
824
825}
826
827
828
829sub process {
830    my $self = shift (@_);
831    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
832
833    my $filename = $file;
834    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
835
836    my $top_section = $doc_obj->get_top_section();
837
838    $self->streamable_video($base_dir,$filename,$doc_obj,$top_section);
839
840    $self->hyperlink_timing_info($textref);
841
842    foreach my $mp3_excerpt (@{$self->{'mp3_excerpts'}}) {
843    my $omp3_file = $mp3_excerpt->{'omp3_file'};
844    my $omp3_filename = $mp3_excerpt->{'omp3_filename'};
845
846    $doc_obj->associate_file($omp3_filename,$omp3_file,"audio/mp3",
847                 $top_section);
848    }
849    $self->{'mp3_excerpts'} = undef;
850
851    my $metatable_store = $self->{'metatable_store'};
852    foreach my $metaname (keys %$metatable_store) {
853    my $metadata = $metatable_store->{$metaname};
854    $doc_obj->add_metadata($top_section,$metaname,$metadata);
855    }
856    $self->{'metatable_store'} = undef;
857
858    my $ret_val = $self->SUPER::process(@_);
859
860    $self->add_cuepoints($doc_obj);
861
862
863    return $ret_val;
864
865}
866
867
868
869sub replace_images {
870    my $self = shift (@_);
871    my ($front, $link, $back, $base_dir,
872    $file, $doc_obj, $section) = @_;
873
874    if ($link =~ m/^"?_.*?_"?\//) {
875    # variety of greenstone macro, so let through unchanged
876    return $front . $link . $back ;
877    }
878
879    return $self->SUPER::replace_images(@_);
880}
881
882
883
884
885
886sub replace_href_links {
887    my $self = shift (@_);
888    my ($front, $link, $back, $base_dir, $file, $doc_obj, $section) = @_;
889
890
891    if ($link =~ m/^"?_.*?_"?/) {
892    # variety of greenstone macro, so let through unchanged
893    return $front . $link . $back ;
894    }
895
896    return $self->SUPER::replace_href_links(@_);
897}
898
8991;
Note: See TracBrowser for help on using the browser.