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

Last change on this file since 19785 was 19785, checked in by davidb, 13 years ago

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

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