1 /* the base video control JSON object with default attributes
2 * for supported attribute details see README
6 "loading_plugin" : "loading plugin<blink>...</blink>",
8 "select_playback" : "Set Playback Preference",
9 "link_back" : "Link Back",
10 "error_load_lib" : "mv_embed: Unable to load required javascript libraries\n insert script via DOM has failed, try reloading? ",
12 "error_swap_vid" : "Error:mv_embed was unable to swap the video tag for the mv_embed interface",
14 "add_to_end_of_sequence" : "Add to End of Sequence",
16 "missing_video_stream" : "The video file for this stream is missing",
18 "play_clip" : "Play Clip",
19 "pause_clip": "Pause Clip",
20 "volume_control": "Volume Control",
21 "player_options": "Player Options",
22 "closed_captions": "Close Captions",
23 "player_fullscreen": "Fullscreen",
25 "next_clip_msg" : "Play Next Clip",
26 "prev_clip_msg" : "Play Previous Clip",
27 "current_clip_msg" : "Continue Playing this Clip",
28 "seek_to" : "Seek to",
30 "download_segment" : "Download Selection:",
31 "download_full" : "Download Full Video File:",
32 "download_right_click": "To download right click and select <i>save target as</i>",
33 "download_clip" : "Download the Clip",
34 "download_text" : "Download Text (<a style=\"color:white\" title=\"cmml\" href=\"http://wiki.xiph.org/index.php/CMML\">cmml</a> xml):",
36 "clip_linkback" : "Clip Source Page",
38 "mv_ogg-player-vlc-mozilla" : "VLC Plugin",
39 "mv_ogg-player-videoElement" : "Native Ogg Video Support",
40 "mv_ogg-player-vlc-activex" : "VLC ActiveX",
41 "mv_ogg-player-oggPlugin" : "Generic Ogg Plugin",
42 "mv_ogg-player-quicktime-mozilla" : "Quicktime Plugin",
43 "mv_ogg-player-quicktime-activex" : "Quicktime ActiveX",
44 "mv_ogg-player-cortado" : "Java Cortado",
45 "mv_ogg-player-flowplayer" : "Flowplayer",
46 "mv_ogg-player-selected" : " (selected)",
47 "mv_ogg-player-omtkplayer" : "OMTK Flash Vorbis",
48 "mv_generic_missing_plugin" : "You browser does not appear to support 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>",
50 "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>",
51 "mv_do_not_warn_again": "Dissmiss for now."
55 var default_video_attributes
= {
72 //roe url (for xml based metadata)
74 //if roe includes metadata tracks we can expose a link to metadata
75 "show_meta_link":true,
77 //default state attributes per html5 spec:
78 //http://www.whatwg.org/specs/web-apps/current-work/#video)
80 "readyState":0, //http://www.whatwg.org/specs/web-apps/current-work/#readystate
81 "currentTime":0, //current playback position (should be updated by plugin)
82 "duration":null, //media duration (read from file or the temporal url)
85 "startOffset":null, //if serving an ogg_chop segment use this to offset the presentation time
87 //custom attributes for mv_embed:
93 "type":null //the content type of the media
96 * the base source attibute checks
98 var mv_default_source_attr
= new Array(
102 'URLTimeEncoding', //boolean if we support temporal url requests on the source media
110 //set the dismissNativeWarn flag:
111 _global
['dismissNativeWarn'] = false;
113 * Converts all occurrences of <video> tag into video object
115 function mv_video_embed(swap_done_callback
, force_id
){
116 mvEmbed
.init( swap_done_callback
, force_id
);
119 //flist stores the set of functions to run after the video has been swaped in.
121 init:function( swap_done_callback
, force_id
){
123 if(swap_done_callback
)
124 mvEmbed
.flist
.push( swap_done_callback
);
126 //get mv_embed location if it has not been set
127 js_log('mv_embed ' + MV_EMBED_VERSION
);
129 var loadPlaylistLib
=false;
131 var eAction = function(this_elm
){
132 js_log( "Do SWAP: " + $j(this_elm
).attr("id") + ' tag: '+ this_elm
.tagName
.toLowerCase() );
134 if( $j(this_elm
).attr("id") == '' ){
135 $j(this_elm
).attr("id", 'v'+ global_player_list
.length
);
137 //stre a global reference to the id
138 global_player_list
.push( $j(this_elm
).attr("id") );
140 switch( this_elm
.tagName
.toLowerCase()){
142 var videoInterface
= new embedVideo(this_elm
);
143 mvEmbed
.swapEmbedVideoElement( this_elm
, videoInterface
);
146 var videoInterface
= new embedVideo(this_elm
);
147 videoInterface
.type
='audio';
148 mvEmbed
.swapEmbedVideoElement( this_elm
, videoInterface
);
151 loadPlaylistLib
=true;
156 if( force_id
== null && force_id
!= '' ){
157 var j_selector
= 'video,audio,playlist';
159 var j_selector
= '#'+force_id
;
161 //process selected elements:
162 //ie8 does not play well with the jQuery video,audio,playlist selector use native:
163 if($j
.browser
.msie
&& $j
.browser
.version
>= 8){
164 jtags
= j_selector
.split(',');
165 for( var i
=0; i
< jtags
.length
; i
++){
166 $j( document
.getElementsByTagName( jtags
[i
] )).each(function(){
171 $j( j_selector
).each(function(){
178 '$j.ui', //include dialog for pop-ing up thigns
181 $j('playlist').each(function(){
182 //create new playlist interface:
183 var plObj
= new mvPlayList( this );
184 mvEmbed
.swapEmbedVideoElement(this, plObj
);
185 var added_height
= plObj
.pl_layout
.title_bar_height
+ plObj
.pl_layout
.control_height
;
186 //move into a blocking display container with height + controls + title height:
187 $j('#'+plObj
.id
).wrap('<div style="display:block;height:' + (plObj
.height
+ added_height
) + 'px;"></div>');
191 this.checkClipsReady();
194 * swapEmbedVideoElement
195 * takes a video element as input and swaps it out with
196 * an embed video interface based on the video_elements attributes
198 swapEmbedVideoElement:function(video_element
, videoInterface
){
199 js_log('do swap ' + videoInterface
.id
+ ' for ' + video_element
);
200 embed_video
= document
.createElement('div');
201 //make sure our div has a hight/width set:
203 $j(embed_video
).css({
204 'width':videoInterface
.width
,
205 'height':videoInterface
.height
206 }).html( mv_get_loading_img() );
207 //inherit the video interface
208 for(var method
in videoInterface
){ //for in loop oky in Element context
209 if(method
!='readyState'){ //readyState crashes IE
211 embed_video
.setAttribute('style', videoInterface
[method
]);
212 }else if(method
=='class'){
213 if( $j
.browser
.msie
)
214 embed_video
.setAttribute("className", videoInterface
['class']);
216 embed_video
.setAttribute("class", videoInterface
['class']);
219 embed_video
[method
]=videoInterface
[method
];
223 if(embed_video
[method
]=="false")embed_video
[method
]=false;
224 if(embed_video
[method
]=="true")embed_video
[method
]=true;
226 ///js_log('did vI style');
227 //now swap out the video element for the embed_video obj:
228 $j(video_element
).after(embed_video
).remove();
229 //js_log('did swap');
230 $j('#'+embed_video
.id
).get(0).on_dom_swap();
231 // now that "embed_video" is stable, do more initialization (if we are ready)
232 if($j('#'+embed_video
.id
).get(0).loading_external_data
==false &&
233 $j('#'+embed_video
.id
).get(0).init_with_sources_loadedDone
==false){
234 //load and set ready state since source are available:
235 $j('#'+embed_video
.id
).get(0).init_with_sources_loaded();
237 js_log('done with child: ' + embed_video
.id
+ ' len:' + global_player_list
.length
);
240 //this should not be needed.
241 checkClipsReady : function(){
242 //js_log('checkClipsReady');
244 for(var i
=0; i
< global_player_list
.length
; i
++){
245 if( $j('#'+global_player_list
[i
]).length
!=0){
246 var cur_vid
= $j('#'+global_player_list
[i
]).get(0);
247 is_ready
= ( cur_vid
.ready_to_play
) ? is_ready
: false;
248 if( !is_ready
&& cur_vid
.load_error
){
250 $j(cur_vid
).html( cur_vid
.load_error
);
255 mvEmbed
.allClipsReady
= true;
256 // run queued functions
257 //js_log('run queded functions:' + mvEmbed.flist[0]);
260 setTimeout( 'mvEmbed.checkClipsReady()', 25 );
264 while (this.flist
.length
){
265 this.flist
.shift()();
280 getControls:function( embedObj
){
281 js_log('f:controlsBuilder:: opt:' + this.options
);
282 this.id
= (embedObj
.pc
)?embedObj
.pc
.pp
.id
:embedObj
.id
;
283 this.available_width
= embedObj
.playerPixelWidth();
284 //make pointer to the embedObj
285 this.embedObj
=embedObj
;
287 $j
.each( embedObj
.supports
, function( i
, sup
){
288 _this
.supports
[i
] = embedObj
.supports
[i
];
292 if( ( embedObj
.roe
|| embedObj
.media_element
.timedTextSources() )
293 && embedObj
.show_meta_link
)
294 this.supports
['closed_captions']=true;
297 //append options to body (if not already there)
298 if($j('#mv_vid_options_'+ctrlBuilder
.id
).length
==0)
299 $j('body').append( this.components
['mv_embedded_options'].o() );
302 for( var i
in this.components
){
303 if( this.supports
[i
] ){
304 if( this.available_width
> this.components
[i
].w
){
305 //special case with playhead don't add unless we have 60px
306 if( i
== 'play_head' && ctrlBuilder
.available_width
< 60 )
308 o
+=this.components
[i
].o();
309 this.available_width
-= this.components
[i
].w
;
311 js_log('not enough space for control component:' + i
);
319 * to be run once controls are attached to the dom
321 addControlHooks:function(embedObj
){
322 //add in drag/seek hooks:
323 if(!embedObj
.base_seeker_slider_offset
&& $j('#mv_seeker_slider_'+embedObj
.id
).get(0))
324 embedObj
.base_seeker_slider_offset
= $j('#mv_seeker_slider_'+embedObj
.id
).get(0).offsetLeft
;
326 //js_log('looking for: #mv_seeker_slider_'+embedObj.id + "\n " +
327 // 'start sec: '+embedObj.start_time_sec + ' base offset: '+embedObj.base_seeker_slider_offset);
330 $j('#mv_play_pause_button_' + embedObj
.id
).unbind().btnBind().click(function(){
331 $j('#' + embedObj
.id
).get(0).play();
334 //big_play_link_ play binding:
335 $j('#big_play_link_' + embedObj
.id
).unbind().click(function(){
336 $j('#' + embedObj
.id
).get(0).play();
339 //add recomend firefox if non-native playback:
340 if( embedObj
.doNativeWarningCheck() ){
341 $j('#dc_'+ embedObj
.id
).hover(
343 if($j('#gnp_' + embedObj
.id
).length
==0){
344 $j(this).append('<div id="gnp_' + embedObj
.id
+ '" class="ui-state-highlight ui-corner-all" ' +
345 'style="position:absolute;display:none;background:#FFF;top:10px;left:10px;right:10px;height:60px;">' +
346 gM('mv_for_best_experience') +
347 '<br><input id="ffwarn_'+embedObj
.id
+'" type=\"checkbox\">' +
348 gM('mv_do_not_warn_again') +
350 $j('#ffwarn_'+embedObj
.id
).click(function(){
351 if( $j(this).is(':checked') ){
352 //set up a cookie for 7 days:
353 $j
.cookie('dismissNativeWarn', true, { expires
: 5 });
354 //set the current instance
355 _global
['dismissNativeWarn'] = true;
356 $j('#gnp_' + embedObj
.id
).fadeOut('slow');
358 _global
['adismissNativeWarn'] = false;
359 $j
.cookie('dismissNativeWarn', false);
364 if( ($j
.cookie('dismissNativeWarn') !== true) &&
365 _global
['dismissNativeWarn'] === false ){
366 $j('#gnp_' + embedObj
.id
).fadeIn('slow');
370 $j('#gnp_' + embedObj
.id
).fadeOut('slow');
375 if( $j
.browser
.msie
&& $j
.browser
.version
<= 6){
376 $j('#big_play_link_' + embedObj
.id
).pngFix();
381 $j('#timed_text_' + embedObj
.id
).unbind().btnBind().click(function(){
382 $j('#' + embedObj
.id
).get(0).showTextInterface();
386 $j('#options_button_' + embedObj
.id
).unbind().btnBind().click(function(){
387 $j('#' +embedObj
.id
).get(0).doOptionsHTML();
390 //fullscreen binding:
391 $j('#fullscreen_'+embedObj
.id
).unbind().btnBind().click(function(){
392 $j('#' +embedObj
.id
).get(0).fullscreen();
395 js_log(" should add slider binding: " + $j('#mv_play_head_'+embedObj
.id
).length
) ;
396 $j('#mv_play_head_'+embedObj
.id
).slider({
401 start: function(event
, ui
){
402 var id
= (embedObj
.pc
!=null)?embedObj
.pc
.pp
.id
:embedObj
.id
;
403 embedObj
.userSlide
=true;
404 $j('#big_play_link_'+id
).fadeOut('fast');
405 //if playlist always start at 0
406 embedObj
.start_time_sec
= (embedObj
.instanceOf
== 'mvPlayList')?0:
407 npt2seconds(embedObj
.getTimeReq().split('/')[0]);
409 slide: function(event
, ui
) {
410 var perc
= ui
.value
/1000;
411 embedObj
.jump_time
= seconds2npt( parseFloat( parseFloat(embedObj
.getDuration()) * perc
) + embedObj
.start_time_sec
);
412 //js_log('perc:' + perc + ' * ' + embedObj.getDuration() + ' jt:'+ this.jump_time);
413 embedObj
.setStatus( gM('seek_to')+' '+embedObj
.jump_time
);
414 //update the thumbnail / frame
415 if(embedObj
.isPlaying
==false){
416 embedObj
.updateThumbPerc( perc
);
419 change:function(event
, ui
){
420 //only run the onChange event if done by a user slide:
421 if(embedObj
.userSlide
){
422 embedObj
.userSlide
=false;
423 embedObj
.seeking
=true;
424 //stop the monitor timer (if we can)
425 if(embedObj
.stopMonitor
)
426 embedObj
.stopMonitor();
428 var perc
= ui
.value
/1000;
429 //set seek time (in case we have to do a url seek)
430 embedObj
.seek_time_sec
= npt2seconds( embedObj
.jump_time
, true );
431 js_log('do jump to: '+embedObj
.jump_time
+ ' perc:' +perc
+ ' sts:' + embedObj
.seek_time_sec
);
432 embedObj
.doSeek(perc
);
436 //up the z-index of the default status indicator:
437 $j('#mv_play_head_'+embedObj
.id
+ ' .ui-slider-handle').css('z-index', 4);
438 $j('#mv_play_head_'+embedObj
.id
+ ' .ui-slider-range').addClass('ui-corner-all').css('z-index', 2);
439 //extended class list for jQuery ui themeing (we can probably refactor this with custom buffering highliter)
440 $j('#mv_play_head_'+embedObj
.id
).append( ctrlBuilder
.getMvBufferHtml() );
443 $j('#mv_vid_options_'+ctrlBuilder
.id
+' .vo_selection').click(function(){
444 embedObj
.selectPlaybackMethod();
445 $j('#mv_vid_options_'+ctrlBuilder
.id
).hide();
448 $j('#mv_vid_options_'+ctrlBuilder
.id
+' .vo_download').click(function(){
449 embedObj
.showVideoDownload();
450 $j('#mv_vid_options_'+ctrlBuilder
.id
).hide();
453 $j('#mv_vid_options_'+ctrlBuilder
.id
+' .vo_showcode').click(function(){
454 embedObj
.showEmbedCode();
455 $j('#mv_vid_options_'+ctrlBuilder
.id
).hide();
460 var hoverOverDelay
=false;
461 $j('#volume_control_'+embedObj
.id
).unbind().btnBind().click(function(){
462 $j('#' +embedObj
.id
).get(0).toggleMute();
465 $j('#vol_container_' + embedObj
.id
).addClass('vol_container_top');
466 //set to "below" if playing and embedType != native
467 if(embedObj
&& embedObj
.isPlaying() && !embedObj
.supports
['overlays']){
468 $j('#vol_container_' + embedObj
.id
).removeClass('vol_container_top').addClass('vol_container_below');
471 $j('#vol_container_' + embedObj
.id
).fadeIn('fast');
472 hoverOverDelay
= true;
475 hoverOverDelay
= false;
476 setTimeout(function doHideVolume(){
478 $j('#vol_container_' + embedObj
.id
).fadeOut('fast');
484 $j('#volume_bar_'+embedObj
.id
).slider({
485 orientation
: "vertical",
490 slide: function(event
, ui
) {
491 var perc
= ui
.value
/100;
492 //js_log('update volume:' + perc);
493 embedObj
.updateVolumen(perc
);
495 change:function(event
, ui
){
496 var perc
= ui
.value
/100;
498 $j('#volume_control_'+embedObj
.id
+ ' span').removeClass('ui-icon-volume-on').addClass('ui-icon-volume-off');
500 $j('#volume_control_'+embedObj
.id
+ ' span').removeClass('ui-icon-volume-off').addClass('ui-icon-volume-on');
502 //only run the onChange event if done by a user slide:
503 if(embedObj
.userSlide
){
504 embedObj
.userSlide
=false;
505 embedObj
.seeking
=true;
506 var perc
= ui
.value
/100;
507 embedObj
.updateVolumen(perc
);
513 getMvBufferHtml:function(){
514 return '<div class="ui-slider-range ui-slider-range-min ui-widget-header ' +
515 'ui-state-highlight ui-corner-all '+
516 'mv_buffer" style="width:0px;height:100%;z-index:1;top:0px" />';
525 'mv_embedded_options':{
528 var o
= '<div id="mv_vid_options_'+ctrlBuilder
.id
+'" class="videoOptions">'+
529 '<div class="videoOptionsTop"></div>'+
530 '<div class="videoOptionsBox">'+
531 '<div class="block">'+
532 '<h6>Video Options</h6>'+
534 '<div class="block">'+
535 '<p class="short_match vo_selection"><a href="#"><span>Stream Selection</span></a></p>'+
536 '<p class="short_match vo_download"><a href="#"><span>Download</span></a></p>'+
537 '<p class="short_match vo_showcode"><a href="#"><span>Share or Embed</span></a></p>';
539 //link to the stream page if we are not already there:
540 if( ctrlBuilder
.embedObj
.roe
&& typeof mv_stream_interface
== 'undefined' )
541 o
+='<p class="short_match"><a href="javascript:$j(\'#'+ctrlBuilder
.id
+'\').get(0).doLinkBack()"><span><strong>Source Page</strong></span></a></p>';
544 '</div><!--videoOptionsInner-->' +
545 '<div class="videoOptionsBot"></div>' +
546 '</div><!--videoOptions-->';
553 return '<div title="' + gM('player_fullscreen') + '" id="fullscreen_'+ctrlBuilder
.id
+'" class="ui-state-default ui-corner-all ui-icon_link rButton"><span class="ui-icon ui-icon-arrow-4-diag"></span></div>'
559 return '<div title="'+ gM('player_options') + '" id="options_button_'+ctrlBuilder
.id
+'" class="ui-state-default ui-corner-all ui-icon_link rButton"><span class="ui-icon ui-icon-wrench"></span></div>';
565 return '<div title="' + gM('play_clip') + '" id="mv_play_pause_button_' + ctrlBuilder
.id
+ '" class="ui-state-default ui-corner-all ui-icon_link lButton"><span class="ui-icon ui-icon-play"/></div>';
571 return '<div title="' + gM('closed_captions') + '" id="timed_text_'+ctrlBuilder
.id
+'" class="ui-state-default ui-corner-all ui-icon_link rButton"><span class="ui-icon ui-icon-comment"></span></div>'
577 return '<div title="' + gM('volume_control') + '" id="volume_control_'+ctrlBuilder
.id
+'" class="ui-state-default ui-corner-all ui-icon_link rButton">' +
578 '<span class="ui-icon ui-icon-volume-on"></span>' +
579 '<div style="position:absolute;display:none;" id="vol_container_'+ctrlBuilder
.id
+'" class="vol_container ui-corner-all">' +
580 '<div class="volume_bar" id="volume_bar_' + ctrlBuilder
.id
+ '"></div>' +
588 return '<div id="mv_time_'+ctrlBuilder
.id
+'" class="ui-widget time">' + ctrlBuilder
.embedObj
.getTimeReq() + '</div>';
592 'w':0, //special case (takes up remaining space)
594 return '<div class="play_head" id="mv_play_head_' + ctrlBuilder
.id
+ '" style="width: ' + ( ctrlBuilder
.available_width
- 30 ) + 'px;"></div>';
601 * mediaSource class represents a source for a media element.
602 * @param {String} type MIME type of the source.
603 * @param {String} uri URI of the source.
606 function mediaSource(element
)
612 mediaSource
.prototype =
614 /** MIME type of the source. */
616 /** URI of the source. */
618 /** Title of the source. */
620 /** True if the source has been marked as the default. */
621 marked_default
:false,
622 /** True if the source supports url specification of offset and duration */
623 URLTimeEncoding
:false,
624 /** Start offset of the requested segment */
626 /** Duration of the requested segment (0 if not known) */
629 upddate_interval
:null,
635 init : function(element
)
637 //js_log('adding mediaSource: ' + element);
638 this.src
= $j(element
).attr('src');
639 this.marked_default
= false;
640 if ( element
.tagName
.toLowerCase() == 'video')
641 this.marked_default
= true;
643 //set default URLTimeEncoding if we have a time url:
644 //not ideal way to discover if content is on an oggz_chop server.
645 //should check some other way.
646 var pUrl
= parseUri ( this.src
);
647 if(typeof pUrl
['queryKey']['t'] != 'undefined'){
648 this['URLTimeEncoding']=true;
650 for(var i
=0; i
< mv_default_source_attr
.length
; i
++){ //array loop:
651 var attr
= mv_default_source_attr
[ i
];
652 if( $j(element
).attr( attr
) ) {
653 this[ attr
] = $j(element
).attr( attr
);
656 //update duration from hit if present:
657 if(this.durationHint
)
658 this.duration
= this.durationHint
;
661 if ( $j(element
).attr('type'))
662 this.mime_type
= $j(element
).attr('type');
663 else if ($j(element
).attr('content-type'))
664 this.mime_type
= $j(element
).attr('content-type');
666 this.mime_type
= this.detectType(this.src
);
668 //set the title if unset:
670 this.title
= this.mime_type
;
672 this.parseURLDuration();
674 updateSource:function(element
){
675 //for now just update the title:
676 if ($j(element
).attr("title"))
677 this.title
= $j(element
).attr("title");
679 /** updates the src time and start & end
680 * @param {String} start_time in NTP format
681 * @param {String} end_time in NTP format
683 updateSrcTime:function (start_ntp
, end_ntp
){
684 //js_log("f:updateSrcTime: "+ start_ntp+'/'+ end_ntp + ' from org: ' + this.start_ntp+ '/'+this.end_ntp);
685 //js_log("pre uri:" + this.src);
686 //if we have time we can use:
687 if( this.URLTimeEncoding
){
688 //make sure its a valid start time / end time (else set default)
689 if( !npt2seconds(start_ntp
) )
690 start_ntp
= this.start_ntp
;
692 if( !npt2seconds(end_ntp
) )
693 end_ntp
= this.end_ntp
;
695 this.src
= getURLParamReplace(this.src
, { 't': start_ntp
+'/'+ end_ntp
} );
697 //update the duration
698 this.parseURLDuration();
701 setDuration:function (duration
)
703 this.duration
= duration
;
705 this.end_ntp
= seconds2npt( this.start_offset
+ duration
);
708 /** MIME type accessor function.
709 @return the MIME type of the source.
712 getMIMEType : function()
714 return this.mime_type
;
716 /** URI accessor function.
717 * @param int seek_time_sec (used to adjust the URI for url based seeks)
718 @return the URI of the source.
721 getURI : function( seek_time_sec
)
723 if( !seek_time_sec
|| !this.URLTimeEncoding
){
729 var endvar
= '/'+ this.end_ntp
;
731 return getURLParamReplace(this.src
, { 't': seconds2npt( seek_time_sec
)+endvar
} ); ;
733 /** Title accessor function.
734 @return the title of the source.
737 getTitle : function()
741 /** Index accessor function.
742 @return the source's index within the enclosing mediaElement container.
745 getIndex : function()
750 * function getDuration in milliseconds
751 * special case derive duration from request url
752 * supports media_url?t=ntp_start/ntp_end url request format
754 parseURLDuration : function(){
755 //check if we have a URLTimeEncoding:
756 if( this.URLTimeEncoding
){
757 var annoURL
= parseUri( this.src
);
758 if( annoURL
.queryKey
['t'] ){
759 var times
= annoURL
.queryKey
['t'].split('/');
760 this.start_ntp
= times
[0];
761 this.end_ntp
= times
[1];
762 this.start_offset
= npt2seconds( this.start_ntp
);
763 this.duration
= npt2seconds( this.end_ntp
) - this.start_offset
;
765 //look for this info as attributes
766 if(this.startOffset
){
767 this.start_offset
= this.startOffset
;
768 this.start_ntp
= seconds2npt( this.startOffset
);
771 this.end_ntp
= seconds2npt( parseInt(this.duration
) + parseInt(this.start_offset
) );
775 //else nothing to parse just keep whatever info we already have
777 //js_log('f:parseURLDuration() for:' + this.src + ' d:' + this.duration);
779 /** Attempts to detect the type of a media file based on the URI.
780 @param {String} uri URI of the media file.
781 @returns The guessed MIME type of the file.
784 detectType:function(uri
)
786 //@@todo if media is on the same server as the javascript or we have mv_proxy configured
787 //we can issue a HEAD request and read the mime type of the media...
788 // (this will detect media mime type independently of the url name)
789 //http://www.jibbering.com/2002/4/httprequest.html (this should be done by extending jquery's ajax objects)
790 var end_inx
= (uri
.indexOf('?')!=-1)? uri
.indexOf('?') : uri
.length
;
791 var no_param_uri
= uri
.substr(0, end_inx
);
792 switch( no_param_uri
.substr(no_param_uri
.lastIndexOf('.'),4).toLowerCase() ){
793 case '.flv':return 'video/x-flv';break;
794 case '.ogg': case '.ogv': return 'video/ogg';break;
795 case '.oga': return 'audio/ogg'; break;
796 case '.anx':return 'video/ogg';break;
801 /** A media element corresponding to a <video> element.
802 It is implemented as a collection of mediaSource objects. The media sources
803 will be initialized from the <video> element, its child <source> elements,
804 and/or the ROE file referenced by the <video> element.
805 @param {element} video_element <video> element used for initialization.
808 function mediaElement(video_element
)
810 this.init(video_element
);
813 mediaElement
.prototype =
815 /** The array of mediaSource elements. */
818 /** Selected mediaSource element. */
819 selected_source
:null,
824 init:function( video_element
)
827 js_log('Initializing mediaElement...' );
828 this.sources
= new Array();
829 this.thumbnail
= mv_default_thumb_url
;
830 // Process the source element:
831 if($j(video_element
).attr("src"))
832 this.tryAddSource(video_element
);
834 if($j(video_element
).attr('thumbnail'))
835 this.thumbnail
=$j(video_element
).attr('thumbnail');
837 if($j(video_element
).attr('poster'))
838 this.thumbnail
=$j(video_element
).attr('poster');
840 // Process all inner <source> elements
841 //js_log("inner source count: " + video_element.getElementsByTagName('source').length );
843 $j(video_element
).find('source,text').each(function(inx
, inner_source
){
844 _this
.tryAddSource( inner_source
);
847 /** Updates the time request for all sources that have a standard time request argument (ie &t=start_time/end_time)
849 updateSourceTimes:function(start_ntp
, end_ntp
){
851 $j
.each(this.sources
, function(inx
, mediaSource
){
852 mediaSource
.updateSrcTime(start_ntp
, end_ntp
);
856 timedTextSources:function(){
857 for(var i
=0; i
< this.sources
.length
; i
++){
858 if( this.sources
[i
].mime_type
== 'text/cmml' ||
859 this.sources
[i
].mime_type
== 'text/x-srt')
864 /** Returns the array of mediaSources of this element.
865 \returns {Array} Array of mediaSource elements.
867 getSources:function( mime_filter
)
872 var source_set
= new Array();
873 for(var i
=0; i
< this.sources
.length
; i
++){
874 if( this.sources
[i
].mime_type
.indexOf( mime_filter
) != -1 )
875 source_set
.push( this.sources
[i
] );
879 getSourceById:function( source_id
){
880 for(var i
=0; i
< this.sources
.length
; i
++){
881 if( this.sources
[i
].id
== source_id
)
882 return this.sources
[i
];
886 /** Selects a particular source for playback.
888 selectSource:function(index
)
890 js_log('f:selectSource:'+index
);
891 var playable_sources
= this.getPlayableSources();
892 for(var i
=0; i
< playable_sources
.length
; i
++){
894 this.selected_source
= playable_sources
[i
];
895 //update the user selected format:
896 embedTypes
.players
.userSelectFormat( playable_sources
[i
].mime_type
);
901 /** selects the default source via cookie preference, default marked, or by id order
903 autoSelectSource:function(){
904 js_log('f:autoSelectSource:');
905 //@@todo read user preference for source
906 // Select the default source
907 var playable_sources
= this.getPlayableSources();
908 var flash_flag
=ogg_flag
=false;
910 for(var source
=0; source
< playable_sources
.length
; source
++){
911 var mime_type
=playable_sources
[source
].mime_type
;
912 if( playable_sources
[source
].marked_default
){
913 js_log('set via marked default: ' + playable_sources
[source
].marked_default
);
914 this.selected_source
= playable_sources
[source
];
917 //set via user-preference
918 if(embedTypes
.players
.preference
['format_prefrence'] == mime_type
){
919 js_log('set via preference: '+playable_sources
[source
].mime_type
);
920 this.selected_source
= playable_sources
[source
];
924 //set Ogg via player support
925 for(var source
=0; source
< playable_sources
.length
; source
++){
926 js_log('f:autoSelectSource:' + playable_sources
[source
].mime_type
);
927 var mime_type
=playable_sources
[source
].mime_type
;
928 //set source via player
929 if(mime_type
=='video/ogg' || mime_type
=='ogg/video' || mime_type
=='video/annodex' || mime_type
=='application/ogg'){
930 for(var i
=0; i
< embedTypes
.players
.players
.length
; i
++){ //for in loop on object oky
931 var player
= embedTypes
.players
.players
[i
];
932 if(player
.library
=='vlc' || player
.library
=='native'){
933 js_log('set via ogg via order');
934 this.selected_source
= playable_sources
[source
];
941 for(var source
=0; source
< playable_sources
.length
; source
++){
942 var mime_type
=playable_sources
[source
].mime_type
;
943 if( mime_type
=='video/x-flv' ){
944 js_log('set via by player preference normal flash')
945 this.selected_source
= playable_sources
[source
];
950 for(var source
=0; source
< playable_sources
.length
; source
++){
951 var mime_type
=playable_sources
[source
].mime_type
;
952 if( mime_type
=='video/h264' ){
953 js_log('set via playable_sources preference h264 flash')
954 this.selected_source
= playable_sources
[source
];
958 //select first source
959 if (!this.selected_source
)
961 js_log('set via first source:' + playable_sources
[0]);
962 this.selected_source
= playable_sources
[0];
966 /** Returns the thumbnail URL for the media element.
967 \returns {String} thumbnail URL
969 getThumbnailURL:function()
971 return this.thumbnail
;
973 /** Checks whether there is a stream of a specified MIME type.
974 @param {String} mime_type MIME type to check.
975 @type {BooleanPrimitive}.
977 hasStreamOfMIMEType:function(mime_type
)
979 for(source
in this.sources
)
981 if(this.sources
[source
].getMIMEType() == mime_type
)
986 isPlayableType:function(mime_type
)
988 if( embedTypes
.players
.defaultPlayer( mime_type
) ){
993 //if(this.selected_player){
994 //return mime_type=='video/ogg' || mime_type=='ogg/video' || mime_type=='video/annodex' || mime_type=='video/x-flv';
996 /** Adds a single mediaSource using the provided element if
997 the element has a 'src' attribute.
998 @param element {element} <video>, <source> or <mediaSource> element.
1000 tryAddSource:function(element
)
1002 js_log('f:tryAddSource:'+ $j(element
).attr("src"));
1003 if (! $j(element
).attr("src")){
1004 //js_log("element has no src");
1007 var new_src
= $j(element
).attr('src');
1008 //make sure an existing element with the same src does not already exist:
1009 for( var i
=0; i
< this.sources
.length
; i
++ ){
1010 if(this.sources
[i
].src
== new_src
){
1011 //js_log('checking existing: '+this.sources[i].getURI() + ' != '+ new_src);
1012 //can't add it all but try to update any additional attr:
1013 this.sources
[i
].updateSource(element
);
1017 var source
= new mediaSource( element
);
1018 this.sources
.push(source
);
1019 //alert('pushed source to stack'+ source + 'sl:'+this.sources.length);
1021 getPlayableSources: function(){
1022 var playable_sources
= new Array();
1023 for(var i
=0; i
< this.sources
.length
; i
++){
1024 if( this.isPlayableType( this.sources
[i
].mime_type
) ){
1025 playable_sources
.push( this.sources
[i
] );
1027 js_log("type "+ this.sources
[i
].mime_type
+ 'is not playable');
1030 return playable_sources
;
1032 /* Imports media sources from ROE data.
1033 * @param roe_data ROE data.
1035 addROE:function(roe_data
){
1037 this.addedROEData
=true;
1039 if( typeof roe_data
== 'string' )
1041 var parser
=new DOMParser();
1042 js_log('ROE data:' + roe_data
);
1043 roe_data
=parser
.parseFromString(roe_data
,"text/xml");
1046 $j
.each(roe_data
.getElementsByTagName('mediaSource'), function(inx
, source
){
1047 _this
.tryAddSource(source
);
1049 //set the thumbnail:
1050 $j
.each(roe_data
.getElementsByTagName('img'), function(inx
, n
){
1051 if($j(n
).attr("id")=="stream_thumb"){
1052 js_log('roe:set thumb to '+$j(n
).attr("src"));
1053 _this
['thumbnail'] =$j(n
).attr("src");
1057 $j
.each(roe_data
.getElementsByTagName('link'), function(inx
, n
){
1058 if($j(n
).attr('id')=='html_linkback'){
1059 js_log('roe:set linkback to '+$j(n
).attr("href"));
1060 _this
['linkback'] = $j(n
).attr('href');
1064 js_log('ROE data empty.');
1070 /** base embedVideo object
1071 @param element <video> tag used for initialization.
1074 var embedVideo = function(element
) {
1075 return this.init(element
);
1078 embedVideo
.prototype = {
1079 /** The mediaElement object containing all mediaSource objects */
1082 ready_to_play
:false, //should use html5 ready state
1083 load_error
:false, //used to set error in case of error
1084 loading_external_data
:false,
1085 thumbnail_updating
:false,
1086 thumbnail_disp
:true,
1087 init_with_sources_loadedDone
:false,
1089 //for onClip done stuff:
1090 anno_data_cache
:null,
1092 base_seeker_slider_offset
:null,
1093 onClipDone_disp
:false,
1095 //for seek thumb updates:
1096 cur_thumb_seek_time
:0,
1097 thumb_seek_interval
:null,
1100 //set the buffered percent:
1102 //utility functions for property values:
1103 hx : function ( s
) {
1104 if ( typeof s
!= 'String' ) {
1107 return s
.replace( /&/g
, '&' )
1108 . replace( /</g
, '<' )
1109 . replace( />/g
, '>' );
1111 hq : function ( s
) {
1112 return '"' + this.hx( s
) + '"';
1114 playerPixelWidth : function()
1116 var player
= $j('#mv_embedded_player_'+this.id
).get(0);
1117 if(typeof player
!='undefined' && player
['offsetWidth'])
1118 return player
.offsetWidth
;
1120 return parseInt(this.width
);
1122 playerPixelHeight : function()
1124 var player
= $j('#mv_embedded_player_'+this.id
).get(0);
1125 if(typeof player
!='undefined' && player
['offsetHeight'])
1126 return player
.offsetHeight
;
1128 return parseInt(this.height
);
1130 init: function(element
){
1131 //this.element_pointer = element;
1133 //inherit all the default video_attributes
1134 for(var attr
in default_video_attributes
){ //for in loop oky on user object
1135 if(element
.getAttribute(attr
)){
1136 this[attr
]=element
.getAttribute(attr
);
1137 //js_log('attr:' + attr + ' val: ' + element.getAttribute(attr) +'(set by elm)');
1139 this[attr
]=default_video_attributes
[attr
];
1140 //js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)");
1143 //make sure startOffset is cast as an int
1144 if( this.startOffset
&& this.startOffset
.split(':').length
>= 2)
1145 this.startOffset
= npt2seconds(this.startOffset
);
1146 //make sure offset is in float:
1147 this.startOffset
= parseFloat(this.startOffset
);
1149 if( this.duration
&& this.duration
.split(':').length
>= 2)
1150 this.duration
= npt2seconds( this.duration
);
1151 //make sure duration is in float:
1152 this.duration
= parseFloat(this.duration
);
1153 js_log("duration is: " + this.duration
);
1154 //if style is set override width and height
1155 var dwh
= mv_default_video_size
.split('x');
1156 this.width
= element
.style
.width
? element
.style
.width
: dwh
[0];
1157 this.height
= element
.style
.height
? element
.style
.height
: dwh
[1];
1159 this.pid
= 'pid_' + this.id
;
1161 //grab any innerHTML and set it to missing_plugin_html
1162 //@@todo we should strip source tags instead of checking and skipping
1163 if(element
.innerHTML
!='' && element
.getElementsByTagName('source').length
==0){
1164 js_log('innerHTML: ' + element
.innerHTML
);
1165 this.user_missing_plugin_html
=element
.innerHTML
;
1167 // load all of the specified sources
1168 this.media_element
= new mediaElement(element
);
1170 on_dom_swap: function(){
1171 js_log('f:on_dom_swap');
1172 // Process the provided ROE file... if we don't yet have sources
1173 if(this.roe
&& this.media_element
.sources
.length
==0 ){
1174 js_log('loading external data');
1175 this.loading_external_data
=true;
1177 do_request(this.roe
, function(data
)
1180 _this
.media_element
.addROE( data
);
1181 js_log('added_roe::' + _this
.media_element
.sources
.length
);
1183 js_log('set loading_external_data=false');
1184 _this
.loading_external_data
=false;
1186 _this
.init_with_sources_loaded();
1190 init_with_sources_loaded : function()
1192 js_log('f:init_with_sources_loaded');
1193 //set flag that we have run this function:
1194 this.init_with_sources_loadedDone
=true;
1195 //autoseletct the source
1196 this.media_element
.autoSelectSource();
1197 //auto select player based on prefrence or default order
1198 if( !this.media_element
.selected_source
)
1200 //check for parent clip:
1201 if( typeof this.pc
!= 'undefined' ){
1202 js_log('no sources, type:' +this.type
+ ' check for html');
1204 //do load player if just displaying innerHTML:
1205 if( this.pc
.type
== 'text/html' ){
1206 this.selected_player
= embedTypes
.players
.defaultPlayer( 'text/html' );
1207 js_log('set selected player:'+ this.selected_player
.mime_type
);
1211 this.selected_player
= embedTypes
.players
.defaultPlayer( this.media_element
.selected_source
.mime_type
);
1213 if( this.selected_player
){
1214 js_log('selected ' + this.selected_player
.getName());
1215 js_log("PLAYBACK TYPE: "+this.selected_player
.library
);
1216 this.thumbnail_disp
= true;
1217 this.inheritEmbedObj();
1219 //no source's playable
1220 var missing_type
='';
1222 for( var i
=0; i
< this.media_element
.sources
.length
; i
++){
1223 missing_type
+=or
+ this.media_element
.sources
[i
].mime_type
;
1227 var missing_type
= this.pc
.type
;
1228 js_log('no player found for given source type ' + missing_type
);
1229 this.load_error
= this.getPluginMissingHTML(missing_type
);
1232 inheritEmbedObj:function(){
1233 js_log("inheritEmbedObj:duration is: " + this.duration
);
1234 //@@note: tricky cuz direct overwrite is not so ideal.. since the extended object is already tied to the dom
1235 //clear out any non-base embedObj stuff:
1236 if(this.instanceOf
){
1237 eval('tmpObj = '+this.instanceOf
);
1238 for(var i
in tmpObj
){ //for in loop oky for object
1239 if(this['parent_'+i
]){
1240 this[i
]=this['parent_'+i
];
1246 //set up the new embedObj
1247 js_log('f: inheritEmbedObj: embedding with ' + this.selected_player
.library
);
1249 this.selected_player
.load( function()
1251 js_log("selected_player::load:duration is: " + _this
.duration
);
1252 //js_log('inheriting '+_this.selected_player.library +'Embed to ' + _this.id + ' ' + $j('#'+_this.id).length);
1253 //var _this = $j('#'+_this.id).get(0);
1254 //js_log( 'type of ' + _this.selected_player.library +'Embed + ' +
1255 // eval('typeof '+_this.selected_player.library +'Embed'));
1256 eval('embedObj = ' +_this
.selected_player
.library
+'Embed;');
1257 for(var method
in embedObj
){ //for in loop oky for object
1258 //parent method preservation for local overwritten methods
1260 _this
['parent_' + method
] = _this
[method
];
1261 _this
[method
]=embedObj
[method
];
1263 js_log('TYPEOF_ppause: ' + typeof _this
['parent_pause']);
1265 if(_this
.inheritEmbedOverride
){
1266 _this
.inheritEmbedOverride();
1268 //update controls if possible
1269 if(!_this
.loading_external_data
)
1270 _this
.refreshControlsHTML();
1272 //js_log("READY TO PLAY:"+_this.id);
1273 _this
.ready_to_play
=true;
1274 _this
.getDuration();
1278 selectPlayer:function(player
)
1281 if(this.selected_player
.id
!= player
.id
){
1282 this.selected_player
= player
;
1283 this.inheritEmbedObj();
1286 doNativeWarningCheck:function(){
1287 if( $j
.cookie('dismissNativeWarn') && $j
.cookie('dismissNativeWarn')===true){
1290 //see if we have native support for ogg:
1291 var supporting_players
= embedTypes
.players
.getMIMETypePlayers( 'video/ogg' );
1292 for(var i
=0; i
< supporting_players
.length
; i
++){
1293 if(supporting_players
[i
].id
== 'videoElement'){
1297 //see if we are using mv_embed without a ogg source in which case no point in promoting firefox :P
1298 if(this.media_element
&& this.media_element
.sources
){
1299 var foundOgg
= false;
1300 var playable_sources
= this.media_element
.getPlayableSources();
1301 for(var sInx
=0; sInx
< playable_sources
.length
; sInx
++){
1302 var mime_type
= playable_sources
[sInx
].mime_type
;
1303 if( mime_type
=='video/ogg' ){
1304 //they have flash / h.264 fallback no need to push firefox :(
1308 //no ogg no point in download firefox
1316 getTimeReq:function(){
1317 //js_log('f:getTimeReq:'+ this.getDurationNTP());
1318 var default_time_req
= '0:00:00/' + this.getDurationNTP() ;
1319 if(!this.media_element
)
1320 return default_time_req
;
1321 if(!this.media_element
.selected_source
)
1322 return default_time_req
;
1323 if(!this.media_element
.selected_source
.end_ntp
)
1324 return default_time_req
;
1325 return this.media_element
.selected_source
.start_ntp
+'/'+this.media_element
.selected_source
.end_ntp
;
1327 getDuration:function(){
1328 //update some local pointers for the selected source:
1329 if(this.media_element
&& this.media_element
.selected_source
&& this.media_element
.selected_source
.duration
){
1330 this.duration
= this.media_element
.selected_source
.duration
;
1331 this.start_offset
= this.media_element
.selected_source
.start_offset
;
1332 this.start_ntp
= this.media_element
.selected_source
.start_ntp
;
1333 this.end_ntp
= this.media_element
.selected_source
.end_ntp
;
1335 //update start end_ntp if duration !=0 (set from plugin)
1337 this.start_ntp
= '0:0:0';
1338 if(!this.end_ntp
&& this.duration
)
1339 this.end_ntp
= seconds2npt( this.duration
);
1340 //return the duration
1341 return this.duration
;
1343 /* get the duration in ntp format */
1344 getDurationNTP:function(){
1345 return seconds2npt(this.getDuration());
1348 * wrapEmebedContainer
1349 * wraps the embed code into a container to better support playlist function
1350 * (where embed element is swapped for next clip
1351 * (where plugin method does not support playlsits)
1353 wrapEmebedContainer:function(embed_code
){
1354 //check if parent clip is set( ie we are in a playlist so name the embed container by playlistID)
1355 var id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
1356 return '<div id="mv_ebct_'+id
+'" style="width:'+this.width
+'px;height:'+this.height
+'px;">' +
1360 getEmbedHTML : function(){
1361 //return this.wrapEmebedContainer( this.getEmbedObj() );
1362 return 'function getEmbedHTML should be overitten by embedLib ';
1364 //do seek function (should be overwritten by implementing embedLibs)
1365 // first check if seek can be done on locally downloaded content.
1366 doSeek : function( perc
){
1367 if( this.supportsURLTimeEncoding() ){
1368 //make sure this.seek_time_sec is up-to-date:
1369 this.seek_time_sec
= npt2seconds( this.start_ntp
) + parseFloat( perc
* this.getDuration() );
1370 js_log('updated seek_time_sec: ' + seconds2npt ( this.seek_time_sec
) );
1372 this.didSeekJump
=true;
1374 this.setSliderValue( perc
);
1376 //do play in 100ms (give things time to clear)
1377 setTimeout('$j(\'#' + this.id
+ '\').get(0).play()',100);
1380 * seeks to the requested time and issues a callback when ready
1381 * (should be overwitten by client that supports frame serving)
1383 setCurrentTime:function( time
, callback
){
1384 js_log('error: base embed setCurrentTime can not frame serve (overide via plugin)');
1386 addPresTimeOffset:function(){
1387 //add in the offset:
1388 if(this.seek_time_sec
&& this.seek_time_sec
!=0){
1389 this.currentTime
+=this.seek_time_sec
;
1390 }else if(this.start_offset
&& this.start_offset
!=0){
1391 this.currentTime
= parseFloat(this.currentTime
) + parseFloat(this.start_offset
);
1394 doEmbedHTML:function()
1396 js_log('f:doEmbedHTML');
1397 js_log('thum disp:'+this.thumbnail_disp
);
1399 this.closeDisplayedHTML();
1401 // if(!this.selected_player){
1402 // return this.getPluginMissingHTML();
1403 //Set "loading" here
1404 $j('#mv_embedded_player_'+_this
.id
).html(''+
1405 '<div style="color:black;width:'+this.width
+'px;height:'+this.height
+'px;">' +
1406 gM('loading_plugin') +
1409 // schedule embedding
1410 this.selected_player
.load(function()
1412 js_log('performing embed for ' + _this
.id
);
1413 var embed_code
= _this
.getEmbedHTML();
1414 //js_log('shopuld embed:' + embed_code);
1415 $j('#mv_embedded_player_'+_this
.id
).html(embed_code
);
1418 onClipDone:function(){
1419 js_log('base:onClipDone');
1420 //stop the clip (load the thumbnail etc)
1422 this.seek_time_sec
= 0;
1423 this.setSliderValue(0);
1426 //if the clip resolution is < 320 don't do fancy onClipDone stuff
1427 if(this.width
< 300){
1430 this.onClipDone_disp
=true;
1431 this.thumbnail_disp
=true;
1432 //make sure we are not in preview mode( no end clip actions in preview mode)
1433 if( this.preview_mode
)
1436 $j('#img_thumb_'+this.id
).css('zindex',1);
1437 $j('#big_play_link_'+this.id
).hide();
1438 //add the liks_info_div black back
1439 $j('#dc_'+this.id
).append('<div id="liks_info_'+this.id
+'" ' +
1440 'style="width:' +parseInt(parseInt(this.width
)/2)+'px;'+
1441 'height:'+ parseInt(parseInt(this.height
)) +'px;'+
1442 'position:absolute;top:10px;overflow:auto'+
1443 'width: '+parseInt( ((parseInt(this.width
)/2)-15) ) + 'px;'+
1444 'left:'+ parseInt( ((parseInt(this.width
)/2)+15) ) +'px;">'+
1446 '<div id="black_back_'+this.id
+'" ' +
1447 'style="z-index:-2;position:absolute;background:#000;' +
1448 'top:0px;left:0px;width:'+parseInt(this.width
)+'px;' +
1449 'height:'+parseInt(this.height
)+'px;">' +
1453 //start animation (make thumb small in upper left add in div for "loading"
1454 $j('#img_thumb_'+this.id
).animate({
1455 width
:parseInt(parseInt(_this
.width
)/2),
1456 height
:parseInt(parseInt(_this
.height
)/2),
1462 //animation done.. add "loading" to div if empty
1463 if($j('#liks_info_'+_this
.id
).html()==''){
1464 $j('#liks_info_'+_this
.id
).html(gM('loading_txt'));
1468 //now load roe if run the showNextPrevLinks
1469 if(this.roe
&& this.media_element
.addedROEData
==false){
1470 do_request(this.roe
, function(data
)
1472 _this
.media_element
.addROE(data
);
1473 _this
.getNextPrevLinks();
1476 this.getNextPrevLinks();
1479 //@@todo we should merge getNextPrevLinks with textInterface .. there is repeated code between them.
1480 getNextPrevLinks:function(){
1481 js_log('f:getNextPrevLinks');
1482 var anno_track_url
= null;
1484 //check for annoative track
1485 $j
.each(this.media_element
.sources
, function(inx
, n
){
1486 if(n
.mime_type
=='text/cmml'){
1487 if( n
.id
== 'Anno_en'){
1488 anno_track_url
= n
.src
;
1492 if( anno_track_url
){
1493 js_log('found annotative track:'+ anno_track_url
);
1494 //zero out seconds (should improve cache hit rate and generally expands metadata search)
1495 //@@todo this could be repalced with a regExp
1496 var annoURL
= parseUri(anno_track_url
);
1497 var times
= annoURL
.queryKey
['t'].split('/');
1498 var stime_parts
= times
[0].split(':');
1499 var etime_parts
= times
[1].split(':');
1500 //zero out the hour:
1501 var new_start
= stime_parts
[0]+':'+'0:0';
1502 //zero out the end sec
1503 var new_end
= (etime_parts
[0]== stime_parts
[0])? (etime_parts
[0]+1)+':0:0' :etime_parts
[0]+':0:0';
1505 var etime_parts
= times
[1].split(':');
1507 var new_anno_track_url
= annoURL
.protocol
+'://'+ annoURL
.host
+ annoURL
.path
+'?';
1508 $j
.each(annoURL
.queryKey
, function(i
, val
){
1509 new_anno_track_url
+=(i
=='t')?'t='+new_start
+'/'+new_end
+'&' :
1512 var request_key
= new_start
+'/'+new_end
;
1513 //check the anno_data cache:
1514 //@@todo search cache see if current is in range.
1515 if(this.anno_data_cache
){
1516 js_log('anno data found in cache: '+request_key
);
1517 this.showNextPrevLinks();
1519 do_request(new_anno_track_url
, function(cmml_data
){
1520 js_log('raw response: '+ cmml_data
);
1521 if(typeof cmml_data
== 'string')
1523 var parser
=new DOMParser();
1524 js_log('Parse CMML data:' + cmml_data
);
1525 cmml_data
=parser
.parseFromString(cmml_data
,"text/xml");
1527 //init anno_data_cache
1528 if(!_this
.anno_data_cache
)
1529 _this
.anno_data_cache
={};
1530 //grab all metadata and put it into the anno_data_cache:
1531 $j
.each(cmml_data
.getElementsByTagName('clip'), function(inx
, clip
){
1532 _this
.anno_data_cache
[ $j(clip
).attr("id") ]={
1533 'start_time_sec':npt2seconds($j(clip
).attr("start").replace('npt:','')),
1534 'end_time_sec':npt2seconds($j(clip
).attr("end").replace('npt:','')),
1535 'time_req':$j(clip
).attr("start").replace('npt:','')+'/'+$j(clip
).attr("end").replace('npt:','')
1538 _this
.anno_data_cache
[ $j(clip
).attr("id") ]['meta']={};
1539 $j
.each(clip
.getElementsByTagName('meta'),function(imx
, meta
){
1540 //js_log('adding meta: '+ $j(meta).attr("name")+ ' = '+ $j(meta).attr("content"));
1541 _this
.anno_data_cache
[$j(clip
).attr("id")]['meta'][$j(meta
).attr("name")]=$j(meta
).attr("content");
1544 _this
.showNextPrevLinks();
1548 js_log('no annotative track found');
1549 $j('#liks_info_'+this.id
).html('no metadata found for related links');
1551 //query current request time +|- 60s to get prev next speech links.
1553 showNextPrevLinks:function(){
1554 //js_log('f:showNextPrevLinks');
1555 //int requested links:
1561 var curTime
= this.getTimeReq().split('/');
1563 var s_sec
= npt2seconds(curTime
[0]);
1564 var e_sec
= npt2seconds(curTime
[1]);
1565 js_log('showNextPrevLinks: req time: '+ s_sec
+ ' to ' + e_sec
);
1566 //now we have all the data in anno_data_cache
1567 var current_done
=false;
1568 for(var clip_id
in this.anno_data_cache
){ //for in loop oky for object
1569 var clip
= this.anno_data_cache
[clip_id
];
1570 //js_log('on clip:'+ clip_id);
1571 //set prev_link (if cur_link is still empty)
1572 if( s_sec
> clip
.end_time_sec
){
1573 link
.prev
= clip_id
;
1574 js_log('showNextPrevLinks: ' + s_sec
+ ' < ' + clip
.end_time_sec
+ ' set prev');
1577 if(e_sec
==clip
.end_time_sec
&& s_sec
== clip
.start_time_sec
)
1578 current_done
= true;
1579 //current clip is not done:
1580 if( e_sec
< clip
.end_time_sec
&& link
.current
=='' && !current_done
){
1581 link
.current
= clip_id
;
1582 js_log('showNextPrevLinks: ' + e_sec
+ ' < ' + clip
.end_time_sec
+ ' set current');
1585 //set end clip (first clip where start time is > end_time of req
1586 if( e_sec
< clip
.start_time_sec
&& link
.next
==''){
1587 link
.next
= clip_id
;
1588 js_log('showNextPrevLinks: '+ e_sec
+ ' < '+ clip
.start_time_sec
+ ' && ' + link
.next
);
1592 if(link
.prev
=='' && link
.current
=='' && link
.next
==''){
1593 html
='<p><a href="'+this.media_element
.linkbackgetMsg
+'">clip page</a>';
1595 for(var link_type
in link
){
1596 var link_id
= link
[link_type
];
1598 var clip
= this.anno_data_cache
[link_id
];
1600 for(var j
in clip
['meta']){
1601 title_msg
+=j
.replace(/_/g,' ') +': ' +clip['meta'][j].replace(/_
/g
,' ') +" <br>";
1603 var time_req
= clip
.time_req
;
1604 if(link_type
=='current') //if current start from end of current clip play to end of current meta:
1605 time_req
= curTime
[1]+ '/' + seconds2npt( clip
.end_time_sec
);
1607 //do special linkbacks for metavid content:
1608 var regTimeCheck
= new RegExp(/[0-9]+:[0-9]+:[0-9]+\/[0-9]+:[0-9]+:[0-9]+/);
1610 if( regTimeCheck
.test( this.media_element
.linkback
) ){
1611 html
+=' href="'+ this.media_element
.linkback
.replace(regTimeCheck
,time_req
) +'" ';
1613 html
+=' href="#" onClick="$j(\'#'+this.id
+'\').get(0).playByTimeReq(\''+
1614 time_req
+ '\'); return false; "';
1616 html
+=' title="' + title_msg
+ '">' +
1617 gM(link_type
+'_clip_msg') +
1618 '</a><br><span style="font-size:small">'+ title_msg
+'<span></p>';
1622 //js_og("should set html:"+ html);
1623 $j('#liks_info_'+this.id
).html(html
);
1625 playByTimeReq: function(time_req
){
1626 js_log('f:playByTimeReq: '+time_req
);
1628 this.updateVideoTimeReq(time_req
);
1631 doThumbnailHTML:function()
1634 js_log('f:doThumbnailHTML'+ this.thumbnail_disp
);
1635 this.closeDisplayedHTML();
1636 $j( '#mv_embedded_player_' + this.id
).html( this.getThumbnailHTML() );
1638 this.thumbnail_disp
= true;
1640 refreshControlsHTML:function(){
1641 js_log('refreshing controls HTML');
1642 if($j('#mv_embedded_controls_'+this.id
).length
==0)
1644 js_log('#mv_embedded_controls_'+this.id
+ ' not present, returning');
1647 $j('#mv_embedded_controls_'+this.id
).html( this.getControlsHTML() );
1648 ctrlBuilder
.addControlHooks(this);
1651 getControlsHTML:function()
1653 return ctrlBuilder
.getControls( this );
1655 getHTML : function (){
1656 //@@todo check if we have sources avaliable
1657 js_log('f:getHTML : ' + this.id
);
1660 html_code
= '<div id="videoPlayer_'+this.id
+'" style="width:'+this.width
+'px;" class="videoPlayer">';
1661 html_code
+= '<div style="width:'+parseInt(this.width
)+'px;height:'+parseInt(this.height
)+'px;" id="mv_embedded_player_'+this.id
+'">' +
1662 this.getThumbnailHTML() +
1664 //js_log("mvEmbed:controls "+ typeof this.controls);
1667 js_log("f:getHTML:AddControls");
1668 html_code
+='<div id="mv_embedded_controls_' + this.id
+ '" class="ui-widget ui-corner-bottom ui-state-default controls" >';
1669 html_code
+= this.getControlsHTML();
1670 html_code
+='</div>';
1671 //block out some space by encapulating the top level div
1672 $j(this).wrap('<div style="width:'+parseInt(this.width
)+'px;height:'
1673 +(parseInt(this.height
)+ctrlBuilder
.height
)+'px"></div>');
1675 html_code
+= '</div>'; //videoPlayer div close
1676 //js_log('should set: '+this.id);
1677 $j(this).html( html_code
);
1678 //add hooks once Controls are in DOM
1679 ctrlBuilder
.addControlHooks(this);
1681 //js_log('set this to: ' + $j(this).html() );
1683 //if auto play==true directly embed the plugin
1686 js_log('activating autoplay');
1691 * get missing plugin html (check for user included code)
1693 getPluginMissingHTML : function(missing_type
){
1694 //keep the box width hight:
1695 var out
= '<div style="width:'+this.width
+'px;height:'+this.height
+'px">';
1696 if(this.user_missing_plugin_html
){
1697 out
+= this.user_missing_plugin_html
;
1701 out
+= gM('mv_generic_missing_plugin', missing_type
) + ' or <a title="'+gM('download_clip')+'" href="'+this.src
+'">'+gM('download_clip')+'</a>';
1703 return out
+ '</div>';
1705 updateVideoTimeReq:function(time_req
){
1706 js_log('f:updateVideoTimeReq');
1707 var time_parts
=time_req
.split('/');
1708 this.updateVideoTime(time_parts
[0], time_parts
[1]);
1711 updateVideoTime:function(start_ntp
, end_ntp
){
1713 this.media_element
.updateSourceTimes( start_ntp
, end_ntp
);
1715 this.setStatus(start_ntp
+'/'+end_ntp
);
1717 this.setSliderValue(0);
1718 //reset seek_offset:
1719 if(this.media_element
.selected_source
.URLTimeEncoding
)
1720 this.seek_time_sec
=0;
1722 this.seek_time_sec
=npt2seconds(start_ntp
);
1724 //@@todo overwite by embed library if we can render frames natavily
1725 renderTimelineThumbnail:function( options
){
1726 var my_thumb_src
= this.media_element
.getThumbnailURL();
1727 //check if our thumbnail has a time attribute:
1728 if( my_thumb_src
.indexOf('t=') !== -1){
1729 var time_ntp
= seconds2npt ( options
.time
+ parseInt(this.start_offset
) );
1730 my_thumb_src
= getURLParamReplace( my_thumb_src
, { 't':time_ntp
, 'size': options
.size
} );
1732 var thumb_class
= (typeof options
['thumb_class'] != 'undefined' ) ? options
['thumb_class'] : '';
1733 return '<div class="ui-corner-all ' + thumb_class
+ '" src="' + my_thumb_src
+ '" '+
1734 'style="height:' + options
.height
+ 'px;' +
1735 'width:' + options
.width
+ 'px" >' +
1736 '<img src="' + my_thumb_src
+'" '+
1737 'style="height:' + options
.height
+ 'px;' +
1738 'width:' + options
.width
+ 'px">' +
1741 updateThumbTimeNTP:function( time
){
1742 this.updateThumbTime( npt2seconds(time
) - parseInt(this.start_offset
) );
1744 updateThumbTime:function( float_sec
){
1745 //js_log('updateThumbTime:'+float_sec);
1747 if( typeof this.org_thum_src
=='undefined' ){
1748 this.org_thum_src
= this.media_element
.getThumbnailURL();
1750 if( this.org_thum_src
.indexOf('t=') !== -1){
1751 this.last_thumb_url
= getURLParamReplace(this.org_thum_src
,
1752 { 't' : seconds2npt( float_sec
+ parseInt(this.start_offset
)) } );
1753 if(!this.thumbnail_updating
){
1754 this.updateThumbnail(this.last_thumb_url
,false);
1755 this.last_thumb_url
=null;
1759 //for now provide a src url .. but need to figure out how to copy frames from video for plug-in based thumbs
1760 updateThumbPerc:function( perc
){
1761 return this.updateThumbTime( (this.getDuration() * perc
) );
1763 //updates the thumbnail if the thumbnail is being displayed
1764 updateThumbnail : function(src
, quick_switch
){
1765 //make sure we don't go to the same url if we are not already updating:
1766 if( !this.thumbnail_updating
&& $j('#img_thumb_'+this.id
).attr('src')== src
)
1768 //if we are already updating don't issue a new update:
1769 if( this.thumbnail_updating
&& $j('#new_img_thumb_'+this.id
).attr('src')== src
)
1772 js_log('update thumb: ' + src
);
1775 $j('#img_thumb_'+this.id
).attr('src', src
);
1778 //if still animating remove new_img_thumb_
1779 if(this.thumbnail_updating
==true)
1780 $j('#new_img_thumb_'+this.id
).stop().remove();
1782 if(this.thumbnail_disp
){
1783 js_log('set to thumb:'+ src
);
1784 this.thumbnail_updating
=true;
1785 $j('#dc_'+this.id
).append('<img src="'+src
+'" ' +
1786 'style="display:none;position:absolute;zindex:2;top:0px;left:0px;" ' +
1787 'width="'+this.width
+'" height="'+this.height
+'" '+
1788 'id = "new_img_thumb_'+this.id
+'" />');
1789 //js_log('appended: new_img_thumb_');
1790 $j('#new_img_thumb_'+this.id
).fadeIn("slow", function(){
1791 //once faded in remove org and rename new:
1792 $j('#img_thumb_'+_this
.id
).remove();
1793 $j('#new_img_thumb_'+_this
.id
).attr('id', 'img_thumb_'+_this
.id
);
1794 $j('#img_thumb_'+_this
.id
).css('zindex','1');
1795 _this
.thumbnail_updating
=false;
1796 //js_log("done fadding in "+ $j('#img_thumb_'+_this.id).attr("src"));
1798 //if we have a thumb queued update to that
1799 if(_this
.last_thumb_url
){
1800 var src_url
=_this
.last_thumb_url
;
1801 _this
.last_thumb_url
=null;
1802 _this
.updateThumbnail(src_url
);
1808 /** Returns the HTML code for the video when it is in thumbnail mode.
1809 This includes the specified thumbnail as well as buttons for
1810 playing, configuring the player, inline cmml display, HTML linkback,
1811 download, and embed code.
1813 getThumbnailHTML : function ()
1815 var thumb_html
= '';
1818 //if(this.class)class_atr = ' class="'+this.class+'"';
1819 //if(this.style)style_atr = ' style="'+this.style+'"';
1820 // else style_atr = 'overflow:hidden;height:'+this.height+'px;width:'+this.width+'px;';
1821 this.thumbnail
= this.media_element
.getThumbnailURL();
1823 //put it all in the div container dc_id
1824 thumb_html
+= '<div id="dc_'+this.id
+'" style="position:relative;'+
1825 ' overflow:hidden; top:0px; left:0px; width:'+this.playerPixelWidth()+'px; height:'+this.playerPixelHeight()+'px; z-index:0;">'+
1826 '<img width="'+this.playerPixelWidth()+'" height="'+this.playerPixelHeight()+'" style="position:relative;width:'+this.playerPixelWidth()+';height:'+this.playerPixelHeight()+'"' +
1827 ' id="img_thumb_'+this.id
+'" src="' + this.thumbnail
+ '">';
1829 if(this.play_button
== true && this.controls
== true)
1830 thumb_html
+=this.getPlayButton();
1832 thumb_html
+='</div>';
1835 getEmbeddingHTML:function()
1837 var thumbnail
= this.media_element
.getThumbnailURL();
1839 var embed_thumb_html
;
1840 if(thumbnail
.substring(0,1)=='/'){
1841 eURL
= parseUri(mv_embed_path
);
1842 embed_thumb_html
= eURL
.protocol
+ '://' + eURL
.host
+ thumbnail
;
1843 //js_log('set from mv_embed_path:'+embed_thumb_html);
1845 embed_thumb_html
= (thumbnail
.indexOf('http://')!=-1)?thumbnail
:mv_embed_path
+ thumbnail
;
1847 var embed_code_html
= '<script type="text/javascript" ' +
1848 'src="'+mv_embed_path
+'mv_embed.js"></script>' +
1851 embed_code_html
+='roe="'+this.roe
+'" >';
1853 embed_code_html
+='src="'+this.src
+'" ' +
1854 'thumbnail="'+embed_thumb_html
+'">';
1856 //close the video tag
1857 embed_code_html
+='</video>';
1859 return embed_code_html
;
1861 doOptionsHTML:function()
1863 var sel_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
1864 var pos
= $j('#options_button_'+sel_id
).offset();
1865 pos
['top']=pos
['top']+24;
1866 pos
['left']=pos
['left']-124;
1867 //js_log('pos of options button: t:'+pos['top']+' l:'+ pos['left']);
1868 $j('#mv_vid_options_'+sel_id
).css(pos
).toggle();
1871 getPlayButton:function(id
){
1873 return '<div title="' + gM('play_clip') + '" id="big_play_link_'+id
+'" class="large_play_button" '+
1874 'style="left:'+((this.playerPixelWidth()-130)/2)+'px;'+
1875 'top:' + ((this.playerPixelHeight()-96)/2) + 'px;">'+
1876 '<img src="' + mv_skin_img_path
+ 'player_big_play_button.png">'+
1879 doLinkBack:function(){
1880 if(this.roe
&& this.media_element
.addedROEData
==false){
1882 this.displayHTML(gM('loading_txt'));
1883 do_request(this.roe
, function(data
)
1885 _this
.media_element
.addROE(data
);
1889 if(this.media_element
.linkback
){
1890 window
.location
= this.media_element
.linkback
;
1892 this.displayHTML(gM('could_not_find_linkback'));
1896 //display the code to remotely embed this video:
1897 showEmbedCode : function(embed_code
){
1899 embed_code
= this.getEmbeddingHTML();
1902 o
+='<a class="email" href="'+this.linkback
+'">Share Clip via Link</a> '+
1906 '<span style="color:#FFF;font-size:14px;">Embed Clip in Blog or Site</span><br>'+
1907 '<span style="color:#FFF;font-size:12px;"><a style="color:red" href="http://metavid.org/wiki/Security_Notes_on_Remote_Embedding">'+
1908 'Read This</a> before embeding.</span>'+
1909 '<div class="embed_code"> '+
1910 '<textarea onClick="this.select();" id="embedding_user_html_'+this.id
+'" name="embed">' +
1913 '<button onClick="$j(\'#'+this.id
+'\').get(0).copyText(); return false;" class="copy_to_clipboard">Copy to Clipboard</button> '+
1916 this.displayHTML(o
);
1918 copyText:function(){
1919 $j('#embedding_user_html_'+this.id
).focus().select();
1920 if(document
.selection
){
1921 CopiedTxt
= document
.selection
.createRange();
1922 CopiedTxt
.execCommand("Copy");
1925 showTextInterface:function(){
1927 //display the text container with loading text:
1928 //@@todo support position config
1929 var loc
= $j(this).position();
1930 if($j('#metaBox_'+this.id
).length
==0){
1931 $j(this).after('<div class="ui-widget ui-widget-content ui-corner-all" style="position:absolute;z-index:10;'+
1932 'top:' + (loc
.top
) + 'px;' +
1933 'left:' + (parseInt( loc
.left
) + parseInt(this.width
) + 10 )+'px;' +
1934 'height:'+ parseInt( this.height
)+'px;width:400px;' +
1936 'id="metaBox_' + this.id
+ '">'+
1940 //fade in the text display
1941 $j('#metaBox_'+this.id
).fadeIn("fast");
1942 //check if textObj present:
1943 if(typeof this.textInterface
== 'undefined' ){
1944 //load the default text interface:
1949 _this
.textInterface
= new mvTextInterface( _this
);
1951 _this
.textInterface
.show();
1952 js_log("NEW TEXT INTERFACE");
1953 for(var i
in _this
.textInterface
.availableTracks
){
1954 js_log("tracks in new interface: "+_this
.id
+ ' tid:' + i
);
1960 this.textInterface
.show();
1963 closeTextInterface:function(){
1964 js_log('closeTextInterface '+ typeof this.textInterface
);
1965 if(typeof this.textInterface
!== 'undefined' ){
1966 this.textInterface
.close();
1969 /** Generic function to display custom HTML inside the mv_embed element.
1970 The code should call the closeDisplayedHTML function to close the
1971 display of the custom HTML and restore the regular mv_embed display.
1972 @param {String} HTML code for the selection list.
1974 displayHTML:function(html_code
)
1976 var sel_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
1978 if(!this.supports
['overlays'])
1981 //put select list on-top
1982 //make sure the parent is relatively positioned:
1983 $j('#'+sel_id
).css('position', 'relative');
1984 //set height width (check for playlist container)
1985 var width
= (this.pc
)?this.pc
.pp
.width
:this.playerPixelWidth();
1986 var height
= (this.pc
)?this.pc
.pp
.height
:this.playerPixelHeight();
1989 height
+=(this.pc
.pp
.pl_layout
.title_bar_height
+ this.pc
.pp
.pl_layout
.control_height
);
1992 if($j('#blackbg_'+sel_id
).length
!=0)
1995 $j('#blackbg_'+sel_id
).remove();
1997 //fade in a black bg div ontop of everything
1998 var div_code
= '<div id="blackbg_'+sel_id
+'" class="videoComplete" ' +
1999 'style="height:'+parseInt(height
)+'px;width:'+parseInt(width
)+'px;">'+
2000 '<div class="videoOptionsComplete">'+
2001 //@@TODO: this style should go to .css
2002 '<span style="float:right;margin-right:10px">' +
2003 '<a href="#" style="color:white;" onClick="$j(\'#'+sel_id
+'\').get(0).closeDisplayedHTML();return false;">close</a>' +
2005 '<div id="mv_disp_inner_'+sel_id
+'" style="padding-top:10px;">'+
2009 $j('#'+sel_id
).prepend(div_code
);
2011 $j('#blackbg_'+sel_id
).fadeIn("slow");
2013 $j('#blackbg_'+sel_id
).show();
2014 return false; //onclick action return false
2016 /** Close the custom HTML displayed using displayHTML and restores the
2017 regular mv_embed display.
2019 closeDisplayedHTML:function(){
2020 var sel_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2021 $j('#blackbg_'+sel_id
).fadeOut("slow", function(){
2022 $j('#blackbg_'+sel_id
).remove();
2024 return false; //onclick action return false
2026 selectPlaybackMethod:function(){
2027 //get id (in case where we have a parent container)
2028 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2031 var out
= '<span style="color:#FFF;background-color:black;"><blockquote style="background-color:black;">';
2033 //js_log('selected src'+ _this.media_element.selected_source.url);
2034 $j
.each( this.media_element
.getPlayableSources(), function(source_id
, source
){
2035 var default_player
= embedTypes
.players
.defaultPlayer( source
.getMIMEType() );
2037 var is_selected
= (source
== _this
.media_element
.selected_source
);
2038 var image_src
= mv_skin_img_path
;
2040 //set the Playable source type:
2041 if( source
.mime_type
== 'video/x-flv' ){
2042 image_src
+= 'flash_icon_';
2043 }else if( source
.mime_type
== 'video/h264'){
2044 //for now all mp4 content is pulled from archive.org (so use archive.org icon)
2045 image_src
+= 'archive_org_';
2047 image_src
+= 'fish_xiph_org_';
2049 image_src
+= is_selected
? 'color':'bw';
2050 image_src
+= '.png';
2054 out
+= '<img src="'+image_src
+'"/>';
2056 out
+='<a href="#" class="sel_source" id="sc_' + source_id
+ '_' + default_player
.id
+'">';
2057 out
+= source
.getTitle()+ (is_selected
?'</a>':'') + ' ';
2059 //output the player select code:
2060 var supporting_players
= embedTypes
.players
.getMIMETypePlayers( source
.getMIMEType() );
2061 out
+='<div id="player_select_list_' + source_id
+ '" class="player_select_list"><ul>';
2062 for(var i
=0; i
< supporting_players
.length
; i
++){
2063 if( _this
.selected_player
.id
== supporting_players
[i
].id
&& is_selected
){
2064 out
+='<li style="border-style:dashed;margin-left:20px;">'+
2065 '<img border="0" width="16" height="16" src="' + mv_skin_img_path
+ 'plugin.png">' +
2066 supporting_players
[i
].getName() +
2069 //else gray plugin and the plugin with link to select
2070 out
+='<li style="margin-left:20px;">'+
2071 '<a href="#" class="sel_source" id="sc_' + source_id
+ '_' + supporting_players
[i
].id
+'">'+
2072 '<img border="0" width="16" height="16" src="' + mv_skin_img_path
+ 'plugin_disabled.png">'+
2073 supporting_players
[i
].getName() +
2080 out
+= source
.getTitle() + ' - no player available';
2082 out
+='</blockquote></span>';
2083 this.displayHTML(out
);
2085 //set up the click bindings:
2086 $j('.sel_source').each(function(){
2087 $j(this).click(function(){
2088 var iparts
= $j(this).attr( 'id' ).replace(/sc_/,'').split('_');
2089 var source_id
= iparts
[0];
2090 var default_player_id
= iparts
[1];
2091 js_log('source id: ' + source_id
+ ' player id: ' + default_player_id
);
2093 $j('#' + this_id
).get(0).closeDisplayedHTML();
2094 $j('#' + _this
.id
).get(0).media_element
.selectSource( source_id
);
2096 embedTypes
.players
.userSelectPlayer( default_player_id
,
2097 _this
.media_element
.sources
[ source_id
].getMIMEType() );
2099 //be sure to issue a stop
2100 $j('#' + this_id
).get(0).stop();
2102 //don't follow the empty # link:
2107 showVideoDownload:function(){
2108 //load the roe if available (to populate out download options:
2109 //js_log('f:showVideoDownload '+ this.roe + ' ' + this.media_element.addedROEData);
2110 if(this.roe
&& this.media_element
.addedROEData
== false){
2112 this.displayHTML(gM('loading_txt'));
2113 do_request(this.roe
, function(data
)
2115 _this
.media_element
.addROE(data
);
2116 $j('#mv_disp_inner_'+_this
.id
).html( _this
.getShowVideoDownload() );
2119 this.displayHTML( this.getShowVideoDownload() );
2122 getShowVideoDownload:function(){
2123 var out
='<div style="color:white">' +
2124 '<b style="color:white;">'+gM('download_segment')+'</b><br>';
2125 out
+='<blockquote style="background:#000">'+
2126 gM('download_right_click') + '</blockquote><br>';
2129 $j
.each(this.media_element
.getSources(), function(index
, source
){
2130 var dl_line
= '<li>' + '<a style="color:white" href="' + source
.getURI() +'"> '
2131 + source
.getTitle()+'</a> '+ '</li>'+"\n";
2132 if( source
.getURI().indexOf('?t=')!==-1){
2134 }else if(this.getMIMEType()=="text/cmml" || this.getMIMEType()=="text/x-srt"){
2135 dl_txt_list
+=dl_line
;
2142 out
+=gM('download_full') + '<blockquote style="background:#000">' + dl_list
+ '</blockquote>';
2144 out
+=gM('download_text')+'<blockquote style="background:#000">' + dl_txt_list
+'</blockquote>';
2149 * base embed controls
2150 * the play button calls
2153 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2155 //js_log( "mv_embed play:" + this.id);
2156 //js_log('thum disp:'+this.thumbnail_disp);
2157 //check if thumbnail is being displayed and embed html
2158 if( this.thumbnail_disp
){
2159 if( !this.selected_player
){
2160 js_log('no selected_player');
2161 //this.innerHTML = this.getPluginMissingHTML();
2162 //$j(this).html(this.getPluginMissingHTML());
2163 $j('#'+this.id
).html( this.getPluginMissingHTML() );
2166 this.onClipDone_disp
=false;
2168 this.thumbnail_disp
=false;
2171 //the plugin is already being displayed
2172 this.paused
=false; //make sure we are not "paused"
2176 $j("#mv_play_pause_button_" + this_id
+ ' span').removeClass('ui-icon-play').addClass('ui-icon-pause');
2177 $j("#mv_play_pause_button_" + this_id
).unbind().btnBind().click(function(){
2178 $j('#' + this_id
).get(0).pause();
2179 }).attr('title', gM('pause_clip'));
2183 //should be done by child (no base way to load assets)
2184 js_log('baseEmbed:load call');
2187 return this.media_element
.selected_source
.getURI( this.seek_time_sec
);
2191 * there is no general way to pause the video
2192 * must be overwritten by embed object to support this functionality.
2195 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2196 //js_log('mv_embed:do pause');
2197 //(playing) do pause
2199 //update the ctrl "paused state"
2200 $j("#mv_play_pause_button_" + this_id
+ ' span').removeClass('ui-icon-pause').addClass('ui-icon-play');
2201 $j("#mv_play_pause_button_" + this_id
).unbind().btnBind().click(function(){
2202 $j('#'+this_id
).get(0).play();
2203 }).attr('title', gM('play_clip'));
2206 * base embed stop (can be overwritten by the plugin)
2210 js_log('mvEmbed:stop:'+this.id
);
2212 //no longer seeking:
2213 this.didSeekJump
=false;
2215 //first issue pause to update interface (only call the parent)
2216 if(this['parent_pause']){
2217 this.parent_pause();
2222 //reset the currentTime:
2224 //check if thumbnail is being displayed in which case do nothing
2225 if( this.thumbnail_disp
){
2226 //already in stooped state
2227 js_log('already in stopped state');
2229 //rewrite the html to thumbnail disp
2230 this.doThumbnailHTML();
2231 this.bufferedPercent
=0; //reset buffer state
2232 this.setSliderValue(0);
2233 this.setStatus( this.getTimeReq() );
2236 //make sure the big playbutton is has click action:
2237 $j('#big_play_link_' + _this
.id
).unbind('click').click(function(){
2238 $j('#' +_this
.id
).get(0).play();
2241 if(this.update_interval
)
2243 clearInterval(this.update_interval
);
2244 this.update_interval
= null;
2247 toggleMute:function(){
2248 var this_id
= (this.pc
!=null)?this.pc
.pp
.id
:this.id
;
2251 $j('#volume_control_'+this_id
+ ' span').removeClass('ui-icon-volume-off').addClass('ui-icon-volume-on');
2252 $j('#volume_bar_'+this_id
).slider('value', 100);
2253 this.updateVolumen(1);
2256 $j('#volume_control_'+this_id
+ ' span').removeClass('ui-icon-volume-on').addClass('ui-icon-volume-off');
2257 $j('#volume_bar_'+this_id
).slider('value', 0);
2258 this.updateVolumen(0);
2260 js_log('f:toggleMute::' + this.muted
);
2262 updateVolumen:function(perc
){
2263 js_log('update volume not supported with current playback type');
2265 fullscreen:function(){
2266 js_log('fullscreen not supported with current playback type');
2268 /* returns bool true if playing or paused, false if stooped
2270 isPlaying : function(){
2271 if(this.thumbnail_disp
){
2274 }else if( this.paused
){
2281 isPaused : function(){
2282 return this.isPlaying() && this.paused
;
2284 isStoped : function(){
2285 return this.thumbnail_disp
;
2287 playlistSupport:function(){
2288 //by default not supported (implemented in js)
2291 postEmbedJS:function(){
2294 //do common monitor code like update the playhead and play status
2295 //plugin objects are responsible for updating currentTime
2297 if( this.currentTime
&& this.currentTime
> 0 && this.duration
){
2298 if( !this.userSlide
){
2299 if( this.start_offset
){
2300 //if start offset include that calculation
2301 this.setSliderValue( ( this.currentTime
- this.start_offset
) / this.duration
);
2302 this.setStatus( seconds2npt(this.currentTime
) + '/'+ seconds2npt(parseFloat(this.start_offset
)+parseFloat(this.duration
) ));
2304 this.setSliderValue( this.currentTime
/ this.duration
);
2305 this.setStatus( seconds2npt(this.currentTime
) + '/' + seconds2npt(this.duration
));
2309 //js_log(' ct:' + this.currentTime + ' dur: ' + this.duration);
2310 if( this.isStoped() ){
2311 this.setStatus( this.getTimeReq() );
2312 }else if( this.isPaused() ){
2313 this.setStatus( "paused" );
2314 }else if( this.isPlaying() ){
2315 if( this.currentTime
&& ! this.duration
)
2316 this.setStatus( seconds2npt( this.currentTime
) + ' /' );
2318 this.setStatus(" - - - ");
2320 this.setStatus( this.getTimeReq() );
2323 //update buffer information
2324 this.updateBufferStatus();
2326 //update monitorTimerId to call child monitor
2327 if( ! this.monitorTimerId
){
2328 //make sure an instance of this.id exists:
2329 if( document
.getElementById(this.id
) ){
2330 this.monitorTimerId
= setInterval('$j(\'#'+this.id
+'\').get(0).monitor()', 250);
2334 stopMonitor:function(){
2335 if( this.monitorTimerId
!= 0 )
2337 clearInterval( this.monitorTimerId
);
2338 this.monitorTimerId
= 0;
2341 updateBufferStatus: function(){
2343 //build the buffer targeet based for playlist vs clip
2344 var buffer_select
= (this.pc
) ?
2345 '#cl_status_' + this.id
+ ' .mv_buffer':
2346 '#mv_play_head_' + this.id
+ ' .mv_buffer';
2348 //update the buffer progress bar (if available )
2349 if( this.bufferedPercent
!= 0 ){
2350 //js_log('bufferedPercent: ' + this.bufferedPercent);
2351 if(this.bufferedPercent
> 1)
2352 this.bufferedPercent
=1;
2354 $j(buffer_select
).css("width", (this.bufferedPercent
*100) +'%' );
2356 $j(buffer_select
).css("width", '0px' );
2359 relativeCurrentTime: function(){
2360 if(!this.start_offset
)
2361 this.start_offset
=0;
2362 var rt
= this.currentTime
- this.start_offset
;
2363 if( rt
< 0 ) //should not happen but does.
2367 getPluginEmbed : function(){
2368 if (window
.document
[this.pid
]){
2369 return window
.document
[this.pid
];
2371 if ($j
.browser
.msie
){
2372 return document
.getElementById(this.pid
);
2374 if (document
.embeds
&& document
.embeds
[this.pid
])
2375 return document
.embeds
[this.pid
];
2379 //HELPER Functions for selected source
2381 * returns the selected source url for players to play
2383 getURI : function( seek_time_sec
){
2384 return this.media_element
.selected_source
.getURI( this.seek_time_sec
);
2386 supportsURLTimeEncoding: function(){
2387 //do head request if on the same domain
2388 return this.media_element
.selected_source
.URLTimeEncoding
;
2390 setSliderValue: function(perc
, hide_progress
){
2392 var this_id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2393 var val
= parseInt( perc
*1000 );
2394 $j('#mv_play_head_'+this_id
).slider('value', val
);
2396 //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) );
2397 //js_log('op:' + offset_perc + ' *('+perc+' * ' + $j('#slider_'+id).width() + ')');
2399 highlightPlaySection:function(options
){
2400 js_log('highlightPlaySection');
2401 var this_id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2402 var dur
= this.getDuration();
2403 var hide_progress
= true;
2404 //set the left percet and update the slider:
2405 rel_start_sec
= npt2seconds( options
['start']);
2406 //remove the start_offset if relevent:
2407 if(this.start_offset
)
2408 rel_start_sec
= rel_start_sec
- this.start_offset
2411 if( rel_start_sec
<= 0 ){
2413 options
['start'] = seconds2npt( this.start_offset
);
2415 this.setSliderValue( 0 , hide_progress
);
2417 left_perc
= parseInt( (rel_start_sec
/ dur
)*100 ) ;
2418 slider_perc
= (left_perc
/ 100);
2420 js_log("slider perc:" + slider_perc
);
2421 if( ! this.isPlaying() ){
2422 this.setSliderValue( slider_perc
, hide_progress
);
2425 width_perc
= parseInt( (( npt2seconds( options
['end'] ) - npt2seconds( options
['start'] ) ) / dur
)*100 ) ;
2426 if( (width_perc
+ left_perc
) > 100 ){
2427 width_perc
= 100 - left_perc
;
2429 //js_log('should hl: '+rel_start_sec+ '/' + dur + ' re:' + rel_end_sec+' lp:' + left_perc + ' width: ' + width_perc);
2430 $j('#mv_seeker_' + this_id
+ ' .mv_highlight').css({
2431 'left':left_perc
+'%',
2432 'width':width_perc
+'%'
2435 this.jump_time
= options
['start'];
2436 this.seek_time_sec
= npt2seconds( options
['start']);
2438 this.setStatus( gM('seek_to')+' '+ seconds2npt( this.seek_time_sec
) );
2439 js_log('DO update: ' + this.jump_time
);
2440 this.updateThumbTime( rel_start_sec
);
2442 hideHighlight:function(){
2443 var this_id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2444 $j('#mv_seeker_' + this_id
+ ' .mv_highlight').hide();
2445 this.setStatus( this.getTimeReq() );
2446 this.setSliderValue( 0 );
2448 setStatus:function(value
){
2449 var id
= (this.pc
)?this.pc
.pp
.id
:this.id
;
2451 $j('#mv_time_'+id
).html(value
);
2458 * mediaPlayer represents a media player plugin.
2459 * @param {String} id id used for the plugin.
2460 * @param {Array<String>} supported_types n array of supported MIME types.
2461 * @param {String} library external script containing the plugin interface code. (mv_<library>Embed.js)
2464 function mediaPlayer(id
, supported_types
, library
)
2467 this.supported_types
= supported_types
;
2468 this.library
= library
;
2469 this.loaded
= false;
2470 this.loading_callbacks
= new Array();
2473 mediaPlayer
.prototype =
2476 supported_types
:null,
2479 loading_callbacks
:null,
2480 supportsMIMEType : function(type
)
2482 for (var i
=0; i
< this.supported_types
.length
; i
++)
2483 if(this.supported_types
[i
] == type
)
2487 getName : function()
2489 return gM('mv_ogg-player-' + this.id
);
2491 load : function(callback
){
2492 var libName
= this.library
+'Embed';
2493 if( mvJsLoader
.checkObjPath( libName
) ){
2494 js_log('plugin loaded, do callback:');
2498 //jQuery based get script does not work so well.
2507 /* players and supported mime types
2508 @@todo ideally we query the plugin to get what mime types it supports in practice not always reliable/avaliable
2510 var flowPlayer
= new mediaPlayer('flowplayer',['video/x-flv', 'video/h264'],'flash');
2512 var omtkPlayer
= new mediaPlayer('omtkplayer',['audio/ogg'], 'omtk' );
2514 var cortadoPlayer
= new mediaPlayer('cortado',['video/ogg', 'audio/ogg'],'java');
2515 var videoElementPlayer
= new mediaPlayer('videoElement',['video/ogg', 'audio/ogg'],'native');
2517 var vlcMineList
= ['video/ogg','audio/ogg', 'video/x-flv', 'video/mp4', 'video/h264'];
2518 var vlcMozillaPlayer
= new mediaPlayer('vlc-mozilla',vlcMineList
,'vlc');
2519 var vlcActiveXPlayer
= new mediaPlayer('vlc-activex',vlcMineList
,'vlc');
2522 var oggPluginPlayer
= new mediaPlayer('oggPlugin',['video/ogg'],'generic');
2524 //depricate quicktime in favor of safari native
2525 //var quicktimeMozillaPlayer = new mediaPlayer('quicktime-mozilla',['video/ogg'],'quicktime');
2526 //var quicktimeActiveXPlayer = new mediaPlayer('quicktime-activex',['video/ogg'],'quicktime');
2528 var htmlPlayer
= new mediaPlayer('html',['text/html', 'image/jpeg', 'image/png', 'image/svg'], 'html');
2531 * mediaPlayers is a collection of mediaPlayer objects supported by the client.
2532 * It could be merged with embedTypes, since there is one embedTypes per script
2533 * and one mediaPlayers per embedTypes.
2535 function mediaPlayers()
2540 mediaPlayers
.prototype =
2544 default_players
: {},
2547 this.players
= new Array();
2548 this.loadPreferences();
2550 //set up default players order for each library type
2551 this.default_players
['video/x-flv'] = ['flash','vlc'];
2552 this.default_players
['video/h264'] = ['flash', 'vlc'];
2554 this.default_players
['video/ogg'] = ['native','vlc','java', 'generic'];
2555 this.default_players
['application/ogg'] = ['native','vlc','java', 'generic'];
2556 this.default_players
['audio/ogg'] = ['native','vlc', 'java', 'omtk' ];
2557 this.default_players
['video/mp4'] = ['vlc'];
2559 this.default_players
['text/html'] = ['html'];
2560 this.default_players
['image/jpeg'] = ['html'];
2563 addPlayer : function(player
, mime_type
)
2565 //js_log('Adding ' + player.id + ' with mime_type ' + mime_type);
2566 for (var i
=0; i
< this.players
.length
; i
++){
2567 if (this.players
[i
].id
== player
.id
)
2571 //make sure the mime_type is not already there:
2572 var add_mime
= true;
2573 for(var j
=0; j
< this.players
[i
].supported_types
.length
; j
++ ){
2574 if( this.players
[i
].supported_types
[j
]== mime_type
)
2578 this.players
[i
].supported_types
.push(mime_type
);
2585 player
.supported_types
.push(mime_type
);
2587 this.players
.push( player
);
2589 getMIMETypePlayers : function(mime_type
)
2591 var mime_players
= new Array();
2594 if( this.default_players
[mime_type
] ){
2595 $j
.each( this.default_players
[mime_type
], function(d
, lib
){
2596 var library
= _this
.default_players
[mime_type
][d
];
2597 for ( var i
=0; i
< _this
.players
.length
; i
++ ){
2598 if ( _this
.players
[i
].library
== library
&& _this
.players
[i
].supportsMIMEType(mime_type
) ){
2599 mime_players
[ inx
] = _this
.players
[i
];
2605 return mime_players
;
2607 defaultPlayer : function(mime_type
)
2609 js_log("f:defaultPlayer: " + mime_type
);
2610 var mime_players
= this.getMIMETypePlayers(mime_type
);
2611 if( mime_players
.length
> 0)
2613 // check for prior preference for this mime type
2614 for( var i
=0; i
< mime_players
.length
; i
++ ){
2615 if( mime_players
[i
].id
==this.preference
[mime_type
] )
2616 return mime_players
[i
];
2618 // otherwise just return the first compatible player
2619 // (it will be chosen according to the default_players list
2620 return mime_players
[0];
2622 js_log( 'No default player found for ' + mime_type
);
2625 userSelectFormat : function (mime_format
){
2626 this.preference
['format_prefrence'] = mime_format
;
2627 this.savePreferences();
2629 userSelectPlayer : function(player_id
, mime_type
)
2631 var selected_player
=null;
2632 for(var i
=0; i
< this.players
.length
; i
++){
2633 if(this.players
[i
].id
== player_id
)
2635 selected_player
= this.players
[i
];
2636 js_log('choosing ' + player_id
+ ' for ' + mime_type
);
2637 this.preference
[mime_type
]=player_id
;
2638 this.savePreferences();
2642 if( selected_player
)
2644 for(var i
=0; i
< global_player_list
.length
; i
++)
2646 var embed
= $j('#'+global_player_list
[i
]).get(0);
2647 if(embed
.media_element
.selected_source
&& (embed
.media_element
.selected_source
.mime_type
== mime_type
))
2649 embed
.selectPlayer(selected_player
);
2650 js_log('using ' + embed
.selected_player
.getName() + ' for ' + embed
.media_element
.selected_source
.getTitle());
2655 loadPreferences : function()
2657 this.preference
= new Object();
2658 // see if we have a cookie set to a clientSupported type:
2659 var cookieVal
= $j
.cookie( 'ogg_player_exp' );
2662 var pairs
= cookieVal
.split('&');
2663 for(var i
=0; i
< pairs
.length
; i
++)
2665 var name_value
= pairs
[i
].split('=');
2666 this.preference
[name_value
[0]]=name_value
[1];
2667 //js_log('load preference for ' + name_value[0] + ' is ' + name_value[1]);
2671 savePreferences : function()
2674 for(var i
in this.preference
)
2675 cookieVal
+= i
+ '='+ this.preference
[i
] + '&';
2677 cookieVal
=cookieVal
.substr(0, cookieVal
.length
-1);
2678 var week
= 7*86400*1000;
2679 $j
.cookie( 'ogg_player_exp', cookieVal
, { 'expires':week
} );
2684 * embedTypes object handles setting and getting of supported embed types:
2685 * closely mirrors OggHandler so that its easier to share efforts in this area:
2686 * http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/OggHandler/OggPlayer.js
2693 //detect supported types
2695 this.detect_done
=true;
2697 clientSupports
: { 'thumbnail' : true },
2698 supportedMimeType: function(mimetype
) {
2699 for (var i
= navigator
.plugins
.length
; i
-- > 0; ) {
2700 var plugin
= navigator
.plugins
[i
];
2701 if (typeof plugin
[mimetype
] != "undefined")
2707 detect: function() {
2708 js_log("running detect");
2709 this.players
= new mediaPlayers();
2710 //every browser supports html rendering:
2711 this.players
.addPlayer( htmlPlayer
);
2712 // In Mozilla, navigator.javaEnabled() only tells us about preferences, we need to
2713 // search navigator.mimeTypes to see if it's installed
2714 var javaEnabled
= navigator
.javaEnabled();
2715 // In Opera, navigator.javaEnabled() is all there is
2716 var invisibleJava
= $j
.browser
.opera
;
2717 // Some browsers filter out duplicate mime types, hiding some plugins
2718 var uniqueMimesOnly
= $j
.browser
.opera
|| $j
.browser
.safari
;
2719 // Opera will switch off javaEnabled in preferences if java can't be found.
2720 // And it doesn't register an application/x-java-applet mime type like Mozilla does.
2721 if ( invisibleJava
&& javaEnabled
)
2722 this.players
.addPlayer( cortadoPlayer
);
2725 if($j
.browser
.msie
){
2727 if ( this.testActiveX( 'ShockwaveFlash.ShockwaveFlash')){
2728 //try to get the flash version for omtk include:
2730 a
= new ActiveXObject(SHOCKWAVE_FLASH_AX
+ ".7");
2731 d
= a
.GetVariable("$version"); // Will crash fp6.0.21/23/29
2733 d
= d
.split(" ")[1].split(",");
2734 //we need flash version 10 or greater:
2735 if(parseInt( d
[0]) >=10){
2736 this.players
.addPlayer( omtkPlayer
);
2742 //flowplayer has pretty good compatiablity
2743 // (but if we wanted to be fancy we would check for version of flash and update the mp4/h.264 support
2744 this.players
.addPlayer( flowPlayer
);
2747 if ( this.testActiveX( 'VideoLAN.VLCPlugin.2' ) )
2748 this.players
.addPlayer(vlcActiveXPlayer
);
2750 if ( javaEnabled
&& this.testActiveX( 'JavaWebStart.isInstalled' ) )
2751 this.players
.addPlayer(cortadoPlayer
);
2753 //if ( this.testActiveX( 'QuickTimeCheckObject.QuickTimeCheck.1' ) )
2754 // this.players.addPlayer(quicktimeActiveXPlayer);
2757 if ( typeof HTMLVideoElement
== 'object' // Firefox, Safari
2758 || typeof HTMLVideoElement
== 'function' ) // Opera
2760 //do another test for safari:
2761 if( $j
.browser
.safari
){
2763 var dummyvid
= document
.createElement("video");
2764 if (dummyvid
.canPlayType
&& dummyvid
.canPlayType("video/ogg;codecs=\"theora,vorbis\"") == "probably")
2766 this.players
.addPlayer( videoElementPlayer
);
2767 } else if(this.supportedMimeType( 'video/ogg' )) {
2768 /* older versions of safari do not support canPlayType,
2769 but xiph qt registers mimetype via quicktime plugin */
2770 this.players
.addPlayer( videoElementPlayer
);
2772 //@@todo add some user nagging to install the xiph qt
2775 js_log('could not run canPlayType in safari');
2778 this.players
.addPlayer( videoElementPlayer
);
2783 if( navigator
.mimeTypes
&& navigator
.mimeTypes
.length
> 0) {
2784 for ( var i
= 0; i
< navigator
.mimeTypes
.length
; i
++ ) {
2785 var type
= navigator
.mimeTypes
[i
].type
;
2786 var semicolonPos
= type
.indexOf( ';' );
2787 if ( semicolonPos
> -1 ) {
2788 type
= type
.substr( 0, semicolonPos
);
2790 //js_log('on type: '+type);
2791 var pluginName
= navigator
.mimeTypes
[i
].enabledPlugin
? navigator
.mimeTypes
[i
].enabledPlugin
.name
: '';
2792 if ( !pluginName
) {
2793 // In case it is null or undefined
2796 if ( pluginName
.toLowerCase() == 'vlc multimedia plugin' || pluginName
.toLowerCase() == 'vlc multimedia plug-in' ) {
2797 this.players
.addPlayer(vlcMozillaPlayer
, type
);
2801 if ( javaEnabled
&& type
== 'application/x-java-applet' ) {
2802 this.players
.addPlayer(cortadoPlayer
);
2806 if ( type
== 'application/ogg' ) {
2807 if ( pluginName
.toLowerCase() == 'vlc multimedia plugin' ){
2808 this.players
.addPlayer(vlcMozillaPlayer
, type
);
2809 //else if ( pluginName.indexOf( 'QuickTime' ) > -1 )
2810 // this.players.addPlayer(quicktimeMozillaPlayer);
2812 this.players
.addPlayer(oggPluginPlayer
);
2815 } else if ( uniqueMimesOnly
) {
2816 if ( type
== 'application/x-vlc-player' ) {
2817 this.players
.addPlayer(vlcMozillaPlayer
, type
);
2819 } else if ( type
== 'video/quicktime' ) {
2820 //this.players.addPlayer(quicktimeMozillaPlayer);
2825 /*if ( type == 'video/quicktime' ) {
2826 this.players.addPlayer(vlcMozillaPlayer, type);
2829 if(type
=='application/x-shockwave-flash'){
2830 this.players
.addPlayer( flowPlayer
);
2832 //check version to add omtk:
2833 var flashDescription
= navigator
.plugins
["Shockwave Flash"].description
;
2834 var descArray
= flashDescription
.split(" ");
2835 var tempArrayMajor
= descArray
[2].split(".");
2836 var versionMajor
= tempArrayMajor
[0];
2837 //js_log("version of flash: " + versionMajor);
2838 if(versionMajor
>= 10){
2839 this.players
.addPlayer( omtkPlayer
);
2845 //@@The xiph quicktime component does not work well with annodex streams (temporarly disable)
2846 //this.clientSupports['quicktime-mozilla'] = false;
2847 //this.clientSupports['quicktime-activex'] = false;
2848 //js_log(this.clientSupports);
2850 testActiveX : function ( name
) {
2853 // No IE, not a class called "name", it's a variable
2854 var obj
= new ActiveXObject( '' + name
);