1 /* the base video control JSON object with default attributes
2 * for supported attribute details see README
6 "loading_plugin" : "loading plugin <blink>...<\/blink>",
7 "select_playback" : "Set playback preference",
8 "link_back" : "Link back",
9 "error_load_lib" : "Error: mv_embed was unable to load required JavaScript libraries.\nInsert script via DOM has failed. Please try reloading this page.",
10 "error_swap_vid" : "Error: mv_embed was unable to swap the video tag for the mv_embed interface",
11 "add_to_end_of_sequence" : "Add to end of sequence",
12 "missing_video_stream" : "The video file for this stream is missing",
13 "play_clip" : "Play clip",
14 "pause_clip" : "Pause clip",
15 "volume_control" : "Volume control",
16 "player_options" : "Player options",
17 "closed_captions" : "Close captions",
18 "player_fullscreen" : "Fullscreen",
19 "next_clip_msg" : "Play next clip",
20 "prev_clip_msg" : "Play previous clip",
21 "current_clip_msg" : "Continue playing this clip",
22 "seek_to" : "Seek to",
23 "download_segment" : "Download selection:",
24 "download_full" : "Download full video file:",
25 "download_right_click" : "To download, right click and select <i>Save target as...<\/i>",
26 "download_clip" : "Download video",
27 "download_text" : "Download text (<a style=\"color:white\" title=\"cmml\" href=\"http:\/\/wiki.xiph.org\/index.php\/CMML\">CMML<\/a> xml):",
28 "download" : "Download",
30 "credits" : "Credits",
31 "clip_linkback" : "Clip source page",
32 "chose_player" : "Choose video player",
33 "share_this_video" : "Share this video",
34 "video_credits" : "Video credits",
36 "close_btn" : "Close",
37 "mv_ogg-player-vlc-mozilla" : "VLC plugin",
38 "mv_ogg-player-videoElement" : "Native Ogg video support",
39 "mv_ogg-player-vlc-activex" : "VLC ActiveX",
40 "mv_ogg-player-oggPlugin" : "Generic Ogg plugin",
41 "mv_ogg-player-quicktime-mozilla" : "Quicktime plugin",
42 "mv_ogg-player-quicktime-activex" : "Quicktime ActiveX",
43 "mv_ogg-player-cortado" : "Java Cortado",
44 "mv_ogg-player-flowplayer" : "Flowplayer",
45 "mv_ogg-player-selected" : " (selected)",
46 "mv_ogg-player-omtkplayer" : "OMTK Flash Vorbis",
47 "mv_generic_missing_plugin" : "You browser does not appear to support the following playback type: <b>$1<\/b><br \/>Visit the <a href=\"http:\/\/commons.wikimedia.org\/wiki\/Commons:Media_help\">Playback Methods<\/a> page to download a player.<br \/>",
48 "mv_for_best_experience" : "For a better video playback experience we recommend:<br \/><b><a href=\"http:\/\/www.mozilla.com\/en-US\/firefox\/upgrade.html?from=mwEmbed\">Firefox 3.5<\/a>.<\/b>",
49 "mv_do_not_warn_again" : "Dissmiss for now.",
50 "playerselect" : "Players"
53 var default_video_attributes
= {
70 //roe url (for xml based metadata)
72 //if roe includes metadata tracks we can expose a link to metadata
73 "show_meta_link":true,
75 //default state attributes per html5 spec:
76 //http://www.whatwg.org/specs/web-apps/current-work/#video)
78 "readyState":0, //http://www.whatwg.org/specs/web-apps/current-work/#readystate
79 "currentTime":0, //current playback position (should be updated by plugin)
80 "duration":null, //media duration (read from file or the temporal url)
83 "startOffset":null, //if serving an ogg_chop segment use this to offset the presentation time
85 //custom attributes for mv_embed:
91 "type":null //the content type of the media
94 * the base source attibute checks
96 var mv_default_source_attr
= new Array(
100 'URLTimeEncoding', //boolean if we support temporal url requests on the source media
108 //set the dismissNativeWarn flag:
109 _global
['dismissNativeWarn'] = false;
124 default_menu_item
:'download',
125 getControls:function( embedObj
){
126 js_log('f:controlsBuilder:: opt:');
127 this.id
= (embedObj
.pc
)?embedObj
.pc
.pp
.id
:embedObj
.id
;
128 this.available_width
= embedObj
.playerPixelWidth();
129 //make pointer to the embedObj
130 this.embedObj
= embedObj
;
132 for(var i
in embedObj
.supports
){
133 _this
.supports
[i
] = embedObj
.supports
[i
];
136 //check for close_captions tracks:
137 if( ( embedObj
.roe
|| embedObj
.timedTextSources() )
138 && embedObj
.show_meta_link
)
139 this.supports
['closed_captions']=true;
142 for( var i
in this.components
){
143 if( this.supports
[i
] ){
144 if( this.available_width
> this.components
[i
].w
){
145 //special case with playhead don't add unless we have 60px
146 if( i
== 'play_head' && ctrlBuilder
.available_width
< 60 )
148 o
+=this.components
[i
].o();
149 this.available_width
-= this.components
[i
].w
;
151 js_log('not enough space for control component:' + i
);
159 * to be run once controls are attached to the dom
161 addControlHooks:function( embedObj
){
162 //add in drag/seek hooks:
163 if(!embedObj
.base_seeker_slider_offset
&& $j('#mv_seeker_slider_'+embedObj
.id
).get(0))
164 embedObj
.base_seeker_slider_offset
= $j('#mv_seeker_slider_'+embedObj
.id
).get(0).offsetLeft
;
166 //js_log('looking for: #mv_seeker_slider_'+embedObj.id + "\n " +
167 // 'start sec: '+embedObj.start_time_sec + ' base offset: '+embedObj.base_seeker_slider_offset);
169 var $tp
=$j('#' + embedObj
.id
);
171 //@todo: which object is being play()'d (or whatever) ?
172 //We select the element to attach the event to this way:
173 //$tp.find('.ui-icon-play').parent().click(function(){alert(0)}); or we can give the button itself a class - probably better.
175 //add play hook for play-btn and large_play_button
176 $tp
.find('.play-btn,.play-btn-large').unbind().btnBind().click(function(){
177 $j('#' + embedObj
.id
).get(0).play();
179 //add recomend firefox if non-native playback:
180 if( embedObj
.doNativeWarningCheck() ){
181 $j('#dc_'+ embedObj
.id
).hover(
183 if($j('#gnp_' + embedObj
.id
).length
==0){
184 $j(this).append('<div id="gnp_' + embedObj
.id
+ '" class="ui-state-highlight ui-corner-all" ' +
185 'style="position:absolute;display:none;background:#FFF;top:10px;left:10px;right:10px;height:60px;">' +
186 gM('mv_for_best_experience') +
187 '<br><input id="ffwarn_'+embedObj
.id
+'" type=\"checkbox\">' +
188 gM('mv_do_not_warn_again') +
190 $j('#ffwarn_'+embedObj
.id
).click(function(){
191 if( $j(this).is(':checked') ){
192 //set up a cookie for 5 days:
193 $j
.cookie('dismissNativeWarn', true, { expires
: 5 });
194 //set the current instance
195 _global
['dismissNativeWarn'] = true;
196 $j('#gnp_' + embedObj
.id
).fadeOut('slow');
198 _global
['adismissNativeWarn'] = false;
199 $j
.cookie('dismissNativeWarn', false);
204 if( ($j
.cookie('dismissNativeWarn') !== true) &&
205 _global
['dismissNativeWarn'] === false ){
206 $j('#gnp_' + embedObj
.id
).fadeIn('slow');
210 $j('#gnp_' + embedObj
.id
).fadeOut('slow');
215 if( $j
.browser
.msie
&& $j
.browser
.version
<= 6){
216 $j('#big_play_link_' + embedObj
.id
).pngFix();
220 $j('#timed_text_' + embedObj
.id
).unbind().btnBind().click(function(){
221 $j('#' + embedObj
.id
).get(0).showTextInterface();
225 $j('#options_button_' + embedObj
.id
).unbind().btnBind().click(function(){
226 $j('#' +embedObj
.id
).get(0).doOptionsHTML();
229 //fullscreen binding:
230 $j('#fullscreen_'+embedObj
.id
).unbind().btnBind().click(function(){
231 $j('#' +embedObj
.id
).get(0).fullscreen();
234 js_log(" should add slider binding: " + $j('#mv_play_head_'+embedObj
.id
).length
) ;
235 // $j('#mv_play_head_'+embedObj.id).slider({
236 $tp
.find( '.j-scrubber' ).slider({
241 start: function(event
, ui
){
242 var id
= (embedObj
.pc
!=null)?embedObj
.pc
.pp
.id
:embedObj
.id
;
243 embedObj
.userSlide
=true;
244 $j('#big_play_link_'+id
).fadeOut('fast');
245 //if playlist always start at 0
246 embedObj
.start_time_sec
= (embedObj
.instanceOf
== 'mvPlayList')?0:
247 npt2seconds(embedObj
.getTimeReq().split('/')[0]);
249 slide: function(event
, ui
) {
250 var perc
= ui
.value
/1000;
251 embedObj
.jump_time
= seconds2npt( parseFloat( parseFloat(embedObj
.getDuration()) * perc
) + embedObj
.start_time_sec
);
252 //js_log('perc:' + perc + ' * ' + embedObj.getDuration() + ' jt:'+ this.jump_time);
253 embedObj
.setStatus( gM('seek_to')+' '+embedObj
.jump_time
);
254 //update the thumbnail / frame
255 if(embedObj
.isPlaying
==false){
256 embedObj
.updateThumbPerc( perc
);
259 change:function(event
, ui
){
260 //only run the onChange event if done by a user slide:
261 if(embedObj
.userSlide
){
262 embedObj
.userSlide
=false;
263 embedObj
.seeking
=true;
264 //stop the monitor timer (if we can)
265 if(embedObj
.stopMonitor
)
266 embedObj
.stopMonitor();
268 var perc
= ui
.value
/1000;
269 //set seek time (in case we have to do a url seek)
270 embedObj
.seek_time_sec
= npt2seconds( embedObj
.jump_time
, true );
271 js_log('do jump to: '+embedObj
.jump_time
+ ' perc:' +perc
+ ' sts:' + embedObj
.seek_time_sec
);
272 embedObj
.doSeek(perc
);
276 //@todo: identify problem with volume button jumping...
277 $tp
.find('.k-volume-slider').slider({
282 slide: function(event
, ui
) {
283 embedObj
.updateVolumen(ui
.value
/100);
285 change: function(event
, ui
){
286 var level
= ui
.value
/100;
288 $tp
.find('.k-volume span').addClass('ui-icon-volume-off');
290 $tp
.find('.k-volume span').removeClass('ui-icon-volume-off');
292 //only run the onChange event if done by a user slide:
293 if(embedObj
.userSlide
){
294 embedObj
.userSlide
=false;
295 embedObj
.seeking
=true;
296 // var perc = ui.value/100;
297 embedObj
.updateVolumen(level
);
301 //up the z-index of the default status indicator:
302 // $j('#mv_play_head_'+embedObj.id + ' .ui-slider-handle').css('z-index', 4);
303 // $j('#mv_play_head_'+embedObj.id + ' .ui-slider-range').addClass('ui-corner-all').css('z-index', 2);
304 //extended class list for jQuery ui themeing (we can probably refactor this with custom buffering highliter)
305 $j('#' + embedObj
.id
+ ' .j-scrubber').prepend( ctrlBuilder
.getMvBufferHtml() );
308 //adds options and bindings: (we do this onClick for faster vidoe tag startup times)
309 var addMvOptions = function(){
310 if($j('#' + embedObj
.id
+ ' .k-menu').length
!= 0 )
313 $j('#' + embedObj
.id
).prepend( ctrlBuilder
.components
['mv_embedded_options'].o( embedObj
) );
315 //by default its hidden:
316 $tp
.find('.k-menu').hide();
319 for(i
=0; i
< ctrlBuilder
.menu_items
.length
; i
++){
320 $tp
.find('.k-' + ctrlBuilder
.menu_items
[i
] + '-btn').click(function(){
321 var mk
= $j(this).attr('rel');
322 $target
= $j('#' + embedObj
.id
+ ' .menu-'+mk
).hide();
323 //gennerate the menu html not already done:
324 if( $target
.children().length
== 0 ){
325 //call the function show{Menuitem} with target:
326 embedObj
['show' + mk
.charAt(0).toUpperCase() + mk
.substring(1)](
327 $j('#' + embedObj
.id
+ ' .menu-'+mk
)
330 //slide out the others
331 $j('#' + embedObj
.id
+ ' .menu-screen').hide();
332 $target
.fadeIn("fast");
333 //don't follow the # link
339 //options menu display:
340 $tp
.find('.k-options').click(function(){
341 if($j('#' + embedObj
.id
+ ' .k-menu').length
== 0 )
344 var $ktxt
= $j(this).find('.ui-icon-k-menu');
345 var $kmenu
= $tp
.find('.k-menu');
346 if( $kmenu
.is(':visible') ){
347 $kmenu
.fadeOut("fast",function(){
348 $ktxt
.html ( gM('menu_btn') );
350 $tp
.find('.play-btn-large').fadeIn('fast');
352 $kmenu
.fadeIn("fast", function(){
353 $ktxt
.html ( gM('close_btn') );
355 $tp
.find('.play-btn-large').fadeOut('fast');
360 $tp
.find('.k-volume').unbind().btnBind().click(function(){
364 var hoverOverDelay
=false;
365 /*$j('#volume_control_'+embedObj.id).unbind().btnBind().click(function(){
366 $j('#' +embedObj.id).get(0).toggleMute();
370 $j('#vol_container_' + embedObj.id).addClass('vol_container_top');
371 //set to "below" if playing and embedType != native
372 if(embedObj && embedObj.isPlaying() && !embedObj.supports['overlays']){
373 $j('#vol_container_' + embedObj.id).removeClass('vol_container_top').addClass('vol_container_below');
376 $j('#vol_container_' + embedObj.id).fadeIn('fast');
377 hoverOverDelay = true;
380 hoverOverDelay= false;
381 setTimeout(function doHideVolume(){
383 $j('#vol_container_' + embedObj.id).fadeOut('fast');
389 $j('#volume_bar_'+embedObj.id).slider({
390 orientation: "vertical",
395 slide: function(event, ui) {
396 var perc = ui.value/100;
397 //js_log('update volume:' + perc);
398 embedObj.updateVolumen(perc);
400 change:function(event, ui){
401 var perc = ui.value/100;
403 $j('#volume_control_'+embedObj.id + ' span').removeClass('ui-icon-volume-on').addClass('ui-icon-volume-off');
405 $j('#volume_control_'+embedObj.id + ' span').removeClass('ui-icon-volume-off').addClass('ui-icon-volume-on');
407 //only run the onChange event if done by a user slide:
408 if(embedObj.userSlide){
409 embedObj.userSlide=false;
410 embedObj.seeking=true;
411 var perc = ui.value/100;
412 embedObj.updateVolumen(perc);
418 getMvBufferHtml:function(){
419 return '<div class="ui-slider-horizontal ui-corner-all ui-slider-buffer" />';
428 'mv_embedded_options':{
430 'o':function( embedObj
){
432 '<div class="k-menu ui-widget-content" ' +
433 'style="width:' + embedObj
.playerPixelWidth() + 'px; height:' + embedObj
.playerPixelHeight() + 'px;">' +
434 '<ul class="k-menu-bar">';
435 //output menu item containers:
436 for(i
=0; i
< ctrlBuilder
.menu_items
.length
; i
++){
437 var mk
= ctrlBuilder
.menu_items
[i
];
438 o
+= '<li class="k-' + mk
+ '-btn" rel="'+mk
+'">' +
439 '<a href="#" title="' + gM( mk
) +'">' + gM( mk
) +'</a></li>';
442 //we have to substract the width of the k-menu-bar
443 '<div class="k-menu-screens" style="width:' + ( embedObj
.playerPixelWidth() -75) +
444 'px; height:' + (embedObj
.playerPixelHeight() - ctrlBuilder
.height
) + 'px;">';
446 //output menu item containers:
447 for(i
=0; i
< ctrlBuilder
.menu_items
.length
; i
++){
448 o
+= '<div class="menu-screen menu-' + ctrlBuilder
.menu_items
[i
] + '"></div>';
459 return '<button class="play-btn ui-state-default ui-corner-all" title="' +
460 gM('play_clip') + '" ><span class="ui-icon ui-icon-play"></span></button>'
463 'play_head':{ // scrubber
464 'w':0, //special case (takes up remaining space)
466 return '<div class="ui-slider ui-slider-horizontal ui-corner-all j-scrubber"' +
467 ' style="width:' + ( ctrlBuilder
.available_width
- 30 ) + 'px;"></div>'
473 return '<div class="k-timer">' + seconds2npt ( ctrlBuilder
.embedObj
.getDuration() ) + '</div>';
479 return '<button class="ui-state-default ui-corner-all k-volume">' +
480 '<span class="ui-icon ui-icon-volume-on"></span>' +
482 '<div class="ui-slider ui-slider-horizontal k-volume-slider"></div>';
484 //vertical volume control:
485 /* return '<div title="' + gM('volume_control') + '" id="volume_control_'+ctrlBuilder.id+'" class="ui-state-default ui-corner-all ui-icon_link rButton">' +
486 '<span class="ui-icon ui-icon-volume-on"></span>' +
487 '<div style="position:absolute;display:none;" id="vol_container_'+ctrlBuilder.id+'" class="vol_container ui-corner-all">' +
488 '<div class="volume_bar" id="volume_bar_' + ctrlBuilder.id + '"></div>' +
497 return '<div title="' + gM('closed_captions') + '" id="timed_text_' + ctrlBuilder
.id
+'" ' +
498 'class="ui-state-default ui-corner-all ui-icon_link rButton">' +
499 '<span class="ui-icon ui-icon-comment"></span></div>';
505 return '<button class="ui-state-default ui-corner-all k-fullscreen" title="' + gM('player_fullscreen') + '">' +
506 '<span class="ui-icon ui-icon-arrow-4-diag"></span></button>'
512 return '<button class="ui-state-default ui-corner-bl k-options" title="'+ gM('player_options') + '" >' +
513 '<span class="ui-icon ui-icon-k-menu">'+ gM('menu_btn') + '</span>'
521 * Converts all occurrences of <video> tag into video object
523 function mv_video_embed(swap_done_callback
, force_id
){
524 mvEmbed
.init( swap_done_callback
, force_id
);
527 //flist stores the set of functions to run after the video has been swaped in.
529 init:function( swap_done_callback
, force_id
){
531 if(swap_done_callback
)
532 mvEmbed
.flist
.push( swap_done_callback
);
534 //get mv_embed location if it has not been set
535 js_log('mv_embed ' + MV_EMBED_VERSION
);
537 var loadPlaylistLib
=false;
539 var eAction = function(this_elm
){
540 js_log( "Do SWAP: " + $j(this_elm
).attr("id") + ' tag: '+ this_elm
.tagName
.toLowerCase() );
542 if( $j(this_elm
).attr("id") == '' ){
543 $j(this_elm
).attr("id", 'v'+ global_player_list
.length
);
545 //stre a global reference to the id
546 global_player_list
.push( $j(this_elm
).attr("id") );
548 switch( this_elm
.tagName
.toLowerCase()){
550 var videoInterface
= new embedVideo(this_elm
);
551 mvEmbed
.swapEmbedVideoElement( this_elm
, videoInterface
);
554 var videoInterface
= new embedVideo(this_elm
);
555 videoInterface
.type
='audio';
556 mvEmbed
.swapEmbedVideoElement( this_elm
, videoInterface
);
559 loadPlaylistLib
=true;
564 if( force_id
== null && force_id
!= '' ){
565 var j_selector
= 'video,audio,playlist';
567 var j_selector
= '#' + force_id
;
569 //process selected elements:
570 //ie8 does not play well with the jQuery video,audio,playlist selector use native:
571 if($j
.browser
.msie
&& $j
.browser
.version
>= 8){
572 jtags
= j_selector
.split(',');
573 for( var i
=0; i
< jtags
.length
; i
++){
574 $j( document
.getElementsByTagName( jtags
[i
] )).each(function(){
579 $j( j_selector
).each(function(){
586 '$j.ui', //include dialog for pop-ing up thigns
589 $j('playlist').each(function(){
590 //create new playlist interface:
591 var plObj
= new mvPlayList( this );
592 mvEmbed
.swapEmbedVideoElement(this, plObj
);
593 var added_height
= plObj
.pl_layout
.title_bar_height
+ plObj
.pl_layout
.control_height
;
594 //move into a blocking display container with height + controls + title height:
595 $j('#'+plObj
.id
).wrap('<div style="display:block;height:' + (plObj
.height
+ added_height
) + 'px;"></div>');
599 this.checkClipsReady();
602 * swapEmbedVideoElement
603 * takes a video element as input and swaps it out with
604 * an embed video interface based on the video_elements attributes
606 swapEmbedVideoElement:function(video_element
, videoInterface
){
607 js_log('do swap ' + videoInterface
.id
+ ' for ' + video_element
);
608 embed_video
= document
.createElement('div');
609 //make sure our div has a hight/width set:
611 /*$j(embed_video).css({
612 'width':videoInterface.width,
613 'height':videoInterface.height
614 }).html( mv_get_loading_img() );*/
616 //inherit the video interface
617 for(var method
in videoInterface
){ //for in loop oky in Element context
618 if(method
!='readyState'){ //readyState crashes IE
620 embed_video
.setAttribute('style', videoInterface
[method
]);
621 }else if(method
=='class'){
622 if( $j
.browser
.msie
)
623 embed_video
.setAttribute("className", videoInterface
['class']);
625 embed_video
.setAttribute("class", videoInterface
['class']);
628 embed_video
[method
]=videoInterface
[method
];
632 if(embed_video
[method
]=="false")embed_video
[method
]=false;
633 if(embed_video
[method
]=="true")embed_video
[method
]=true;
635 ///js_log('did vI style');
636 //now swap out the video element for the embed_video obj:
637 $j(video_element
).after(embed_video
).remove();
638 //js_log('did swap');
639 $j('#'+embed_video
.id
).get(0).on_dom_swap();
641 // now that "embed_video" is stable, do more initialization (if we are ready)
642 if($j('#'+embed_video
.id
).get(0).loading_external_data
== false &&
643 $j('#'+embed_video
.id
).get(0).init_with_sources_loadedDone
== false){
644 //load and set ready state since source are available:
645 $j('#'+embed_video
.id
).get(0).init_with_sources_loaded();
648 js_log('done with child: ' + embed_video
.id
+ ' len:' + global_player_list
.length
);
651 //this should not be needed.
652 checkClipsReady : function(){
653 //js_log('checkClipsReady');
655 for(var i
=0; i
< global_player_list
.length
; i
++){
656 if( $j('#'+global_player_list
[i
]).length
!=0){
657 var cur_vid
= $j('#'+global_player_list
[i
]).get(0);
658 is_ready
= ( cur_vid
.ready_to_play
) ? is_ready
: false;
659 if( !is_ready
&& cur_vid
.load_error
){
661 $j(cur_vid
).html( cur_vid
.load_error
);
666 mvEmbed
.allClipsReady
= true;
667 // run queued functions
668 //js_log('run queded functions:' + mvEmbed.flist[0]);
671 setTimeout( 'mvEmbed.checkClipsReady()', 25 );
675 while (this.flist
.length
){
676 this.flist
.shift()();
682 * mediaSource class represents a source for a media element.
683 * @param {String} type MIME type of the source.
684 * @param {String} uri URI of the source.
687 function mediaSource(element
)
693 mediaSource
.prototype =
695 /** MIME type of the source. */
697 /** URI of the source. */
699 /** Title of the source. */
701 /** True if the source has been marked as the default. */
702 marked_default
:false,
703 /** True if the source supports url specification of offset and duration */
704 URLTimeEncoding
:false,
705 /** Start offset of the requested segment */
707 /** Duration of the requested segment (0 if not known) */
710 upddate_interval
:null,
716 init : function(element
)
718 //js_log('adding mediaSource: ' + element);
719 this.src
= $j(element
).attr('src');
720 this.marked_default
= false;
721 if ( element
.tagName
.toLowerCase() == 'video')
722 this.marked_default
= true;
724 //set default URLTimeEncoding if we have a time url:
725 //not ideal way to discover if content is on an oggz_chop server.
726 //should check some other way.
727 var pUrl
= parseUri ( this.src
);
728 if(typeof pUrl
['queryKey']['t'] != 'undefined'){
729 this['URLTimeEncoding']=true;
731 for(var i
=0; i
< mv_default_source_attr
.length
; i
++){ //array loop:
732 var attr
= mv_default_source_attr
[ i
];
733 if( $j(element
).attr( attr
) ) {
734 this[ attr
] = $j(element
).attr( attr
);
737 //update duration from hit if present:
738 if(this.durationHint
)
739 this.duration
= this.durationHint
;
742 if ( $j(element
).attr('type'))
743 this.mime_type
= $j(element
).attr('type');
744 else if ($j(element
).attr('content-type'))
745 this.mime_type
= $j(element
).attr('content-type');
747 this.mime_type
= this.detectType(this.src
);
749 //set the title if unset:
751 this.title
= this.mime_type
;
753 this.parseURLDuration();
755 updateSource:function(element
){
756 //for now just update the title:
757 if ($j(element
).attr("title"))
758 this.title
= $j(element
).attr("title");
760 /** updates the src time and start & end
761 * @param {String} start_time in NTP format
762 * @param {String} end_time in NTP format
764 updateSrcTime:function (start_ntp
, end_ntp
){
765 //js_log("f:updateSrcTime: "+ start_ntp+'/'+ end_ntp + ' from org: ' + this.start_ntp+ '/'+this.end_ntp);
766 //js_log("pre uri:" + this.src);
767 //if we have time we can use:
768 if( this.URLTimeEncoding
){
769 //make sure its a valid start time / end time (else set default)
770 if( !npt2seconds(start_ntp
) )
771 start_ntp
= this.start_ntp
;
773 if( !npt2seconds(end_ntp
) )
774 end_ntp
= this.end_ntp
;
776 this.src
= getURLParamReplace(this.src
, { 't': start_ntp
+'/'+ end_ntp
} );
778 //update the duration
779 this.parseURLDuration();
782 setDuration:function (duration
)
784 this.duration
= duration
;
786 this.end_ntp
= seconds2npt( this.start_offset
+ duration
);
789 /** MIME type accessor function.
790 @return the MIME type of the source.
793 getMIMEType : function()
795 return this.mime_type
;
797 /** URI accessor function.
798 * @param int seek_time_sec (used to adjust the URI for url based seeks)
799 @return the URI of the source.
802 getURI : function( seek_time_sec
)
804 if( !seek_time_sec
|| !this.URLTimeEncoding
){
810 var endvar
= '/'+ this.end_ntp
;
812 return getURLParamReplace(this.src
, { 't': seconds2npt( seek_time_sec
)+endvar
} ); ;
814 /** Title accessor function.
815 @return the title of the source.
818 getTitle : function()
822 /** Index accessor function.
823 @return the source's index within the enclosing mediaElement container.
826 getIndex : function()
831 * function getDuration in milliseconds
832 * special case derive duration from request url
833 * supports media_url?t=ntp_start/ntp_end url request format
835 parseURLDuration : function(){
836 //check if we have a URLTimeEncoding:
837 if( this.URLTimeEncoding
){
838 var annoURL
= parseUri( this.src
);
839 if( annoURL
.queryKey
['t'] ){
840 var times
= annoURL
.queryKey
['t'].split('/');
841 this.start_ntp
= times
[0];
842 this.end_ntp
= times
[1];
843 this.start_offset
= npt2seconds( this.start_ntp
);
844 this.duration
= npt2seconds( this.end_ntp
) - this.start_offset
;
846 //look for this info as attributes
847 if(this.startOffset
){
848 this.start_offset
= this.startOffset
;
849 this.start_ntp
= seconds2npt( this.startOffset
);
852 this.end_ntp
= seconds2npt( parseInt(this.duration
) + parseInt(this.start_offset
) );
856 //else nothing to parse just keep whatever info we already have
858 //js_log('f:parseURLDuration() for:' + this.src + ' d:' + this.duration);
860 /** Attempts to detect the type of a media file based on the URI.
861 @param {String} uri URI of the media file.
862 @returns The guessed MIME type of the file.
865 detectType:function(uri
)
867 //@@todo if media is on the same server as the javascript or we have mv_proxy configured
868 //we can issue a HEAD request and read the mime type of the media...
869 // (this will detect media mime type independently of the url name)
870 //http://www.jibbering.com/2002/4/httprequest.html (this should be done by extending jquery's ajax objects)
871 var end_inx
= (uri
.indexOf('?')!=-1)? uri
.indexOf('?') : uri
.length
;
872 var no_param_uri
= uri
.substr(0, end_inx
);
873 switch( no_param_uri
.substr(no_param_uri
.lastIndexOf('.'),4).toLowerCase() ){
874 case '.flv':return 'video/x-flv';break;
875 case '.ogg': case '.ogv': return 'video/ogg';break;
876 case '.oga': return 'audio/ogg'; break;
877 case '.anx':return 'video/ogg';break;
882 /** A media element corresponding to a <video> element.
883 It is implemented as a collection of mediaSource objects. The media sources
884 will be initialized from the <video> element, its child <source> elements,
885 and/or the ROE file referenced by the <video> element.
886 @param {element} video_element <video> element used for initialization.
889 function mediaElement(video_element
)
891 this.init(video_element
);
894 mediaElement
.prototype =
896 /** The array of mediaSource elements. */
899 /** Selected mediaSource element. */
900 selected_source
:null,
905 init:function( video_element
)
908 js_log('Initializing mediaElement...' );
909 this.sources
= new Array();
910 this.thumbnail
= mv_default_thumb_url
;
911 // Process the source element:
912 if($j(video_element
).attr("src"))
913 this.tryAddSource(video_element
);
915 if($j(video_element
).attr('thumbnail'))
916 this.thumbnail
= $j(video_element
).attr('thumbnail');
918 if($j(video_element
).attr('poster'))
919 this.thumbnail
= $j(video_element
).attr('poster');
921 // Process all inner <source> elements
922 //js_log("inner source count: " + video_element.getElementsByTagName('source').length );
924 $j(video_element
).find('source,text').each(function(inx
, inner_source
){
925 _this
.tryAddSource( inner_source
);
928 /** Updates the time request for all sources that have a standard time request argument (ie &t=start_time/end_time)
930 updateSourceTimes:function(start_ntp
, end_ntp
){
932 $j
.each(this.sources
, function(inx
, mediaSource
){
933 mediaSource
.updateSrcTime(start_ntp
, end_ntp
);
937 timedTextSources:function(){
938 for(var i
=0; i
< this.sources
.length
; i
++){
939 if( this.sources
[i
].mime_type
== 'text/cmml' ||
940 this.sources
[i
].mime_type
== 'text/x-srt')
945 /** Returns the array of mediaSources of this element.
946 \returns {Array} Array of mediaSource elements.
948 getSources:function( mime_filter
)
953 var source_set
= new Array();
954 for(var i
=0; i
< this.sources
.length
; i
++){
955 if( this.sources
[i
].mime_type
.indexOf( mime_filter
) != -1 )
956 source_set
.push( this.sources
[i
] );
960 getSourceById:function( source_id
){
961 for(var i
=0; i
< this.sources
.length
; i
++){
962 if( this.sources
[i
].id
== source_id
)
963 return this.sources
[i
];
967 /** Selects a particular source for playback.
969 selectSource:function(index
)
971 js_log('f:selectSource:'+index
);
972 var playable_sources
= this.getPlayableSources();
973 for(var i
=0; i
< playable_sources
.length
; i
++){
975 this.selected_source
= playable_sources
[i
];
976 //update the user selected format:
977 embedTypes
.players
.userSelectFormat( playable_sources
[i
].mime_type
);
982 /** selects the default source via cookie preference, default marked, or by id order
984 autoSelectSource:function(){
985 js_log('f:autoSelectSource:');
986 //@@todo read user preference for source
987 // Select the default source
988 var playable_sources
= this.getPlayableSources();
989 var flash_flag
=ogg_flag
=false;
991 for(var source
=0; source
< playable_sources
.length
; source
++){
992 var mime_type
=playable_sources
[source
].mime_type
;
993 if( playable_sources
[source
].marked_default
){
994 js_log('set via marked default: ' + playable_sources
[source
].marked_default
);
995 this.selected_source
= playable_sources
[source
];
998 //set via user-preference
999 if(embedTypes
.players
.preference
['format_prefrence'] == mime_type
){
1000 js_log('set via preference: '+playable_sources
[source
].mime_type
);
1001 this.selected_source
= playable_sources
[source
];
1005 //set Ogg via player support
1006 for(var source
=0; source
< playable_sources
.length
; source
++){
1007 js_log('f:autoSelectSource:' + playable_sources
[source
].mime_type
);
1008 var mime_type
=playable_sources
[source
].mime_type
;
1009 //set source via player
1010 if(mime_type
=='video/ogg' || mime_type
=='ogg/video' || mime_type
=='video/annodex' || mime_type
=='application/ogg'){
1011 for(var i
=0; i
< embedTypes
.players
.players
.length
; i
++){ //for in loop on object oky
1012 var player
= embedTypes
.players
.players
[i
];
1013 if(player
.library
=='vlc' || player
.library
=='native'){
1014 js_log('set via ogg via order');
1015 this.selected_source
= playable_sources
[source
];
1022 for(var source
=0; source
< playable_sources
.length
; source
++){
1023 var mime_type
=playable_sources
[source
].mime_type
;
1024 if( mime_type
=='video/x-flv' ){
1025 js_log('set via by player preference normal flash')
1026 this.selected_source
= playable_sources
[source
];
1031 for(var source
=0; source
< playable_sources
.length
; source
++){
1032 var mime_type
=playable_sources
[source
].mime_type
;
1033 if( mime_type
=='video/h264' ){
1034 js_log('set via playable_sources preference h264 flash')
1035 this.selected_source
= playable_sources
[source
];
1039 //select first source
1040 if (!this.selected_source
)
1042 js_log('set via first source:' + playable_sources
[0]);
1043 this.selected_source
= playable_sources
[0];
1047 /** Returns the thumbnail URL for the media element.
1048 \returns {String} thumbnail URL
1050 getThumbnailURL:function()
1052 return this.thumbnail
;
1054 /** Checks whether there is a stream of a specified MIME type.
1055 @param {String} mime_type MIME type to check.
1056 @type {BooleanPrimitive}.
1058 hasStreamOfMIMEType:function(mime_type
)
1060 for(source
in this.sources
)
1062 if(this.sources
[source
].getMIMEType() == mime_type
)
1067 isPlayableType:function(mime_type
)
1069 if( embedTypes
.players
.defaultPlayer( mime_type
) ){
1074 //if(this.selected_player){
1075 //return mime_type=='video/ogg' || mime_type=='ogg/video' || mime_type=='video/annodex' || mime_type=='video/x-flv';
1077 /** Adds a single mediaSource using the provided element if
1078 the element has a 'src' attribute.
1079 @param element {element} <video>, <source> or <mediaSource> element.
1081 tryAddSource:function(element
)
1083 js_log('f:tryAddSource:'+ $j(element
).attr("src"));
1084 if (! $j(element
).attr("src")){
1085 //js_log("element has no src");
1088 var new_src
= $j(element
).attr('src');
1089 //make sure an existing element with the same src does not already exist:
1090 for( var i
=0; i
< this.sources
.length
; i
++ ){
1091 if(this.sources
[i
].src
== new_src
){
1092 //js_log('checking existing: '+this.sources[i].getURI() + ' != '+ new_src);
1093 //can't add it all but try to update any additional attr:
1094 this.sources
[i
].updateSource(element
);
1098 var source
= new mediaSource( element
);
1099 this.sources
.push(source
);
1100 //alert('pushed source to stack'+ source + 'sl:'+this.sources.length);
1102 getPlayableSources: function(){
1103 var playable_sources
= new Array();
1104 for(var i
=0; i
< this.sources
.length
; i
++){
1105 if( this.isPlayableType( this.sources
[i
].mime_type
) ){
1106 playable_sources
.push( this.sources
[i
] );
1108 js_log("type "+ this.sources
[i
].mime_type
+ 'is not playable');
1111 return playable_sources
;
1113 /* Imports media sources from ROE data.
1114 * @param roe_data ROE data.
1116 addROE:function(roe_data
){
1118 this.addedROEData
=true;
1120 if( typeof roe_data
== 'string' )
1122 var parser
=new DOMParser();
1123 js_log('ROE data:' + roe_data
);
1124 roe_data
=parser
.parseFromString(roe_data
,"text/xml");
1127 $j
.each(roe_data
.getElementsByTagName('mediaSource'), function(inx
, source
){
1128 _this
.tryAddSource(source
);
1130 //set the thumbnail:
1131 $j
.each(roe_data
.getElementsByTagName('img'), function(inx
, n
){
1132 if($j(n
).attr("id")=="stream_thumb"){
1133 js_log('roe:set thumb to '+$j(n
).attr("src"));
1134 _this
['thumbnail'] =$j(n
).attr("src");
1138 $j
.each(roe_data
.getElementsByTagName('link'), function(inx
, n
){
1139 if($j(n
).attr('id')=='html_linkback'){
1140 js_log('roe:set linkback to '+$j(n
).attr("href"));
1141 _this
['linkback'] = $j(n
).attr('href');
1145 js_log('ROE data empty.');
1151 /** base embedVideo object
1152 @param element <video> tag used for initialization.
1155 var embedVideo = function(element
) {
1156 return this.init(element
);
1159 embedVideo
.prototype = {
1160 /** The mediaElement object containing all mediaSource objects */
1163 ready_to_play
:false, //should use html5 ready state
1164 load_error
:false, //used to set error in case of error
1165 loading_external_data
:false,
1166 thumbnail_updating
:false,
1167 thumbnail_disp
:true,
1168 init_with_sources_loadedDone
:false,
1170 //for onClip done stuff:
1171 anno_data_cache
:null,
1173 base_seeker_slider_offset
:null,
1174 onClipDone_disp
:false,
1176 //for seek thumb updates:
1177 cur_thumb_seek_time
:0,
1178 thumb_seek_interval
:null,
1181 //set the buffered percent:
1183 //utility functions for property values:
1184 hx : function ( s
) {
1185 if ( typeof s
!= 'String' ) {
1188 return s
.replace( /&/g
, '&' )
1189 . replace( /</g
, '<' )
1190 . replace( />/g
, '>' );
1192 hq : function ( s
) {
1193 return '"' + this.hx( s
) + '"';
1195 playerPixelWidth : function()
1197 var player
= $j('#dc_'+this.id
).get(0);
1198 if(typeof player
!='undefined' && player
['offsetWidth'])
1199 return player
.offsetWidth
;
1201 return parseInt(this.width
);
1203 playerPixelHeight : function()
1205 var player
= $j('#dc_'+this.id
).get(0);
1206 if(typeof player
!='undefined' && player
['offsetHeight'])
1207 return player
.offsetHeight
;
1209 return parseInt(this.height
);
1211 init: function(element
){
1212 //this.element_pointer = element;
1214 //inherit all the default video_attributes
1215 for(var attr
in default_video_attributes
){ //for in loop oky on user object
1216 if(element
.getAttribute(attr
)){
1217 this[attr
]=element
.getAttribute(attr
);
1218 //js_log('attr:' + attr + ' val: ' + element.getAttribute(attr) +'(set by elm)');
1220 this[attr
]=default_video_attributes
[attr
];
1221 //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)");
1224 //make sure startOffset is cast as an int
1225 if( this.startOffset
&& this.startOffset
.split(':').length
>= 2)
1226 this.startOffset
= npt2seconds(this.startOffset
);
1227 //make sure offset is in float:
1228 this.startOffset
= parseFloat(this.startOffset
);
1230 if( this.duration
&& this.duration
.split(':').length
>= 2)
1231 this.duration
= npt2seconds( this.duration
);
1232 //make sure duration is in float:
1233 this.duration
= parseFloat(this.duration
);
1234 js_log("duration is: " + this.duration
);
1235 //if style is set override width and height
1236 var dwh
= mwConfig
['video_size'].split('x');
1237 this.width
= element
.style
.width
? element
.style
.width
: dwh
[0];
1238 this.height
= element
.style
.height
? element
.style
.height
: dwh
[1];
1240 this.pid
= 'pid_' + this.id
;
1242 //grab any innerHTML and set it to missing_plugin_html
1243 //@@todo we should strip source tags instead of checking and skipping
1244 if(element
.innerHTML
!='' && element
.getElementsByTagName('source').length
==0){
1245 js_log('innerHTML: ' + element
.innerHTML
);
1246 this.user_missing_plugin_html
=element
.innerHTML
;
1248 // load all of the specified sources
1249 this.media_element
= new mediaElement(element
);
1251 on_dom_swap: function(){
1252 js_log('f:on_dom_swap');
1253 // Process the provided ROE file... if we don't yet have sources
1254 if(this.roe
&& this.media_element
.sources
.length
==0 ){
1255 js_log('loading external data');
1256 this.loading_external_data
=true;
1258 do_request(this.roe
, function(data
)
1261 _this
.media_element
.addROE( data
);
1262 js_log('added_roe::' + _this
.media_element
.sources
.length
);
1264 js_log('set loading_external_data=false');
1265 _this
.loading_external_data
=false;
1267 _this
.init_with_sources_loaded();
1271 init_with_sources_loaded : function()
1273 js_log('f:init_with_sources_loaded');
1274 //set flag that we have run this function:
1275 this.init_with_sources_loadedDone
=true;
1276 //autoseletct the source
1277 this.media_element
.autoSelectSource();
1278 //auto select player based on prefrence or default order
1279 if( !this.media_element
.selected_source
)
1281 //check for parent clip:
1282 if( typeof this.pc
!= 'undefined' ){
1283 js_log('no sources, type:' +this.type
+ ' check for html');
1285 //do load player if just displaying innerHTML:
1286 if( this.pc
.type
== 'text/html' ){
1287 this.selected_player
= embedTypes
.players
.defaultPlayer( 'text/html' );
1288 js_log('set selected player:'+ this.selected_player
.mime_type
);
1292 this.selected_player
= embedTypes
.players
.defaultPlayer( this.media_element
.selected_source
.mime_type
);
1294 if( this.selected_player
){
1295 js_log('selected ' + this.selected_player
.getName());
1296 js_log("PLAYBACK TYPE: "+this.selected_player
.library
);
1297 this.thumbnail_disp
= true;
1298 this.inheritEmbedObj();
1300 //no source's playable
1301 var missing_type
='';
1303 for( var i
=0; i
< this.media_element
.sources
.length
; i
++){
1304 missing_type
+= or
+ this.media_element
.sources
[i
].mime_type
;
1308 var missing_type
= this.pc
.type
;
1309 js_log('no player found for given source type ' + missing_type
);
1310 this.load_error
= this.getPluginMissingHTML(missing_type
);
1313 inheritEmbedObj:function(){
1314 js_log("inheritEmbedObj:duration is: " + this.duration
);
1315 //@@note: tricky cuz direct overwrite is not so ideal.. since the extended object is already tied to the dom
1316 //clear out any non-base embedObj stuff:
1317 if(this.instanceOf
){
1318 eval('tmpObj = '+this.instanceOf
);
1319 for(var i
in tmpObj
){ //for in loop oky for object
1320 if(this['parent_'+i
]){
1321 this[i
]=this['parent_'+i
];
1327 //set up the new embedObj
1328 js_log('f: inheritEmbedObj: embedding with ' + this.selected_player
.library
);
1330 this.selected_player
.load( function()
1332 js_log("selected_player::load:duration is: " + _this
.duration
);
1333 //js_log('inheriting '+_this.selected_player.library +'Embed to ' + _this.id + ' ' + $j('#'+_this.id).length);
1334 //var _this = $j('#'+_this.id).get(0);
1335 //js_log( 'type of ' + _this.selected_player.library +'Embed + ' +
1336 // eval('typeof '+_this.selected_player.library +'Embed'));
1337 eval('embedObj = ' +_this
.selected_player
.library
+'Embed;');
1338 for(var method
in embedObj
){ //for in loop oky for object
1339 //parent method preservation for local overwritten methods
1341 _this
['parent_' + method
] = _this
[method
];
1342 _this
[method
]=embedObj
[method
];
1344 js_log('TYPEOF_ppause: ' + typeof _this
['parent_pause']);
1346 if(_this
.inheritEmbedOverride
){
1347 _this
.inheritEmbedOverride();
1349 //update controls if possible
1350 if(!_this
.loading_external_data
)
1351 _this
.refreshControlsHTML();
1353 //js_log("READY TO PLAY:"+_this.id);
1354 _this
.ready_to_play
=true;
1355 _this
.getDuration();
1359 selectPlayer:function(player
)
1362 if(this.selected_player
.id
!= player
.id
){
1363 this.selected_player
= player
;
1364 this.inheritEmbedObj();
1367 doNativeWarningCheck:function(){
1368 if( $j
.cookie('dismissNativeWarn') && $j
.cookie('dismissNativeWarn')===true){
1371 //see if we have native support for ogg:
1372 var supporting_players
= embedTypes
.players
.getMIMETypePlayers( 'video/ogg' );
1373 for(var i
=0; i
< supporting_players
.length
; i
++){
1374 if(supporting_players
[i
].id
== 'videoElement'){
1378 //see if we are using mv_embed without a ogg source in which case no point in promoting firefox :P
1379 if(this.media_element
&& this.media_element
.sources
){
1380 var foundOgg
= false;
1381 var playable_sources
= this.media_element
.getPlayableSources();
1382 for(var sInx
=0; sInx
< playable_sources
.length
; sInx
++){
1383 var mime_type
= playable_sources
[sInx
].mime_type
;
1384 if( mime_type
=='video/ogg' ){
1385 //they have flash / h.264 fallback no need to push firefox :(
1389 //no ogg no point in download firefox
1397 getTimeReq:function(){
1398 var default_time_req
= '0:00:00/' + seconds2npt(this.getDuration());
1399 if(!this.media_element
)
1400 return default_time_req
;
1401 if(!this.media_element
.selected_source
)
1402 return default_time_req
;
1403 if(!this.media_element
.selected_source
.end_ntp
)
1404 return default_time_req
;
1405 return this.media_element
.selected_source
.start_ntp
+'/'+this.media_element
.selected_source
.end_ntp
;
1407 getDuration:function(){
1408 //update some local pointers for the selected source:
1409 if(this.media_element
&& this.media_element
.selected_source
&& this.media_element
.selected_source
.duration
){
1410 this.duration
= this.media_element
.selected_source
.duration
;
1411 this.start_offset
= this.media_element
.selected_source
.start_offset
;
1412 this.start_ntp
= this.media_element
.selected_source
.start_ntp
;
1413 this.end_ntp
= this.media_element
.selected_source
.end_ntp
;
1415 //update start end_ntp if duration !=0 (set from plugin)
1417 this.start_ntp
= '0:0:0';
1418 if(!this.end_ntp
&& this.duration
)
1419 this.end_ntp
= seconds2npt( this.duration
);
1420 //return the duration
1421 return this.duration
;
1423 timedTextSources:function(){
1424 if(!this.media_element
.timedTextSources
)
1426 return this.media_element
.timedTextSources()
1429 * wrapEmebedContainer
1430 * wraps the embed code into a container to better support playlist function
1431 * (where embed element is swapped for next clip
1432 * (where plugin method does not support playlsits)
1434 wrapEmebedContainer:function(embed_code
){
1435 //check if parent clip is set( ie we are in a playlist so name the embed container by playlistID)
1436 var id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
1437 return '<div id="mv_ebct_'+id
+'" style="width:'+this.width
+'px;height:'+this.height
+'px;">' +
1441 getEmbedHTML : function(){
1442 //return this.wrapEmebedContainer( this.getEmbedObj() );
1443 return 'function getEmbedHTML should be overitten by embedLib ';
1445 //do seek function (should be overwritten by implementing embedLibs)
1446 // first check if seek can be done on locally downloaded content.
1447 doSeek : function( perc
){
1448 if( this.supportsURLTimeEncoding() ){
1449 //make sure this.seek_time_sec is up-to-date:
1450 this.seek_time_sec
= npt2seconds( this.start_ntp
) + parseFloat( perc
* this.getDuration() );
1451 js_log('updated seek_time_sec: ' + seconds2npt ( this.seek_time_sec
) );
1453 this.didSeekJump
=true;
1455 this.setSliderValue( perc
);
1457 //do play in 100ms (give things time to clear)
1458 setTimeout('$j(\'#' + this.id
+ '\').get(0).play()',100);
1461 * seeks to the requested time and issues a callback when ready
1462 * (should be overwitten by client that supports frame serving)
1464 setCurrentTime:function( time
, callback
){
1465 js_log('error: base embed setCurrentTime can not frame serve (overide via plugin)');
1467 addPresTimeOffset:function(){
1468 //add in the offset:
1469 if(this.seek_time_sec
&& this.seek_time_sec
!=0){
1470 this.currentTime
+=this.seek_time_sec
;
1471 }else if(this.start_offset
&& this.start_offset
!=0){
1472 this.currentTime
= parseFloat(this.currentTime
) + parseFloat(this.start_offset
);
1475 doEmbedHTML:function()
1477 js_log('f:doEmbedHTML');
1478 js_log('thum disp:'+this.thumbnail_disp
);
1480 this.closeDisplayedHTML();
1482 // if(!this.selected_player){
1483 // return this.getPluginMissingHTML();
1484 //Set "loading" here
1485 $j('#dc_'+_this
.id
).html(''+
1486 '<div style="color:black;width:'+this.width
+'px;height:'+this.height
+'px;">' +
1487 gM('loading_plugin') +
1490 // schedule embedding
1491 this.selected_player
.load(function()
1493 js_log('performing embed for ' + _this
.id
);
1494 var embed_code
= _this
.getEmbedHTML();
1495 //js_log('shopuld embed:' + embed_code);
1496 $j('#dc_'+_this
.id
).html(embed_code
);
1499 onClipDone:function(){
1500 js_log('base:onClipDone');
1501 //stop the clip (load the thumbnail etc)
1503 this.seek_time_sec
= 0;
1504 this.setSliderValue(0);
1507 //if the clip resolution is < 320 don't do fancy onClipDone stuff
1508 if(this.width
< 300){
1511 this.onClipDone_disp
=true;
1512 this.thumbnail_disp
=true;
1513 //make sure we are not in preview mode( no end clip actions in preview mode)
1514 if( this.preview_mode
)
1517 $j('#img_thumb_'+this.id
).css('zindex',1);
1518 $j('#big_play_link_'+this.id
).hide();
1519 //add the liks_info_div black back
1520 $j('#dc_'+this.id
).append('<div id="liks_info_'+this.id
+'" ' +
1521 'style="width:' +parseInt(parseInt(this.width
)/2)+'px;'+
1522 'height:'+ parseInt(parseInt(this.height
)) +'px;'+
1523 'position:absolute;top:10px;overflow:auto'+
1524 'width: '+parseInt( ((parseInt(this.width
)/2)-15) ) + 'px;'+
1525 'left:'+ parseInt( ((parseInt(this.width
)/2)+15) ) +'px;">'+
1527 '<div id="black_back_'+this.id
+'" ' +
1528 'style="z-index:-2;position:absolute;background:#000;' +
1529 'top:0px;left:0px;width:'+parseInt(this.width
)+'px;' +
1530 'height:'+parseInt(this.height
)+'px;">' +
1534 //start animation (make thumb small in upper left add in div for "loading"
1535 $j('#img_thumb_'+this.id
).animate({
1536 width
:parseInt(parseInt(_this
.width
)/2),
1537 height
:parseInt(parseInt(_this
.height
)/2),
1543 //animation done.. add "loading" to div if empty
1544 if($j('#liks_info_'+_this
.id
).html()==''){
1545 $j('#liks_info_'+_this
.id
).html(gM('loading_txt'));
1549 //now load roe if run the showNextPrevLinks
1550 if(this.roe
&& this.media_element
.addedROEData
==false){
1551 do_request(this.roe
, function(data
)
1553 _this
.media_element
.addROE(data
);
1554 _this
.getNextPrevLinks();
1557 this.getNextPrevLinks();
1560 //@@todo we should merge getNextPrevLinks with textInterface .. there is repeated code between them.
1561 getNextPrevLinks:function(){
1562 js_log('f:getNextPrevLinks');
1563 var anno_track_url
= null;
1565 //check for annoative track
1566 $j
.each(this.media_element
.sources
, function(inx
, n
){
1567 if(n
.mime_type
=='text/cmml'){
1568 if( n
.id
== 'Anno_en'){
1569 anno_track_url
= n
.src
;
1573 if( anno_track_url
){
1574 js_log('found annotative track:'+ anno_track_url
);
1575 //zero out seconds (should improve cache hit rate and generally expands metadata search)
1576 //@@todo this could be repalced with a regExp
1577 var annoURL
= parseUri(anno_track_url
);
1578 var times
= annoURL
.queryKey
['t'].split('/');
1579 var stime_parts
= times
[0].split(':');
1580 var etime_parts
= times
[1].split(':');
1581 //zero out the hour:
1582 var new_start
= stime_parts
[0]+':'+'0:0';
1583 //zero out the end sec
1584 var new_end
= (etime_parts
[0]== stime_parts
[0])? (etime_parts
[0]+1)+':0:0' :etime_parts
[0]+':0:0';
1586 var etime_parts
= times
[1].split(':');
1588 var new_anno_track_url
= annoURL
.protocol
+'://'+ annoURL
.host
+ annoURL
.path
+'?';
1589 $j
.each(annoURL
.queryKey
, function(i
, val
){
1590 new_anno_track_url
+=(i
=='t')?'t='+new_start
+'/'+new_end
+'&' :
1593 var request_key
= new_start
+'/'+new_end
;
1594 //check the anno_data cache:
1595 //@@todo search cache see if current is in range.
1596 if(this.anno_data_cache
){
1597 js_log('anno data found in cache: '+request_key
);
1598 this.showNextPrevLinks();
1600 do_request(new_anno_track_url
, function(cmml_data
){
1601 js_log('raw response: '+ cmml_data
);
1602 if(typeof cmml_data
== 'string')
1604 var parser
=new DOMParser();
1605 js_log('Parse CMML data:' + cmml_data
);
1606 cmml_data
=parser
.parseFromString(cmml_data
,"text/xml");
1608 //init anno_data_cache
1609 if(!_this
.anno_data_cache
)
1610 _this
.anno_data_cache
={};
1611 //grab all metadata and put it into the anno_data_cache:
1612 $j
.each(cmml_data
.getElementsByTagName('clip'), function(inx
, clip
){
1613 _this
.anno_data_cache
[ $j(clip
).attr("id") ]={
1614 'start_time_sec':npt2seconds($j(clip
).attr("start").replace('npt:','')),
1615 'end_time_sec':npt2seconds($j(clip
).attr("end").replace('npt:','')),
1616 'time_req':$j(clip
).attr("start").replace('npt:','')+'/'+$j(clip
).attr("end").replace('npt:','')
1619 _this
.anno_data_cache
[ $j(clip
).attr("id") ]['meta']={};
1620 $j
.each(clip
.getElementsByTagName('meta'),function(imx
, meta
){
1621 //js_log('adding meta: '+ $j(meta).attr("name")+ ' = '+ $j(meta).attr("content"));
1622 _this
.anno_data_cache
[$j(clip
).attr("id")]['meta'][$j(meta
).attr("name")]=$j(meta
).attr("content");
1625 _this
.showNextPrevLinks();
1629 js_log('no annotative track found');
1630 $j('#liks_info_'+this.id
).html('no metadata found for related links');
1632 //query current request time +|- 60s to get prev next speech links.
1634 showNextPrevLinks:function(){
1635 //js_log('f:showNextPrevLinks');
1636 //int requested links:
1642 var curTime
= this.getTimeReq().split('/');
1644 var s_sec
= npt2seconds(curTime
[0]);
1645 var e_sec
= npt2seconds(curTime
[1]);
1646 js_log('showNextPrevLinks: req time: '+ s_sec
+ ' to ' + e_sec
);
1647 //now we have all the data in anno_data_cache
1648 var current_done
=false;
1649 for(var clip_id
in this.anno_data_cache
){ //for in loop oky for object
1650 var clip
= this.anno_data_cache
[clip_id
];
1651 //js_log('on clip:'+ clip_id);
1652 //set prev_link (if cur_link is still empty)
1653 if( s_sec
> clip
.end_time_sec
){
1654 link
.prev
= clip_id
;
1655 js_log('showNextPrevLinks: ' + s_sec
+ ' < ' + clip
.end_time_sec
+ ' set prev');
1658 if(e_sec
==clip
.end_time_sec
&& s_sec
== clip
.start_time_sec
)
1659 current_done
= true;
1660 //current clip is not done:
1661 if( e_sec
< clip
.end_time_sec
&& link
.current
=='' && !current_done
){
1662 link
.current
= clip_id
;
1663 js_log('showNextPrevLinks: ' + e_sec
+ ' < ' + clip
.end_time_sec
+ ' set current');
1666 //set end clip (first clip where start time is > end_time of req
1667 if( e_sec
< clip
.start_time_sec
&& link
.next
==''){
1668 link
.next
= clip_id
;
1669 js_log('showNextPrevLinks: '+ e_sec
+ ' < '+ clip
.start_time_sec
+ ' && ' + link
.next
);
1673 if(link
.prev
=='' && link
.current
=='' && link
.next
==''){
1674 html
='<p><a href="'+this.media_element
.linkbackgetMsg
+'">clip page</a>';
1676 for(var link_type
in link
){
1677 var link_id
= link
[link_type
];
1679 var clip
= this.anno_data_cache
[link_id
];
1681 for(var j
in clip
['meta']){
1682 title_msg
+=j
.replace(/_/g,' ') +': ' +clip['meta'][j].replace(/_
/g
,' ') +" <br>";
1684 var time_req
= clip
.time_req
;
1685 if(link_type
=='current') //if current start from end of current clip play to end of current meta:
1686 time_req
= curTime
[1]+ '/' + seconds2npt( clip
.end_time_sec
);
1688 //do special linkbacks for metavid content:
1689 var regTimeCheck
= new RegExp(/[0-9]+:[0-9]+:[0-9]+\/[0-9]+:[0-9]+:[0-9]+/);
1691 if( regTimeCheck
.test( this.media_element
.linkback
) ){
1692 html
+=' href="'+ this.media_element
.linkback
.replace(regTimeCheck
,time_req
) +'" ';
1694 html
+=' href="#" onClick="$j(\'#'+this.id
+'\').get(0).playByTimeReq(\''+
1695 time_req
+ '\'); return false; "';
1697 html
+=' title="' + title_msg
+ '">' +
1698 gM(link_type
+'_clip_msg') +
1699 '</a><br><span style="font-size:small">'+ title_msg
+'<span></p>';
1703 //js_og("should set html:"+ html);
1704 $j('#liks_info_'+this.id
).html(html
);
1706 playByTimeReq: function(time_req
){
1707 js_log('f:playByTimeReq: '+time_req
);
1709 this.updateVideoTimeReq(time_req
);
1712 doThumbnailHTML:function()
1715 js_log('f:doThumbnailHTML'+ this.thumbnail_disp
);
1716 this.closeDisplayedHTML();
1717 $j( '#dc_' + this.id
).html( this.getThumbnailHTML() );
1719 this.thumbnail_disp
= true;
1721 refreshControlsHTML:function(){
1722 js_log('refreshing controls HTML');
1723 if($j('#mv_embedded_controls_'+this.id
).length
==0)
1725 js_log('#mv_embedded_controls_'+this.id
+ ' not present, returning');
1728 $j('#mv_embedded_controls_'+this.id
).html( this.getControlsHTML() );
1729 ctrlBuilder
.addControlHooks(this);
1732 getControlsHTML:function()
1734 return ctrlBuilder
.getControls( this );
1736 getHTML : function (){
1737 js_log('f:getHTML : ' + this.id
);
1741 //get the thumbnail:
1742 html_code
= this.getThumbnailHTML();
1745 js_log("f:getHTML:AddControls");
1746 html_code
+='<div class="k-control-bar ui-widget-header ui-helper-clearfix">';
1747 html_code
+= this.getControlsHTML();
1748 html_code
+='</div>';
1749 //block out some space by encapulating the top level div
1750 $j(this).wrap('<div style="width:'+parseInt(this.width
)+'px;height:'
1751 + (parseInt(this.height
) + ctrlBuilder
.height
)+'px" id="k-player_' + this.id
+ '" class="k-player"></div>');
1754 //js_log('should set: '+this.id);
1755 $j(this).html( html_code
);
1756 //add hooks once Controls are in DOM
1757 ctrlBuilder
.addControlHooks(this);
1759 //js_log('set this to: ' + $j(this).html() );
1761 //if auto play==true directly embed the plugin
1764 js_log('activating autoplay');
1769 * get missing plugin html (check for user included code)
1771 getPluginMissingHTML : function(missing_type
){
1772 //keep the box width hight:
1773 var out
= '<div style="width:'+this.width
+'px;height:'+this.height
+'px">';
1774 if(this.user_missing_plugin_html
){
1775 out
+= this.user_missing_plugin_html
;
1779 out
+= gM('mv_generic_missing_plugin', missing_type
) + ' or <a title="'+gM('download_clip')+'" href="'+this.src
+'">'+gM('download_clip')+'</a>';
1781 return out
+ '</div>';
1783 updateVideoTimeReq:function(time_req
){
1784 js_log('f:updateVideoTimeReq');
1785 var time_parts
=time_req
.split('/');
1786 this.updateVideoTime(time_parts
[0], time_parts
[1]);
1789 updateVideoTime:function(start_ntp
, end_ntp
){
1791 this.media_element
.updateSourceTimes( start_ntp
, end_ntp
);
1793 this.setStatus(start_ntp
+'/'+end_ntp
);
1795 this.setSliderValue(0);
1796 //reset seek_offset:
1797 if(this.media_element
.selected_source
.URLTimeEncoding
)
1798 this.seek_time_sec
=0;
1800 this.seek_time_sec
=npt2seconds(start_ntp
);
1802 //@@todo overwite by embed library if we can render frames natavily
1803 renderTimelineThumbnail:function( options
){
1804 var my_thumb_src
= this.media_element
.getThumbnailURL();
1805 //check if our thumbnail has a time attribute:
1806 if( my_thumb_src
.indexOf('t=') !== -1){
1807 var time_ntp
= seconds2npt ( options
.time
+ parseInt(this.start_offset
) );
1808 my_thumb_src
= getURLParamReplace( my_thumb_src
, { 't':time_ntp
, 'size': options
.size
} );
1810 var thumb_class
= (typeof options
['thumb_class'] != 'undefined' ) ? options
['thumb_class'] : '';
1811 return '<div class="ui-corner-all ' + thumb_class
+ '" src="' + my_thumb_src
+ '" '+
1812 'style="height:' + options
.height
+ 'px;' +
1813 'width:' + options
.width
+ 'px" >' +
1814 '<img src="' + my_thumb_src
+'" '+
1815 'style="height:' + options
.height
+ 'px;' +
1816 'width:' + options
.width
+ 'px">' +
1819 updateThumbTimeNTP:function( time
){
1820 this.updateThumbTime( npt2seconds(time
) - parseInt(this.start_offset
) );
1822 updateThumbTime:function( float_sec
){
1823 //js_log('updateThumbTime:'+float_sec);
1825 if( typeof this.org_thum_src
=='undefined' ){
1826 this.org_thum_src
= this.media_element
.getThumbnailURL();
1828 if( this.org_thum_src
.indexOf('t=') !== -1){
1829 this.last_thumb_url
= getURLParamReplace(this.org_thum_src
,
1830 { 't' : seconds2npt( float_sec
+ parseInt(this.start_offset
)) } );
1831 if(!this.thumbnail_updating
){
1832 this.updateThumbnail(this.last_thumb_url
,false);
1833 this.last_thumb_url
=null;
1837 //for now provide a src url .. but need to figure out how to copy frames from video for plug-in based thumbs
1838 updateThumbPerc:function( perc
){
1839 return this.updateThumbTime( (this.getDuration() * perc
) );
1841 //updates the thumbnail if the thumbnail is being displayed
1842 updateThumbnail : function(src
, quick_switch
){
1843 //make sure we don't go to the same url if we are not already updating:
1844 if( !this.thumbnail_updating
&& $j('#img_thumb_'+this.id
).attr('src')== src
)
1846 //if we are already updating don't issue a new update:
1847 if( this.thumbnail_updating
&& $j('#new_img_thumb_'+this.id
).attr('src')== src
)
1850 js_log('update thumb: ' + src
);
1853 $j('#img_thumb_'+this.id
).attr('src', src
);
1856 //if still animating remove new_img_thumb_
1857 if(this.thumbnail_updating
==true)
1858 $j('#new_img_thumb_'+this.id
).stop().remove();
1860 if(this.thumbnail_disp
){
1861 js_log('set to thumb:'+ src
);
1862 this.thumbnail_updating
=true;
1863 $j('#dc_'+this.id
).append('<img src="'+src
+'" ' +
1864 'style="display:none;position:absolute;zindex:2;top:0px;left:0px;" ' +
1865 'width="'+this.width
+'" height="'+this.height
+'" '+
1866 'id = "new_img_thumb_'+this.id
+'" />');
1867 //js_log('appended: new_img_thumb_');
1868 $j('#new_img_thumb_'+this.id
).fadeIn("slow", function(){
1869 //once faded in remove org and rename new:
1870 $j('#img_thumb_'+_this
.id
).remove();
1871 $j('#new_img_thumb_'+_this
.id
).attr('id', 'img_thumb_'+_this
.id
);
1872 $j('#img_thumb_'+_this
.id
).css('zindex','1');
1873 _this
.thumbnail_updating
=false;
1874 //js_log("done fadding in "+ $j('#img_thumb_'+_this.id).attr("src"));
1876 //if we have a thumb queued update to that
1877 if(_this
.last_thumb_url
){
1878 var src_url
=_this
.last_thumb_url
;
1879 _this
.last_thumb_url
=null;
1880 _this
.updateThumbnail(src_url
);
1886 /** Returns the HTML code for the video when it is in thumbnail mode.
1887 This includes the specified thumbnail as well as buttons for
1888 playing, configuring the player, inline cmml display, HTML linkback,
1889 download, and embed code.
1891 getThumbnailHTML : function ()
1893 js_log('embedVideo:getThumbnailHTML::' + this.id
);
1894 var thumb_html
= '';
1897 //if(this.class)class_atr = ' class="'+this.class+'"';
1898 //if(this.style)style_atr = ' style="'+this.style+'"';
1899 // else style_atr = 'overflow:hidden;height:'+this.height+'px;width:'+this.width+'px;';
1900 this.thumbnail
= this.media_element
.getThumbnailURL();
1902 //put it all in the div container dc_id
1903 thumb_html
+= '<div id="dc_'+this.id
+'" rel="emdded_play" style="position:relative;'+
1904 ' overflow:hidden; top:0px; left:0px; width:'+this.playerPixelWidth()+'px; height:'+this.playerPixelHeight()+'px; z-index:0;">'+
1905 '<img width="' + this.playerPixelWidth() + '" height="' + this.playerPixelHeight() +
1906 '" style="position:relative;width:'+this.playerPixelWidth()+';height:'+this.playerPixelHeight()+'"' +
1907 ' id="img_thumb_' + this.id
+'" src="' + this.thumbnail
+ '">';
1909 if( this.play_button
== true && this.controls
== true )
1910 thumb_html
+=this.getPlayButton();
1912 thumb_html
+='</div>';
1915 getEmbeddingHTML:function()
1917 var thumbnail
= this.media_element
.getThumbnailURL();
1919 var embed_thumb_html
;
1920 if(thumbnail
.substring(0,1)=='/'){
1921 eURL
= parseUri(mv_embed_path
);
1922 embed_thumb_html
= eURL
.protocol
+ '://' + eURL
.host
+ thumbnail
;
1923 //js_log('set from mv_embed_path:'+embed_thumb_html);
1925 embed_thumb_html
= (thumbnail
.indexOf('http://')!=-1)?thumbnail
:mv_embed_path
+ thumbnail
;
1927 var embed_code_html
= '<script type="text/javascript" ' +
1928 'src="'+mv_embed_path
+'mv_embed.js"></script>' +
1931 embed_code_html
+='roe="'+this.roe
+'" >';
1933 embed_code_html
+='src="'+this.src
+'" ' +
1934 'poster="'+embed_thumb_html
+'">';
1936 //close the video tag
1937 embed_code_html
+='</video>';
1939 return embed_code_html
;
1941 doOptionsHTML:function()
1943 var sel_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
1944 var pos
= $j('#options_button_'+sel_id
).offset();
1945 pos
['top']=pos
['top']+24;
1946 pos
['left']=pos
['left']-124;
1947 //js_log('pos of options button: t:'+pos['top']+' l:'+ pos['left']);
1948 $j('#mv_vid_options_'+sel_id
).css(pos
).toggle();
1951 getPlayButton:function(id
){
1953 return '<div title="' + gM('play_clip') + '" class="ui-state-default play-btn-large" '+
1954 'style="left:'+((this.playerPixelWidth()-130)/2)+'px;'+
1955 'top:' + ((this.playerPixelHeight()-96)/2) + 'px;">'+
1958 doLinkBack:function(){
1959 if(this.roe
&& this.media_element
.addedROEData
==false){
1961 this.displayHTML(gM('loading_txt'));
1962 do_request(this.roe
, function(data
)
1964 _this
.media_element
.addROE(data
);
1968 if(this.media_element
.linkback
){
1969 window
.location
= this.media_element
.linkback
;
1971 this.displayHTML(gM('could_not_find_linkback'));
1975 showCredits: function($target
){
1976 $target
.html('credits page goes here');
1978 //display the code to remotely embed this video:
1979 showShare:function($target
){
1980 var embed_code
= this.getEmbeddingHTML();
1983 o
+='<a class="email" href="'+this.linkback
+'">Share Clip via Link</a> '+
1986 o
+='<span style="color:#FFF;font-size:14px;">Embed Clip in Blog or Site</span><br>'+
1987 '<span style="color:#FFF;font-size:12px;"><a style="color:red" href="http://metavid.org/wiki/Security_Notes_on_Remote_Embedding">'+
1988 'Read This</a> before embeding.</span>'+
1989 '<div class="embed_code"> '+
1990 '<textarea onClick="this.select();" id="embedding_user_html_' + this.id
+ '" name="embed">' +
1993 '<button onClick="$j(\'#' + this.id
+ '\').get(0).copyText(); return false;" class="copy_to_clipboard">Copy to Clipboard</button> '+
1995 js_log("should set share: " + o
);
1998 copyText:function(){
1999 $j('#embedding_user_html_'+this.id
).focus().select();
2000 if(document
.selection
){
2001 CopiedTxt
= document
.selection
.createRange();
2002 CopiedTxt
.execCommand("Copy");
2005 showTextInterface:function(){
2007 //display the text container with loading text:
2008 //@@todo support position config
2009 var loc
= $j(this).position();
2010 if($j('#metaBox_'+this.id
).length
==0){
2011 $j(this).after('<div class="ui-widget ui-widget-content ui-corner-all" style="position:absolute;z-index:10;'+
2012 'top:' + (loc
.top
) + 'px;' +
2013 'left:' + (parseInt( loc
.left
) + parseInt(this.width
) + 10 )+'px;' +
2014 'height:'+ parseInt( this.height
)+'px;width:400px;' +
2016 'id="metaBox_' + this.id
+ '">'+
2020 //fade in the text display
2021 $j('#metaBox_'+this.id
).fadeIn("fast");
2022 //check if textObj present:
2023 if(typeof this.textInterface
== 'undefined' ){
2024 //load the default text interface:
2029 _this
.textInterface
= new mvTextInterface( _this
);
2031 _this
.textInterface
.show();
2032 js_log("NEW TEXT INTERFACE");
2033 for(var i
in _this
.textInterface
.availableTracks
){
2034 js_log("tracks in new interface: "+_this
.id
+ ' tid:' + i
);
2040 this.textInterface
.show();
2043 closeTextInterface:function(){
2044 js_log('closeTextInterface '+ typeof this.textInterface
);
2045 if(typeof this.textInterface
!== 'undefined' ){
2046 this.textInterface
.close();
2049 /** Generic function to display custom HTML inside the mv_embed element.
2050 The code should call the closeDisplayedHTML function to close the
2051 display of the custom HTML and restore the regular mv_embed display.
2052 @param {String} HTML code for the selection list.
2054 displayHTML:function(html_code
)
2056 var sel_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2058 if(!this.supports
['overlays'])
2061 //put select list on-top
2062 //make sure the parent is relatively positioned:
2063 $j('#'+sel_id
).css('position', 'relative');
2064 //set height width (check for playlist container)
2065 var width
= (this.pc
)?this.pc
.pp
.width
:this.playerPixelWidth();
2066 var height
= (this.pc
)?this.pc
.pp
.height
:this.playerPixelHeight();
2069 height
+=(this.pc
.pp
.pl_layout
.title_bar_height
+ this.pc
.pp
.pl_layout
.control_height
);
2072 if($j('#blackbg_'+sel_id
).length
!=0)
2075 $j('#blackbg_'+sel_id
).remove();
2077 //fade in a black bg div ontop of everything
2078 var div_code
= '<div id="blackbg_'+sel_id
+'" class="videoComplete" ' +
2079 'style="height:'+parseInt(height
)+'px;width:'+parseInt(width
)+'px;">'+
2080 '<div class="videoOptionsComplete">'+
2081 //@@TODO: this style should go to .css
2082 '<span style="float:right;margin-right:10px">' +
2083 '<a href="#" style="color:white;" onClick="$j(\'#'+sel_id
+'\').get(0).closeDisplayedHTML();return false;">close</a>' +
2085 '<div id="mv_disp_inner_'+sel_id
+'" style="padding-top:10px;">'+
2089 $j('#'+sel_id
).prepend(div_code
);
2091 $j('#blackbg_'+sel_id
).fadeIn("slow");
2093 $j('#blackbg_'+sel_id
).show();
2094 return false; //onclick action return false
2096 /** Close the custom HTML displayed using displayHTML and restores the
2097 regular mv_embed display.
2099 closeDisplayedHTML:function(){
2100 var sel_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2101 $j('#blackbg_'+sel_id
).fadeOut("slow", function(){
2102 $j('#blackbg_'+sel_id
).remove();
2104 return false; //onclick action return false
2106 showPlayerselect:function( target
){
2107 //get id (in case where we have a parent container)
2108 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2111 // var out= '<span style="color:#FFF;background-color:black;"><blockquote style="background-color:black;">';
2113 out
+='<h2>' + gM('chose_player') + '</h2>';
2115 //js_log('selected src'+ _this.media_element.selected_source.url);
2116 $j
.each( this.media_element
.getPlayableSources(), function(source_id
, source
){
2117 var default_player
= embedTypes
.players
.defaultPlayer( source
.getMIMEType() );
2119 var is_selected
= (source
== _this
.media_element
.selected_source
);
2120 var image_src
= mv_skin_img_path
;
2122 //set the Playable source type:
2123 if( source
.mime_type
== 'video/x-flv' ){
2124 image_src
+= 'flash_icon_';
2125 }else if( source
.mime_type
== 'video/h264'){
2126 //for now all mp4 content is pulled from archive.org (so use archive.org icon)
2127 image_src
+= 'archive_org_';
2129 image_src
+= 'fish_xiph_org_';
2131 image_src
+= is_selected
? 'color':'bw';
2132 image_src
+= '.png';
2137 //output the player select code:
2138 var supporting_players
= embedTypes
.players
.getMIMETypePlayers( source
.getMIMEType() );
2140 for(var i
=0; i
< supporting_players
.length
; i
++){
2141 if( _this
.selected_player
.id
== supporting_players
[i
].id
&& is_selected
){
2142 out
+='<li>' + supporting_players
[i
].getName() +'</li>';
2144 //else gray plugin and the plugin with link to select
2145 // out+='<li style="margin-left:20px;">'+
2146 // '<a href="#" class="sel_source" id="sc_' + source_id + '_' + supporting_players[i].id +'">'+
2147 // '<img border="0" width="16" height="16" src="' + mv_skin_img_path + 'plugin_disabled.png">'+
2148 // supporting_players[i].getName() +
2151 '<a href="#" id="dc_' + source_id
+ '_' + supporting_players
[i
].id
+'">' +
2152 supporting_players
[i
].getName() + '</a><li>';
2157 out
+= source
.getTitle() + ' - no player available';
2159 // out+='</blockquote></span>';
2160 $j(target
).html(out
);
2162 //set up the click bindings:
2163 $j('.sel_source').each(function(){
2164 $j(this).click(function(){
2165 var iparts
= $j(this).attr( 'id' ).replace(/sc_/,'').split('_');
2166 var source_id
= iparts
[0];
2167 var default_player_id
= iparts
[1];
2168 js_log('source id: ' + source_id
+ ' player id: ' + default_player_id
);
2170 $j('#' + this_id
).get(0).closeDisplayedHTML();
2171 $j('#' + _this
.id
).get(0).media_element
.selectSource( source_id
);
2173 embedTypes
.players
.userSelectPlayer( default_player_id
,
2174 _this
.media_element
.sources
[ source_id
].getMIMEType() );
2176 //be sure to issue a stop
2177 $j('#' + this_id
).get(0).stop();
2179 //don't follow the empty # link:
2184 showDownload:function( $target
){
2185 //load the roe if available (to populate out download options:
2186 //js_log('f:showDownload '+ this.roe + ' ' + this.media_element.addedROEData);
2187 if(this.roe
&& this.media_element
.addedROEData
== false){
2189 $target
.html( gM('loading_txt') );
2190 do_request(this.roe
, function(data
)
2192 _this
.media_element
.addROE(data
);
2193 $target
.html( _this
.getShowVideoDownload() );
2196 $target
.html( this.getShowVideoDownload() );
2199 getShowVideoDownload:function(){
2200 var dl_txt_list
= dl_list
= '';
2201 $j
.each(this.media_element
.getSources(), function(index
, source
){
2202 var dl_line
= '<li>' + '<a href="' + source
.getURI() +'"> ' + source
.getTitle() + '</a></li>\n';
2203 if(this.getMIMEType()=="text/cmml" || this.getMIMEType()=="text/x-srt") {
2204 dl_txt_list
+= dl_line
;
2209 var o
='<h2>' + gM('download_clip') + '</h2>'+
2215 if(dl_txt_list
!= '')
2216 o
+='<h2>' + gM('download_text') + '</h2>' +
2225 * base embed controls
2226 * the play button calls
2229 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2231 //js_log( "mv_embed play:" + this.id);
2232 //js_log('thum disp:'+this.thumbnail_disp);
2233 //check if thumbnail is being displayed and embed html
2234 if( this.thumbnail_disp
){
2235 if( !this.selected_player
){
2236 js_log('no selected_player');
2237 //this.innerHTML = this.getPluginMissingHTML();
2238 //$j(this).html(this.getPluginMissingHTML());
2239 $j('#'+this.id
).html( this.getPluginMissingHTML() );
2242 this.onClipDone_disp
=false;
2244 this.thumbnail_disp
=false;
2247 //the plugin is already being displayed
2248 this.paused
=false; //make sure we are not "paused"
2252 $j('#'+ this_id
+ ' .play-btn .ui-icon').removeClass('ui-icon-play').addClass('ui-icon-pause');
2253 $j('#'+ this_id
+ ' .play-btn').unbind().btnBind().click(function(){
2254 $j('#' + this_id
).get(0).pause();
2255 }).attr('title', gM('pause_clip'));
2259 //should be done by child (no base way to load assets)
2260 js_log('baseEmbed:load call');
2263 return this.media_element
.selected_source
.getURI( this.seek_time_sec
);
2267 * there is no general way to pause the video
2268 * must be overwritten by embed object to support this functionality.
2271 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2272 //js_log('mv_embed:do pause');
2273 //(playing) do pause
2275 //update the ctrl "paused state"
2276 $j('#'+ this_id
+ ' .play-btn .ui-icon').removeClass('ui-icon-pause').addClass('ui-icon-play');
2277 $j('#'+ this_id
+ ' .play-btn').unbind().btnBind().click(function(){
2278 $j('#'+this_id
).get(0).play();
2279 }).attr('title', gM('play_clip'));
2282 * base embed stop (can be overwritten by the plugin)
2286 js_log('mvEmbed:stop:'+this.id
);
2288 //no longer seeking:
2289 this.didSeekJump
=false;
2291 //first issue pause to update interface (only call the parent)
2292 if(this['parent_pause']){
2293 this.parent_pause();
2298 //reset the currentTime:
2300 //check if thumbnail is being displayed in which case do nothing
2301 if( this.thumbnail_disp
){
2302 //already in stooped state
2303 js_log('already in stopped state');
2305 //rewrite the html to thumbnail disp
2306 this.doThumbnailHTML();
2307 this.bufferedPercent
=0; //reset buffer state
2308 this.setSliderValue(0);
2309 this.setStatus( this.getTimeReq() );
2312 //make sure the big playbutton is has click action:
2313 $j('#'+ _this
.id
+' .play-btn-large').unbind('click').btnBind().click(function(){
2314 $j('#' +_this
.id
).get(0).play();
2317 if(this.update_interval
)
2319 clearInterval(this.update_interval
);
2320 this.update_interval
= null;
2323 toggleMute:function(){
2324 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2327 $j( '#volume_control_' + this_id
+ ' span').removeClass('ui-icon-volume-off').addClass('ui-icon-volume-on');
2328 $j( '#volume_bar_' + this_id
).slider('value', 100);
2329 this.updateVolumen(1);
2332 $j('#volume_control_'+this_id
+ ' span').removeClass('ui-icon-volume-on').addClass('ui-icon-volume-off');
2333 $j('#volume_bar_'+this_id
).slider('value', 0);
2334 this.updateVolumen(0);
2336 js_log('f:toggleMute::' + this.muted
);
2338 updateVolumen:function(perc
){
2339 js_log('update volume not supported with current playback type');
2341 fullscreen:function(){
2342 js_log('fullscreen not supported with current playback type');
2344 /* returns bool true if playing or paused, false if stopped
2346 isPlaying : function(){
2347 if(this.thumbnail_disp
){
2350 }else if( this.paused
){
2357 isPaused : function(){
2358 return this.isPlaying() && this.paused
;
2360 isStoped : function(){
2361 return this.thumbnail_disp
;
2363 playlistSupport:function(){
2364 //by default not supported (implemented in js)
2367 postEmbedJS:function(){
2370 //do common monitor code like update the playhead and play status
2371 //plugin objects are responsible for updating currentTime
2373 if( this.currentTime
&& this.currentTime
> 0 && this.duration
){
2374 if( !this.userSlide
){
2375 if( this.start_offset
){
2376 //if start offset include that calculation
2377 this.setSliderValue( ( this.currentTime
- this.start_offset
) / this.duration
);
2378 this.setStatus( seconds2npt(this.currentTime
) + '/'+ seconds2npt(parseFloat(this.start_offset
)+parseFloat(this.duration
) ));
2380 this.setSliderValue( this.currentTime
/ this.duration
);
2381 this.setStatus( seconds2npt(this.currentTime
) + '/' + seconds2npt(this.duration
));
2385 //js_log(' ct:' + this.currentTime + ' dur: ' + this.duration);
2386 if( this.isStoped() ){
2387 this.setStatus( this.getTimeReq() );
2388 }else if( this.isPaused() ){
2389 this.setStatus( "paused" );
2390 }else if( this.isPlaying() ){
2391 if( this.currentTime
&& ! this.duration
)
2392 this.setStatus( seconds2npt( this.currentTime
) + ' /' );
2394 this.setStatus(" - - - ");
2396 this.setStatus( this.getTimeReq() );
2399 //update buffer information
2400 this.updateBufferStatus();
2402 //update monitorTimerId to call child monitor
2403 if( ! this.monitorTimerId
){
2404 //make sure an instance of this.id exists:
2405 if( document
.getElementById(this.id
) ){
2406 this.monitorTimerId
= setInterval('$j(\'#'+this.id
+'\').get(0).monitor()', 250);
2410 stopMonitor:function(){
2411 if( this.monitorTimerId
!= 0 )
2413 clearInterval( this.monitorTimerId
);
2414 this.monitorTimerId
= 0;
2417 updateBufferStatus: function(){
2418 //build the buffer targeet based for playlist vs clip
2419 var buffer_select
= (this.pc
) ?
2420 '#cl_status_' + this.id
+ ' .ui-slider-buffer':
2421 '#' + this.id
+ ' .ui-slider-buffer';
2423 //update the buffer progress bar (if available )
2424 if( this.bufferedPercent
!= 0 ){
2425 //js_log('bufferedPercent: ' + this.bufferedPercent);
2426 if(this.bufferedPercent
> 1)
2427 this.bufferedPercent
=1;
2429 $j(buffer_select
).css("width", (this.bufferedPercent
*100) +'%' );
2431 $j(buffer_select
).css("width", '0px' );
2434 relativeCurrentTime: function(){
2435 if(!this.start_offset
)
2436 this.start_offset
=0;
2437 var rt
= this.currentTime
- this.start_offset
;
2438 if( rt
< 0 ) //should not happen but does.
2442 getPluginEmbed : function(){
2443 if (window
.document
[this.pid
]){
2444 return window
.document
[this.pid
];
2446 if ($j
.browser
.msie
){
2447 return document
.getElementById(this.pid
);
2449 if (document
.embeds
&& document
.embeds
[this.pid
])
2450 return document
.embeds
[this.pid
];
2454 //HELPER Functions for selected source
2456 * returns the selected source url for players to play
2458 getURI : function( seek_time_sec
){
2459 return this.media_element
.selected_source
.getURI( this.seek_time_sec
);
2461 supportsURLTimeEncoding: function(){
2462 //do head request if on the same domain
2463 return this.media_element
.selected_source
.URLTimeEncoding
;
2465 setSliderValue: function(perc
, hide_progress
){
2467 var this_id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2468 var val
= parseInt( perc
*1000 );
2469 $j('#'+this.id
+ ' .j-scrubber').slider('value', val
);
2471 //js_log('set#mv_seeker_slider_'+this_id + ' perc in: ' + perc + ' * ' + $j('#mv_seeker_'+this_id).width() + ' = set to: '+ val + ' - '+ Math.round(this.mv_seeker_width*perc) );
2472 //js_log('op:' + offset_perc + ' *('+perc+' * ' + $j('#slider_'+id).width() + ')');
2474 highlightPlaySection:function(options
){
2475 js_log('highlightPlaySection');
2476 var this_id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2477 var dur
= this.getDuration();
2478 var hide_progress
= true;
2479 //set the left percet and update the slider:
2480 rel_start_sec
= npt2seconds( options
['start']);
2481 //remove the start_offset if relevent:
2482 if(this.start_offset
)
2483 rel_start_sec
= rel_start_sec
- this.start_offset
2486 if( rel_start_sec
<= 0 ){
2488 options
['start'] = seconds2npt( this.start_offset
);
2490 this.setSliderValue( 0 , hide_progress
);
2492 left_perc
= parseInt( (rel_start_sec
/ dur
)*100 ) ;
2493 slider_perc
= (left_perc
/ 100);
2495 js_log("slider perc:" + slider_perc
);
2496 if( ! this.isPlaying() ){
2497 this.setSliderValue( slider_perc
, hide_progress
);
2500 width_perc
= parseInt( (( npt2seconds( options
['end'] ) - npt2seconds( options
['start'] ) ) / dur
)*100 ) ;
2501 if( (width_perc
+ left_perc
) > 100 ){
2502 width_perc
= 100 - left_perc
;
2504 //js_log('should hl: '+rel_start_sec+ '/' + dur + ' re:' + rel_end_sec+' lp:' + left_perc + ' width: ' + width_perc);
2505 $j('#mv_seeker_' + this_id
+ ' .mv_highlight').css({
2506 'left':left_perc
+'%',
2507 'width':width_perc
+'%'
2510 this.jump_time
= options
['start'];
2511 this.seek_time_sec
= npt2seconds( options
['start']);
2513 this.setStatus( gM('seek_to')+' '+ seconds2npt( this.seek_time_sec
) );
2514 js_log('DO update: ' + this.jump_time
);
2515 this.updateThumbTime( rel_start_sec
);
2517 hideHighlight:function(){
2518 var this_id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2519 $j('#mv_seeker_' + this_id
+ ' .mv_highlight').hide();
2520 this.setStatus( this.getTimeReq() );
2521 this.setSliderValue( 0 );
2523 setStatus:function(value
){
2524 var id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2526 //$j('#mv_time_'+id).html(value);
2527 $j('#'+this.id
+ ' .k-timer').html(value
);
2534 * mediaPlayer represents a media player plugin.
2535 * @param {String} id id used for the plugin.
2536 * @param {Array<String>} supported_types n array of supported MIME types.
2537 * @param {String} library external script containing the plugin interface code. (mv_<library>Embed.js)
2540 function mediaPlayer(id
, supported_types
, library
)
2543 this.supported_types
= supported_types
;
2544 this.library
= library
;
2545 this.loaded
= false;
2546 this.loading_callbacks
= new Array();
2549 mediaPlayer
.prototype =
2552 supported_types
:null,
2555 loading_callbacks
:null,
2556 supportsMIMEType : function(type
)
2558 for (var i
=0; i
< this.supported_types
.length
; i
++)
2559 if(this.supported_types
[i
] == type
)
2563 getName : function()
2565 return gM('mv_ogg-player-' + this.id
);
2567 load : function(callback
){
2568 var libName
= this.library
+'Embed';
2569 if( mvJsLoader
.checkObjPath( libName
) ){
2570 js_log('plugin loaded, do callback:');
2574 //jQuery based get script does not work so well.
2583 /* players and supported mime types
2584 @@todo ideally we query the plugin to get what mime types it supports in practice not always reliable/avaliable
2586 var flowPlayer
= new mediaPlayer('flowplayer',['video/x-flv', 'video/h264'],'flash');
2588 var omtkPlayer
= new mediaPlayer('omtkplayer',['audio/ogg'], 'omtk' );
2590 var cortadoPlayer
= new mediaPlayer('cortado',['video/ogg', 'audio/ogg'],'java');
2591 var videoElementPlayer
= new mediaPlayer('videoElement',['video/ogg', 'audio/ogg'],'native');
2593 var vlcMineList
= ['video/ogg','audio/ogg', 'video/x-flv', 'video/mp4', 'video/h264'];
2594 var vlcMozillaPlayer
= new mediaPlayer('vlc-mozilla',vlcMineList
,'vlc');
2595 var vlcActiveXPlayer
= new mediaPlayer('vlc-activex',vlcMineList
,'vlc');
2598 var oggPluginPlayer
= new mediaPlayer('oggPlugin',['video/ogg'],'generic');
2600 //depricate quicktime in favor of safari native
2601 //var quicktimeMozillaPlayer = new mediaPlayer('quicktime-mozilla',['video/ogg'],'quicktime');
2602 //var quicktimeActiveXPlayer = new mediaPlayer('quicktime-activex',['video/ogg'],'quicktime');
2604 var htmlPlayer
= new mediaPlayer('html',['text/html', 'image/jpeg', 'image/png', 'image/svg'], 'html');
2607 * mediaPlayers is a collection of mediaPlayer objects supported by the client.
2608 * It could be merged with embedTypes, since there is one embedTypes per script
2609 * and one mediaPlayers per embedTypes.
2611 function mediaPlayers()
2616 mediaPlayers
.prototype =
2620 default_players
: {},
2623 this.players
= new Array();
2624 this.loadPreferences();
2626 //set up default players order for each library type
2627 this.default_players
['video/x-flv'] = ['flash','vlc'];
2628 this.default_players
['video/h264'] = ['flash', 'vlc'];
2630 this.default_players
['video/ogg'] = ['native','vlc','java', 'generic'];
2631 this.default_players
['application/ogg'] = ['native','vlc','java', 'generic'];
2632 this.default_players
['audio/ogg'] = ['native','vlc', 'java', 'omtk' ];
2633 this.default_players
['video/mp4'] = ['vlc'];
2635 this.default_players
['text/html'] = ['html'];
2636 this.default_players
['image/jpeg'] = ['html'];
2637 this.default_players
['image/png'] = ['html'];
2638 this.default_players
['image/svg'] = ['html'];
2641 addPlayer : function(player
, mime_type
)
2643 //js_log('Adding ' + player.id + ' with mime_type ' + mime_type);
2644 for (var i
=0; i
< this.players
.length
; i
++){
2645 if (this.players
[i
].id
== player
.id
)
2649 //make sure the mime_type is not already there:
2650 var add_mime
= true;
2651 for(var j
=0; j
< this.players
[i
].supported_types
.length
; j
++ ){
2652 if( this.players
[i
].supported_types
[j
]== mime_type
)
2656 this.players
[i
].supported_types
.push(mime_type
);
2663 player
.supported_types
.push(mime_type
);
2665 this.players
.push( player
);
2667 getMIMETypePlayers : function(mime_type
)
2669 var mime_players
= new Array();
2672 if( this.default_players
[mime_type
] ){
2673 $j
.each( this.default_players
[mime_type
], function(d
, lib
){
2674 var library
= _this
.default_players
[mime_type
][d
];
2675 for ( var i
=0; i
< _this
.players
.length
; i
++ ){
2676 if ( _this
.players
[i
].library
== library
&& _this
.players
[i
].supportsMIMEType(mime_type
) ){
2677 mime_players
[ inx
] = _this
.players
[i
];
2683 return mime_players
;
2685 defaultPlayer : function(mime_type
)
2687 js_log("get defaultPlayer for " + mime_type
);
2688 var mime_players
= this.getMIMETypePlayers(mime_type
);
2689 if( mime_players
.length
> 0)
2691 // check for prior preference for this mime type
2692 for( var i
=0; i
< mime_players
.length
; i
++ ){
2693 if( mime_players
[i
].id
==this.preference
[mime_type
] )
2694 return mime_players
[i
];
2696 // otherwise just return the first compatible player
2697 // (it will be chosen according to the default_players list
2698 return mime_players
[0];
2700 js_log( 'No default player found for ' + mime_type
);
2703 userSelectFormat : function (mime_format
){
2704 this.preference
['format_prefrence'] = mime_format
;
2705 this.savePreferences();
2707 userSelectPlayer : function(player_id
, mime_type
)
2709 var selected_player
=null;
2710 for(var i
=0; i
< this.players
.length
; i
++){
2711 if(this.players
[i
].id
== player_id
)
2713 selected_player
= this.players
[i
];
2714 js_log('choosing ' + player_id
+ ' for ' + mime_type
);
2715 this.preference
[mime_type
]=player_id
;
2716 this.savePreferences();
2720 if( selected_player
)
2722 for(var i
=0; i
< global_player_list
.length
; i
++)
2724 var embed
= $j('#'+global_player_list
[i
]).get(0);
2725 if(embed
.media_element
.selected_source
&& (embed
.media_element
.selected_source
.mime_type
== mime_type
))
2727 embed
.selectPlayer(selected_player
);
2728 js_log('using ' + embed
.selected_player
.getName() + ' for ' + embed
.media_element
.selected_source
.getTitle());
2733 loadPreferences : function()
2735 this.preference
= new Object();
2736 // see if we have a cookie set to a clientSupported type:
2737 var cookieVal
= $j
.cookie( 'ogg_player_exp' );
2740 var pairs
= cookieVal
.split('&');
2741 for(var i
=0; i
< pairs
.length
; i
++)
2743 var name_value
= pairs
[i
].split('=');
2744 this.preference
[name_value
[0]]=name_value
[1];
2745 //js_log('load preference for ' + name_value[0] + ' is ' + name_value[1]);
2749 savePreferences : function()
2752 for(var i
in this.preference
)
2753 cookieVal
+= i
+ '='+ this.preference
[i
] + '&';
2755 cookieVal
=cookieVal
.substr(0, cookieVal
.length
-1);
2756 var week
= 7*86400*1000;
2757 $j
.cookie( 'ogg_player_exp', cookieVal
, { 'expires':week
} );
2762 * embedTypes object handles setting and getting of supported embed types:
2763 * closely mirrors OggHandler so that its easier to share efforts in this area:
2764 * http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/OggHandler/OggPlayer.js
2771 //detect supported types
2773 this.detect_done
=true;
2775 clientSupports
: { 'thumbnail' : true },
2776 supportedMimeType: function(mimetype
) {
2777 for (var i
= navigator
.plugins
.length
; i
-- > 0; ) {
2778 var plugin
= navigator
.plugins
[i
];
2779 if (typeof plugin
[mimetype
] != "undefined")
2785 detect: function() {
2786 js_log("running detect");
2787 this.players
= new mediaPlayers();
2788 //every browser supports html rendering:
2789 this.players
.addPlayer( htmlPlayer
);
2790 // In Mozilla, navigator.javaEnabled() only tells us about preferences, we need to
2791 // search navigator.mimeTypes to see if it's installed
2792 var javaEnabled
= navigator
.javaEnabled();
2793 // In Opera, navigator.javaEnabled() is all there is
2794 var invisibleJava
= $j
.browser
.opera
;
2795 // Some browsers filter out duplicate mime types, hiding some plugins
2796 var uniqueMimesOnly
= $j
.browser
.opera
|| $j
.browser
.safari
;
2797 // Opera will switch off javaEnabled in preferences if java can't be found.
2798 // And it doesn't register an application/x-java-applet mime type like Mozilla does.
2799 if ( invisibleJava
&& javaEnabled
)
2800 this.players
.addPlayer( cortadoPlayer
);
2803 if($j
.browser
.msie
){
2805 if ( this.testActiveX( 'ShockwaveFlash.ShockwaveFlash')){
2806 //try to get the flash version for omtk include:
2808 a
= new ActiveXObject(SHOCKWAVE_FLASH_AX
+ ".7");
2809 d
= a
.GetVariable("$version"); // Will crash fp6.0.21/23/29
2811 d
= d
.split(" ")[1].split(",");
2812 //we need flash version 10 or greater:
2813 if(parseInt( d
[0]) >=10){
2814 this.players
.addPlayer( omtkPlayer
);
2820 //flowplayer has pretty good compatiablity
2821 // (but if we wanted to be fancy we would check for version of flash and update the mp4/h.264 support
2822 this.players
.addPlayer( flowPlayer
);
2825 if ( this.testActiveX( 'VideoLAN.VLCPlugin.2' ) )
2826 this.players
.addPlayer(vlcActiveXPlayer
);
2828 if ( javaEnabled
&& this.testActiveX( 'JavaWebStart.isInstalled' ) )
2829 this.players
.addPlayer(cortadoPlayer
);
2831 //if ( this.testActiveX( 'QuickTimeCheckObject.QuickTimeCheck.1' ) )
2832 // this.players.addPlayer(quicktimeActiveXPlayer);
2835 if ( typeof HTMLVideoElement
== 'object' // Firefox, Safari
2836 || typeof HTMLVideoElement
== 'function' ) // Opera
2838 //do another test for safari:
2839 if( $j
.browser
.safari
){
2841 var dummyvid
= document
.createElement("video");
2842 if (dummyvid
.canPlayType
&& dummyvid
.canPlayType("video/ogg;codecs=\"theora,vorbis\"") == "probably")
2844 this.players
.addPlayer( videoElementPlayer
);
2845 } else if(this.supportedMimeType( 'video/ogg' )) {
2846 /* older versions of safari do not support canPlayType,
2847 but xiph qt registers mimetype via quicktime plugin */
2848 this.players
.addPlayer( videoElementPlayer
);
2850 //@@todo add some user nagging to install the xiph qt
2853 js_log('could not run canPlayType in safari');
2856 this.players
.addPlayer( videoElementPlayer
);
2861 if( navigator
.mimeTypes
&& navigator
.mimeTypes
.length
> 0) {
2862 for ( var i
= 0; i
< navigator
.mimeTypes
.length
; i
++ ) {
2863 var type
= navigator
.mimeTypes
[i
].type
;
2864 var semicolonPos
= type
.indexOf( ';' );
2865 if ( semicolonPos
> -1 ) {
2866 type
= type
.substr( 0, semicolonPos
);
2868 //js_log('on type: '+type);
2869 var pluginName
= navigator
.mimeTypes
[i
].enabledPlugin
? navigator
.mimeTypes
[i
].enabledPlugin
.name
: '';
2870 if ( !pluginName
) {
2871 // In case it is null or undefined
2874 if ( pluginName
.toLowerCase() == 'vlc multimedia plugin' || pluginName
.toLowerCase() == 'vlc multimedia plug-in' ) {
2875 this.players
.addPlayer(vlcMozillaPlayer
, type
);
2879 if ( javaEnabled
&& type
== 'application/x-java-applet' ) {
2880 this.players
.addPlayer(cortadoPlayer
);
2884 if ( type
== 'application/ogg' ) {
2885 if ( pluginName
.toLowerCase() == 'vlc multimedia plugin' ){
2886 this.players
.addPlayer(vlcMozillaPlayer
, type
);
2887 //else if ( pluginName.indexOf( 'QuickTime' ) > -1 )
2888 // this.players.addPlayer(quicktimeMozillaPlayer);
2890 this.players
.addPlayer(oggPluginPlayer
);
2893 } else if ( uniqueMimesOnly
) {
2894 if ( type
== 'application/x-vlc-player' ) {
2895 this.players
.addPlayer(vlcMozillaPlayer
, type
);
2897 } else if ( type
== 'video/quicktime' ) {
2898 //this.players.addPlayer(quicktimeMozillaPlayer);
2903 /*if ( type == 'video/quicktime' ) {
2904 this.players.addPlayer(vlcMozillaPlayer, type);
2907 if(type
=='application/x-shockwave-flash'){
2908 this.players
.addPlayer( flowPlayer
);
2910 //check version to add omtk:
2911 var flashDescription
= navigator
.plugins
["Shockwave Flash"].description
;
2912 var descArray
= flashDescription
.split(" ");
2913 var tempArrayMajor
= descArray
[2].split(".");
2914 var versionMajor
= tempArrayMajor
[0];
2915 //js_log("version of flash: " + versionMajor);
2916 if(versionMajor
>= 10){
2917 this.players
.addPlayer( omtkPlayer
);
2923 //@@The xiph quicktime component does not work well with annodex streams (temporarly disable)
2924 //this.clientSupports['quicktime-mozilla'] = false;
2925 //this.clientSupports['quicktime-activex'] = false;
2926 //js_log(this.clientSupports);
2928 testActiveX : function ( name
) {
2931 // No IE, not a class called "name", it's a variable
2932 var obj
= new ActiveXObject( '' + name
);