gyorgy@0
|
1 /*!
|
gyorgy@0
|
2 * MediaElement.js
|
gyorgy@0
|
3 * HTML5 <video> and <audio> shim and player
|
gyorgy@0
|
4 * http://mediaelementjs.com/
|
gyorgy@0
|
5 *
|
gyorgy@0
|
6 * Creates a JavaScript object that mimics HTML5 MediaElement API
|
gyorgy@0
|
7 * for browsers that don't understand HTML5 or can't play the provided codec
|
gyorgy@0
|
8 * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
|
gyorgy@0
|
9 *
|
gyorgy@0
|
10 * Copyright 2010-2011, John Dyer (http://j.hn)
|
gyorgy@0
|
11 * Dual licensed under the MIT or GPL Version 2 licenses.
|
gyorgy@0
|
12 *
|
gyorgy@0
|
13 */
|
gyorgy@0
|
14 // Namespace
|
gyorgy@0
|
15 var mejs = mejs || {};
|
gyorgy@0
|
16
|
gyorgy@0
|
17 // version number
|
gyorgy@0
|
18 mejs.version = '2.1.9';
|
gyorgy@0
|
19
|
gyorgy@0
|
20 // player number (for missing, same id attr)
|
gyorgy@0
|
21 mejs.meIndex = 0;
|
gyorgy@0
|
22
|
gyorgy@0
|
23 // media types accepted by plugins
|
gyorgy@0
|
24 mejs.plugins = {
|
gyorgy@0
|
25 silverlight: [
|
gyorgy@0
|
26 {version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}
|
gyorgy@0
|
27 ],
|
gyorgy@0
|
28 flash: [
|
gyorgy@0
|
29 {version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg']}
|
gyorgy@0
|
30 //,{version: [11,0], types: ['video/webm']} // for future reference
|
gyorgy@0
|
31 ]
|
gyorgy@0
|
32 };
|
gyorgy@0
|
33
|
gyorgy@0
|
34 /*
|
gyorgy@0
|
35 Utility methods
|
gyorgy@0
|
36 */
|
gyorgy@0
|
37 mejs.Utility = {
|
gyorgy@0
|
38 encodeUrl: function(url) {
|
gyorgy@0
|
39 return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
|
gyorgy@0
|
40 },
|
gyorgy@0
|
41 escapeHTML: function(s) {
|
gyorgy@0
|
42 return s.toString().split('&').join('&').split('<').join('<').split('"').join('"');
|
gyorgy@0
|
43 },
|
gyorgy@0
|
44 absolutizeUrl: function(url) {
|
gyorgy@0
|
45 var el = document.createElement('div');
|
gyorgy@0
|
46 el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
|
gyorgy@0
|
47 return el.firstChild.href;
|
gyorgy@0
|
48 },
|
gyorgy@0
|
49 getScriptPath: function(scriptNames) {
|
gyorgy@0
|
50 var
|
gyorgy@0
|
51 i = 0,
|
gyorgy@0
|
52 j,
|
gyorgy@0
|
53 path = '',
|
gyorgy@0
|
54 name = '',
|
gyorgy@0
|
55 script,
|
gyorgy@0
|
56 scripts = document.getElementsByTagName('script');
|
gyorgy@0
|
57
|
gyorgy@0
|
58 for (; i < scripts.length; i++) {
|
gyorgy@0
|
59 script = scripts[i].src;
|
gyorgy@0
|
60 for (j = 0; j < scriptNames.length; j++) {
|
gyorgy@0
|
61 name = scriptNames[j];
|
gyorgy@0
|
62 if (script.indexOf(name) > -1) {
|
gyorgy@0
|
63 path = script.substring(0, script.indexOf(name));
|
gyorgy@0
|
64 break;
|
gyorgy@0
|
65 }
|
gyorgy@0
|
66 }
|
gyorgy@0
|
67 if (path !== '') {
|
gyorgy@0
|
68 break;
|
gyorgy@0
|
69 }
|
gyorgy@0
|
70 }
|
gyorgy@0
|
71 return path;
|
gyorgy@0
|
72 },
|
gyorgy@0
|
73 secondsToTimeCode: function(seconds,forceHours) {
|
gyorgy@0
|
74 seconds = Math.round(seconds);
|
gyorgy@0
|
75 var hours,
|
gyorgy@0
|
76 minutes = Math.floor(seconds / 60);
|
gyorgy@0
|
77 if (minutes >= 60) {
|
gyorgy@0
|
78 hours = Math.floor(minutes / 60);
|
gyorgy@0
|
79 minutes = minutes % 60;
|
gyorgy@0
|
80 }
|
gyorgy@0
|
81 hours = hours === undefined ? "00" : (hours >= 10) ? hours : "0" + hours;
|
gyorgy@0
|
82 minutes = (minutes >= 10) ? minutes : "0" + minutes;
|
gyorgy@0
|
83 seconds = Math.floor(seconds % 60);
|
gyorgy@0
|
84 seconds = (seconds >= 10) ? seconds : "0" + seconds;
|
gyorgy@0
|
85 return ((hours > 0 || forceHours === true) ? hours + ":" :'') + minutes + ":" + seconds;
|
gyorgy@0
|
86 },
|
gyorgy@0
|
87 timeCodeToSeconds: function(timecode){
|
gyorgy@0
|
88 var tab = timecode.split(':');
|
gyorgy@0
|
89 return tab[0]*60*60 + tab[1]*60 + parseFloat(tab[2].replace(',','.'));
|
gyorgy@0
|
90 }
|
gyorgy@0
|
91 };
|
gyorgy@0
|
92
|
gyorgy@0
|
93
|
gyorgy@0
|
94 // Core detector, plugins are added below
|
gyorgy@0
|
95 mejs.PluginDetector = {
|
gyorgy@0
|
96
|
gyorgy@0
|
97 // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
|
gyorgy@0
|
98 hasPluginVersion: function(plugin, v) {
|
gyorgy@0
|
99 var pv = this.plugins[plugin];
|
gyorgy@0
|
100 v[1] = v[1] || 0;
|
gyorgy@0
|
101 v[2] = v[2] || 0;
|
gyorgy@0
|
102 return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
|
gyorgy@0
|
103 },
|
gyorgy@0
|
104
|
gyorgy@0
|
105 // cached values
|
gyorgy@0
|
106 nav: window.navigator,
|
gyorgy@0
|
107 ua: window.navigator.userAgent.toLowerCase(),
|
gyorgy@0
|
108
|
gyorgy@0
|
109 // stored version numbers
|
gyorgy@0
|
110 plugins: [],
|
gyorgy@0
|
111
|
gyorgy@0
|
112 // runs detectPlugin() and stores the version number
|
gyorgy@0
|
113 addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
|
gyorgy@0
|
114 this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
|
gyorgy@0
|
115 },
|
gyorgy@0
|
116
|
gyorgy@0
|
117 // get the version number from the mimetype (all but IE) or ActiveX (IE)
|
gyorgy@0
|
118 detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
|
gyorgy@0
|
119
|
gyorgy@0
|
120 var version = [0,0,0],
|
gyorgy@0
|
121 description,
|
gyorgy@0
|
122 i,
|
gyorgy@0
|
123 ax;
|
gyorgy@0
|
124
|
gyorgy@0
|
125 // Firefox, Webkit, Opera
|
gyorgy@0
|
126 if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
|
gyorgy@0
|
127 description = this.nav.plugins[pluginName].description;
|
gyorgy@0
|
128 if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
|
gyorgy@0
|
129 version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
|
gyorgy@0
|
130 for (i=0; i<version.length; i++) {
|
gyorgy@0
|
131 version[i] = parseInt(version[i].match(/\d+/), 10);
|
gyorgy@0
|
132 }
|
gyorgy@0
|
133 }
|
gyorgy@0
|
134 // Internet Explorer / ActiveX
|
gyorgy@0
|
135 } else if (typeof(window.ActiveXObject) != 'undefined') {
|
gyorgy@0
|
136 try {
|
gyorgy@0
|
137 ax = new ActiveXObject(activeX);
|
gyorgy@0
|
138 if (ax) {
|
gyorgy@0
|
139 version = axDetect(ax);
|
gyorgy@0
|
140 }
|
gyorgy@0
|
141 }
|
gyorgy@0
|
142 catch (e) { }
|
gyorgy@0
|
143 }
|
gyorgy@0
|
144 return version;
|
gyorgy@0
|
145 }
|
gyorgy@0
|
146 };
|
gyorgy@0
|
147
|
gyorgy@0
|
148 // Add Flash detection
|
gyorgy@0
|
149 mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
|
gyorgy@0
|
150 // adapted from SWFObject
|
gyorgy@0
|
151 var version = [],
|
gyorgy@0
|
152 d = ax.GetVariable("$version");
|
gyorgy@0
|
153 if (d) {
|
gyorgy@0
|
154 d = d.split(" ")[1].split(",");
|
gyorgy@0
|
155 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
gyorgy@0
|
156 }
|
gyorgy@0
|
157 return version;
|
gyorgy@0
|
158 });
|
gyorgy@0
|
159
|
gyorgy@0
|
160 // Add Silverlight detection
|
gyorgy@0
|
161 mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
|
gyorgy@0
|
162 // Silverlight cannot report its version number to IE
|
gyorgy@0
|
163 // but it does have a isVersionSupported function, so we have to loop through it to get a version number.
|
gyorgy@0
|
164 // adapted from http://www.silverlightversion.com/
|
gyorgy@0
|
165 var v = [0,0,0,0],
|
gyorgy@0
|
166 loopMatch = function(ax, v, i, n) {
|
gyorgy@0
|
167 while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
|
gyorgy@0
|
168 v[i]+=n;
|
gyorgy@0
|
169 }
|
gyorgy@0
|
170 v[i] -= n;
|
gyorgy@0
|
171 };
|
gyorgy@0
|
172 loopMatch(ax, v, 0, 1);
|
gyorgy@0
|
173 loopMatch(ax, v, 1, 1);
|
gyorgy@0
|
174 loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
|
gyorgy@0
|
175 loopMatch(ax, v, 2, 1000);
|
gyorgy@0
|
176 loopMatch(ax, v, 2, 100);
|
gyorgy@0
|
177 loopMatch(ax, v, 2, 10);
|
gyorgy@0
|
178 loopMatch(ax, v, 2, 1);
|
gyorgy@0
|
179 loopMatch(ax, v, 3, 1);
|
gyorgy@0
|
180
|
gyorgy@0
|
181 return v;
|
gyorgy@0
|
182 });
|
gyorgy@0
|
183 // add adobe acrobat
|
gyorgy@0
|
184 /*
|
gyorgy@0
|
185 PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
|
gyorgy@0
|
186 var version = [],
|
gyorgy@0
|
187 d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
|
gyorgy@0
|
188
|
gyorgy@0
|
189 if (d) {
|
gyorgy@0
|
190 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
gyorgy@0
|
191 }
|
gyorgy@0
|
192 return version;
|
gyorgy@0
|
193 });
|
gyorgy@0
|
194 */
|
gyorgy@0
|
195 // necessary detection (fixes for <IE9)
|
gyorgy@0
|
196 mejs.MediaFeatures = {
|
gyorgy@0
|
197 init: function() {
|
gyorgy@0
|
198 var
|
gyorgy@0
|
199 nav = mejs.PluginDetector.nav,
|
gyorgy@0
|
200 ua = mejs.PluginDetector.ua.toLowerCase(),
|
gyorgy@0
|
201 i,
|
gyorgy@0
|
202 v,
|
gyorgy@0
|
203 html5Elements = ['source','track','audio','video'];
|
gyorgy@0
|
204
|
gyorgy@0
|
205 // detect browsers (only the ones that have some kind of quirk we need to work around)
|
gyorgy@0
|
206 this.isiPad = (ua.match(/ipad/i) !== null);
|
gyorgy@0
|
207 this.isiPhone = (ua.match(/iphone/i) !== null);
|
gyorgy@0
|
208 this.isAndroid = (ua.match(/android/i) !== null);
|
gyorgy@0
|
209 this.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
|
gyorgy@0
|
210 this.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
|
gyorgy@0
|
211 this.isChrome = (ua.match(/chrome/gi) !== null);
|
gyorgy@0
|
212 this.isFirefox = (ua.match(/firefox/gi) !== null);
|
gyorgy@0
|
213
|
gyorgy@0
|
214 // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
|
gyorgy@0
|
215 for (i=0; i<html5Elements.length; i++) {
|
gyorgy@0
|
216 v = document.createElement(html5Elements[i]);
|
gyorgy@0
|
217 }
|
gyorgy@0
|
218
|
gyorgy@0
|
219 // detect native JavaScript fullscreen (Safari only, Chrome fails)
|
gyorgy@0
|
220 this.hasNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
|
gyorgy@0
|
221 if (this.isChrome) {
|
gyorgy@0
|
222 this.hasNativeFullScreen = false;
|
gyorgy@0
|
223 }
|
gyorgy@0
|
224 // OS X 10.5 can't do this even if it says it can :(
|
gyorgy@0
|
225 if (this.hasNativeFullScreen && ua.match(/mac os x 10_5/i)) {
|
gyorgy@0
|
226 this.hasNativeFullScreen = false;
|
gyorgy@0
|
227 }
|
gyorgy@0
|
228 }
|
gyorgy@0
|
229 };
|
gyorgy@0
|
230 mejs.MediaFeatures.init();
|
gyorgy@0
|
231
|
gyorgy@0
|
232
|
gyorgy@0
|
233 /*
|
gyorgy@0
|
234 extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
|
gyorgy@0
|
235 */
|
gyorgy@0
|
236 mejs.HtmlMediaElement = {
|
gyorgy@0
|
237 pluginType: 'native',
|
gyorgy@0
|
238 isFullScreen: false,
|
gyorgy@0
|
239
|
gyorgy@0
|
240 setCurrentTime: function (time) {
|
gyorgy@0
|
241 this.currentTime = time;
|
gyorgy@0
|
242 },
|
gyorgy@0
|
243
|
gyorgy@0
|
244 setMuted: function (muted) {
|
gyorgy@0
|
245 this.muted = muted;
|
gyorgy@0
|
246 },
|
gyorgy@0
|
247
|
gyorgy@0
|
248 setVolume: function (volume) {
|
gyorgy@0
|
249 this.volume = volume;
|
gyorgy@0
|
250 },
|
gyorgy@0
|
251
|
gyorgy@0
|
252 // for parity with the plugin versions
|
gyorgy@0
|
253 stop: function () {
|
gyorgy@0
|
254 this.pause();
|
gyorgy@0
|
255 },
|
gyorgy@0
|
256
|
gyorgy@0
|
257 // This can be a url string
|
gyorgy@0
|
258 // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
gyorgy@0
|
259 setSrc: function (url) {
|
gyorgy@0
|
260 if (typeof url == 'string') {
|
gyorgy@0
|
261 this.src = url;
|
gyorgy@0
|
262 } else {
|
gyorgy@0
|
263 var i, media;
|
gyorgy@0
|
264
|
gyorgy@0
|
265 for (i=0; i<url.length; i++) {
|
gyorgy@0
|
266 media = url[i];
|
gyorgy@0
|
267 if (this.canPlayType(media.type)) {
|
gyorgy@0
|
268 this.src = media.src;
|
gyorgy@0
|
269 }
|
gyorgy@0
|
270 }
|
gyorgy@0
|
271 }
|
gyorgy@0
|
272 },
|
gyorgy@0
|
273
|
gyorgy@0
|
274 setVideoSize: function (width, height) {
|
gyorgy@0
|
275 this.width = width;
|
gyorgy@0
|
276 this.height = height;
|
gyorgy@0
|
277 }
|
gyorgy@0
|
278 };
|
gyorgy@0
|
279
|
gyorgy@0
|
280 /*
|
gyorgy@0
|
281 Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
|
gyorgy@0
|
282 */
|
gyorgy@0
|
283 mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
|
gyorgy@0
|
284 this.id = pluginid;
|
gyorgy@0
|
285 this.pluginType = pluginType;
|
gyorgy@0
|
286 this.src = mediaUrl;
|
gyorgy@0
|
287 this.events = {};
|
gyorgy@0
|
288 };
|
gyorgy@0
|
289
|
gyorgy@0
|
290 // JavaScript values and ExternalInterface methods that match HTML5 video properties methods
|
gyorgy@0
|
291 // http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
|
gyorgy@0
|
292 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
gyorgy@0
|
293 mejs.PluginMediaElement.prototype = {
|
gyorgy@0
|
294
|
gyorgy@0
|
295 // special
|
gyorgy@0
|
296 pluginElement: null,
|
gyorgy@0
|
297 pluginType: '',
|
gyorgy@0
|
298 isFullScreen: false,
|
gyorgy@0
|
299
|
gyorgy@0
|
300 // not implemented :(
|
gyorgy@0
|
301 playbackRate: -1,
|
gyorgy@0
|
302 defaultPlaybackRate: -1,
|
gyorgy@0
|
303 seekable: [],
|
gyorgy@0
|
304 played: [],
|
gyorgy@0
|
305
|
gyorgy@0
|
306 // HTML5 read-only properties
|
gyorgy@0
|
307 paused: true,
|
gyorgy@0
|
308 ended: false,
|
gyorgy@0
|
309 seeking: false,
|
gyorgy@0
|
310 duration: 0,
|
gyorgy@0
|
311 error: null,
|
gyorgy@0
|
312
|
gyorgy@0
|
313 // HTML5 get/set properties, but only set (updated by event handlers)
|
gyorgy@0
|
314 muted: false,
|
gyorgy@0
|
315 volume: 1,
|
gyorgy@0
|
316 currentTime: 0,
|
gyorgy@0
|
317
|
gyorgy@0
|
318 // HTML5 methods
|
gyorgy@0
|
319 play: function () {
|
gyorgy@0
|
320 if (this.pluginApi != null) {
|
gyorgy@0
|
321 this.pluginApi.playMedia();
|
gyorgy@0
|
322 this.paused = false;
|
gyorgy@0
|
323 }
|
gyorgy@0
|
324 },
|
gyorgy@0
|
325 load: function () {
|
gyorgy@0
|
326 if (this.pluginApi != null) {
|
gyorgy@0
|
327 this.pluginApi.loadMedia();
|
gyorgy@0
|
328 this.paused = false;
|
gyorgy@0
|
329 }
|
gyorgy@0
|
330 },
|
gyorgy@0
|
331 pause: function () {
|
gyorgy@0
|
332 if (this.pluginApi != null) {
|
gyorgy@0
|
333 this.pluginApi.pauseMedia();
|
gyorgy@0
|
334 this.paused = true;
|
gyorgy@0
|
335 }
|
gyorgy@0
|
336 },
|
gyorgy@0
|
337 stop: function () {
|
gyorgy@0
|
338 if (this.pluginApi != null) {
|
gyorgy@0
|
339 this.pluginApi.stopMedia();
|
gyorgy@0
|
340 this.paused = true;
|
gyorgy@0
|
341 }
|
gyorgy@0
|
342 },
|
gyorgy@0
|
343 canPlayType: function(type) {
|
gyorgy@0
|
344 var i,
|
gyorgy@0
|
345 j,
|
gyorgy@0
|
346 pluginInfo,
|
gyorgy@0
|
347 pluginVersions = mejs.plugins[this.pluginType];
|
gyorgy@0
|
348
|
gyorgy@0
|
349 for (i=0; i<pluginVersions.length; i++) {
|
gyorgy@0
|
350 pluginInfo = pluginVersions[i];
|
gyorgy@0
|
351
|
gyorgy@0
|
352 // test if user has the correct plugin version
|
gyorgy@0
|
353 if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
|
gyorgy@0
|
354
|
gyorgy@0
|
355 // test for plugin playback types
|
gyorgy@0
|
356 for (j=0; j<pluginInfo.types.length; j++) {
|
gyorgy@0
|
357 // find plugin that can play the type
|
gyorgy@0
|
358 if (type == pluginInfo.types[j]) {
|
gyorgy@0
|
359 return true;
|
gyorgy@0
|
360 }
|
gyorgy@0
|
361 }
|
gyorgy@0
|
362 }
|
gyorgy@0
|
363 }
|
gyorgy@0
|
364
|
gyorgy@0
|
365 return false;
|
gyorgy@0
|
366 },
|
gyorgy@0
|
367
|
gyorgy@0
|
368 // custom methods since not all JavaScript implementations support get/set
|
gyorgy@0
|
369
|
gyorgy@0
|
370 // This can be a url string
|
gyorgy@0
|
371 // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
gyorgy@0
|
372 setSrc: function (url) {
|
gyorgy@0
|
373 if (typeof url == 'string') {
|
gyorgy@0
|
374 this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
|
gyorgy@0
|
375 this.src = mejs.Utility.absolutizeUrl(url);
|
gyorgy@0
|
376 } else {
|
gyorgy@0
|
377 var i, media;
|
gyorgy@0
|
378
|
gyorgy@0
|
379 for (i=0; i<url.length; i++) {
|
gyorgy@0
|
380 media = url[i];
|
gyorgy@0
|
381 if (this.canPlayType(media.type)) {
|
gyorgy@0
|
382 this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
|
gyorgy@0
|
383 this.src = mejs.Utility.absolutizeUrl(url);
|
gyorgy@0
|
384 }
|
gyorgy@0
|
385 }
|
gyorgy@0
|
386 }
|
gyorgy@0
|
387
|
gyorgy@0
|
388 },
|
gyorgy@0
|
389 setCurrentTime: function (time) {
|
gyorgy@0
|
390 if (this.pluginApi != null) {
|
gyorgy@0
|
391 this.pluginApi.setCurrentTime(time);
|
gyorgy@0
|
392 this.currentTime = time;
|
gyorgy@0
|
393 }
|
gyorgy@0
|
394 },
|
gyorgy@0
|
395 setVolume: function (volume) {
|
gyorgy@0
|
396 if (this.pluginApi != null) {
|
gyorgy@0
|
397 this.pluginApi.setVolume(volume);
|
gyorgy@0
|
398 this.volume = volume;
|
gyorgy@0
|
399 }
|
gyorgy@0
|
400 },
|
gyorgy@0
|
401 setMuted: function (muted) {
|
gyorgy@0
|
402 if (this.pluginApi != null) {
|
gyorgy@0
|
403 this.pluginApi.setMuted(muted);
|
gyorgy@0
|
404 this.muted = muted;
|
gyorgy@0
|
405 }
|
gyorgy@0
|
406 },
|
gyorgy@0
|
407
|
gyorgy@0
|
408 // additional non-HTML5 methods
|
gyorgy@0
|
409 setVideoSize: function (width, height) {
|
gyorgy@0
|
410 if ( this.pluginElement.style) {
|
gyorgy@0
|
411 this.pluginElement.style.width = width + 'px';
|
gyorgy@0
|
412 this.pluginElement.style.height = height + 'px';
|
gyorgy@0
|
413 }
|
gyorgy@0
|
414 if (this.pluginApi != null) {
|
gyorgy@0
|
415 this.pluginApi.setVideoSize(width, height);
|
gyorgy@0
|
416 }
|
gyorgy@0
|
417 },
|
gyorgy@0
|
418
|
gyorgy@0
|
419 setFullscreen: function (fullscreen) {
|
gyorgy@0
|
420 if (this.pluginApi != null) {
|
gyorgy@0
|
421 this.pluginApi.setFullscreen(fullscreen);
|
gyorgy@0
|
422 }
|
gyorgy@0
|
423 },
|
gyorgy@0
|
424
|
gyorgy@0
|
425 // start: fake events
|
gyorgy@0
|
426 addEventListener: function (eventName, callback, bubble) {
|
gyorgy@0
|
427 this.events[eventName] = this.events[eventName] || [];
|
gyorgy@0
|
428 this.events[eventName].push(callback);
|
gyorgy@0
|
429 },
|
gyorgy@0
|
430 removeEventListener: function (eventName, callback) {
|
gyorgy@0
|
431 if (!eventName) { this.events = {}; return true; }
|
gyorgy@0
|
432 var callbacks = this.events[eventName];
|
gyorgy@0
|
433 if (!callbacks) return true;
|
gyorgy@0
|
434 if (!callback) { this.events[eventName] = []; return true; }
|
gyorgy@0
|
435 for (i = 0; i < callbacks.length; i++) {
|
gyorgy@0
|
436 if (callbacks[i] === callback) {
|
gyorgy@0
|
437 this.events[eventName].splice(i, 1);
|
gyorgy@0
|
438 return true;
|
gyorgy@0
|
439 }
|
gyorgy@0
|
440 }
|
gyorgy@0
|
441 return false;
|
gyorgy@0
|
442 },
|
gyorgy@0
|
443 dispatchEvent: function (eventName) {
|
gyorgy@0
|
444 var i,
|
gyorgy@0
|
445 args,
|
gyorgy@0
|
446 callbacks = this.events[eventName];
|
gyorgy@0
|
447
|
gyorgy@0
|
448 if (callbacks) {
|
gyorgy@0
|
449 args = Array.prototype.slice.call(arguments, 1);
|
gyorgy@0
|
450 for (i = 0; i < callbacks.length; i++) {
|
gyorgy@0
|
451 callbacks[i].apply(null, args);
|
gyorgy@0
|
452 }
|
gyorgy@0
|
453 }
|
gyorgy@0
|
454 }
|
gyorgy@0
|
455 // end: fake events
|
gyorgy@0
|
456 };
|
gyorgy@0
|
457
|
gyorgy@0
|
458
|
gyorgy@0
|
459 // Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
|
gyorgy@0
|
460 mejs.MediaPluginBridge = {
|
gyorgy@0
|
461
|
gyorgy@0
|
462 pluginMediaElements:{},
|
gyorgy@0
|
463 htmlMediaElements:{},
|
gyorgy@0
|
464
|
gyorgy@0
|
465 registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
|
gyorgy@0
|
466 this.pluginMediaElements[id] = pluginMediaElement;
|
gyorgy@0
|
467 this.htmlMediaElements[id] = htmlMediaElement;
|
gyorgy@0
|
468 },
|
gyorgy@0
|
469
|
gyorgy@0
|
470 // when Flash/Silverlight is ready, it calls out to this method
|
gyorgy@0
|
471 initPlugin: function (id) {
|
gyorgy@0
|
472
|
gyorgy@0
|
473 var pluginMediaElement = this.pluginMediaElements[id],
|
gyorgy@0
|
474 htmlMediaElement = this.htmlMediaElements[id];
|
gyorgy@0
|
475
|
gyorgy@0
|
476 // find the javascript bridge
|
gyorgy@0
|
477 switch (pluginMediaElement.pluginType) {
|
gyorgy@0
|
478 case "flash":
|
gyorgy@0
|
479 pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
|
gyorgy@0
|
480 break;
|
gyorgy@0
|
481 case "silverlight":
|
gyorgy@0
|
482 pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
|
gyorgy@0
|
483 pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
|
gyorgy@0
|
484 break;
|
gyorgy@0
|
485 }
|
gyorgy@0
|
486
|
gyorgy@0
|
487 if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
|
gyorgy@0
|
488 pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
|
gyorgy@0
|
489 }
|
gyorgy@0
|
490 },
|
gyorgy@0
|
491
|
gyorgy@0
|
492 // receives events from Flash/Silverlight and sends them out as HTML5 media events
|
gyorgy@0
|
493 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
gyorgy@0
|
494 fireEvent: function (id, eventName, values) {
|
gyorgy@0
|
495
|
gyorgy@0
|
496 var
|
gyorgy@0
|
497 e,
|
gyorgy@0
|
498 i,
|
gyorgy@0
|
499 bufferedTime,
|
gyorgy@0
|
500 pluginMediaElement = this.pluginMediaElements[id];
|
gyorgy@0
|
501
|
gyorgy@0
|
502 pluginMediaElement.ended = false;
|
gyorgy@0
|
503 pluginMediaElement.paused = true;
|
gyorgy@0
|
504
|
gyorgy@0
|
505 // fake event object to mimic real HTML media event.
|
gyorgy@0
|
506 e = {
|
gyorgy@0
|
507 type: eventName,
|
gyorgy@0
|
508 target: pluginMediaElement
|
gyorgy@0
|
509 };
|
gyorgy@0
|
510
|
gyorgy@0
|
511 // attach all values to element and event object
|
gyorgy@0
|
512 for (i in values) {
|
gyorgy@0
|
513 pluginMediaElement[i] = values[i];
|
gyorgy@0
|
514 e[i] = values[i];
|
gyorgy@0
|
515 }
|
gyorgy@0
|
516
|
gyorgy@0
|
517 // fake the newer W3C buffered TimeRange (loaded and total have been removed)
|
gyorgy@0
|
518 bufferedTime = values.bufferedTime || 0;
|
gyorgy@0
|
519
|
gyorgy@0
|
520 e.target.buffered = e.buffered = {
|
gyorgy@0
|
521 start: function(index) {
|
gyorgy@0
|
522 return 0;
|
gyorgy@0
|
523 },
|
gyorgy@0
|
524 end: function (index) {
|
gyorgy@0
|
525 return bufferedTime;
|
gyorgy@0
|
526 },
|
gyorgy@0
|
527 length: 1
|
gyorgy@0
|
528 };
|
gyorgy@0
|
529
|
gyorgy@0
|
530 pluginMediaElement.dispatchEvent(e.type, e);
|
gyorgy@0
|
531 }
|
gyorgy@0
|
532 };
|
gyorgy@0
|
533
|
gyorgy@0
|
534 /*
|
gyorgy@0
|
535 Default options
|
gyorgy@0
|
536 */
|
gyorgy@0
|
537 mejs.MediaElementDefaults = {
|
gyorgy@0
|
538 // allows testing on HTML5, flash, silverlight
|
gyorgy@0
|
539 // auto: attempts to detect what the browser can do
|
gyorgy@0
|
540 // native: forces HTML5 playback
|
gyorgy@0
|
541 // shim: disallows HTML5, will attempt either Flash or Silverlight
|
gyorgy@0
|
542 // none: forces fallback view
|
gyorgy@0
|
543 mode: 'auto',
|
gyorgy@0
|
544 // remove or reorder to change plugin priority and availability
|
gyorgy@0
|
545 plugins: ['flash','silverlight'],
|
gyorgy@0
|
546 // shows debug errors on screen
|
gyorgy@0
|
547 enablePluginDebug: false,
|
gyorgy@0
|
548 // overrides the type specified, useful for dynamic instantiation
|
gyorgy@0
|
549 type: '',
|
gyorgy@0
|
550 // path to Flash and Silverlight plugins
|
gyorgy@0
|
551 pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
|
gyorgy@0
|
552 // name of flash file
|
gyorgy@0
|
553 flashName: 'flashmediaelement.swf',
|
gyorgy@0
|
554 // turns on the smoothing filter in Flash
|
gyorgy@0
|
555 enablePluginSmoothing: false,
|
gyorgy@0
|
556 // name of silverlight file
|
gyorgy@0
|
557 silverlightName: 'silverlightmediaelement.xap',
|
gyorgy@0
|
558 // default if the <video width> is not specified
|
gyorgy@0
|
559 defaultVideoWidth: 480,
|
gyorgy@0
|
560 // default if the <video height> is not specified
|
gyorgy@0
|
561 defaultVideoHeight: 270,
|
gyorgy@0
|
562 // overrides <video width>
|
gyorgy@0
|
563 pluginWidth: -1,
|
gyorgy@0
|
564 // overrides <video height>
|
gyorgy@0
|
565 pluginHeight: -1,
|
gyorgy@0
|
566 // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
|
gyorgy@0
|
567 // larger number is less accurate, but less strain on plugin->JavaScript bridge
|
gyorgy@0
|
568 timerRate: 250,
|
gyorgy@0
|
569 success: function () { },
|
gyorgy@0
|
570 error: function () { }
|
gyorgy@0
|
571 };
|
gyorgy@0
|
572
|
gyorgy@0
|
573 /*
|
gyorgy@0
|
574 Determines if a browser supports the <video> or <audio> element
|
gyorgy@0
|
575 and returns either the native element or a Flash/Silverlight version that
|
gyorgy@0
|
576 mimics HTML5 MediaElement
|
gyorgy@0
|
577 */
|
gyorgy@0
|
578 mejs.MediaElement = function (el, o) {
|
gyorgy@0
|
579 return mejs.HtmlMediaElementShim.create(el,o);
|
gyorgy@0
|
580 };
|
gyorgy@0
|
581
|
gyorgy@0
|
582 mejs.HtmlMediaElementShim = {
|
gyorgy@0
|
583
|
gyorgy@0
|
584 create: function(el, o) {
|
gyorgy@0
|
585 var
|
gyorgy@0
|
586 options = mejs.MediaElementDefaults,
|
gyorgy@0
|
587 htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
|
gyorgy@0
|
588 isVideo = (htmlMediaElement.tagName.toLowerCase() == 'video'),
|
gyorgy@0
|
589 supportsMediaTag = (typeof(htmlMediaElement.canPlayType) != 'undefined'),
|
gyorgy@0
|
590 playback = {method:'', url:''},
|
gyorgy@0
|
591 poster = htmlMediaElement.getAttribute('poster'),
|
gyorgy@0
|
592 autoplay = htmlMediaElement.getAttribute('autoplay'),
|
gyorgy@0
|
593 preload = htmlMediaElement.getAttribute('preload'),
|
gyorgy@0
|
594 controls = htmlMediaElement.getAttribute('controls'),
|
gyorgy@0
|
595 prop;
|
gyorgy@0
|
596
|
gyorgy@0
|
597 // extend options
|
gyorgy@0
|
598 for (prop in o) {
|
gyorgy@0
|
599 options[prop] = o[prop];
|
gyorgy@0
|
600 }
|
gyorgy@0
|
601
|
gyorgy@0
|
602 // check for real poster
|
gyorgy@0
|
603 poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
|
gyorgy@0
|
604 preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
|
gyorgy@0
|
605 autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
|
gyorgy@0
|
606 controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');
|
gyorgy@0
|
607
|
gyorgy@0
|
608 // test for HTML5 and plugin capabilities
|
gyorgy@0
|
609 playback = this.determinePlayback(htmlMediaElement, options, isVideo, supportsMediaTag);
|
gyorgy@0
|
610
|
gyorgy@0
|
611 if (playback.method == 'native') {
|
gyorgy@0
|
612 // second fix for android
|
gyorgy@0
|
613 if (mejs.MediaFeatures.isBustedAndroid) {
|
gyorgy@0
|
614 htmlMediaElement.src = playback.url;
|
gyorgy@0
|
615 htmlMediaElement.addEventListener('click', function() {
|
gyorgy@0
|
616 htmlMediaElement.play();
|
gyorgy@0
|
617 }, true);
|
gyorgy@0
|
618 }
|
gyorgy@0
|
619
|
gyorgy@0
|
620 // add methods to native HTMLMediaElement
|
gyorgy@0
|
621 return this.updateNative( htmlMediaElement, options, autoplay, preload, playback);
|
gyorgy@0
|
622 } else if (playback.method !== '') {
|
gyorgy@0
|
623 // create plugin to mimic HTMLMediaElement
|
gyorgy@0
|
624 return this.createPlugin( htmlMediaElement, options, isVideo, playback.method, (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '', poster, autoplay, preload, controls);
|
gyorgy@0
|
625 } else {
|
gyorgy@0
|
626 // boo, no HTML5, no Flash, no Silverlight.
|
gyorgy@0
|
627 this.createErrorMessage( htmlMediaElement, options, (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '', poster );
|
gyorgy@0
|
628 }
|
gyorgy@0
|
629 },
|
gyorgy@0
|
630
|
gyorgy@0
|
631 determinePlayback: function(htmlMediaElement, options, isVideo, supportsMediaTag) {
|
gyorgy@0
|
632 var
|
gyorgy@0
|
633 mediaFiles = [],
|
gyorgy@0
|
634 i,
|
gyorgy@0
|
635 j,
|
gyorgy@0
|
636 k,
|
gyorgy@0
|
637 l,
|
gyorgy@0
|
638 n,
|
gyorgy@0
|
639 type,
|
gyorgy@0
|
640 result = { method: '', url: ''},
|
gyorgy@0
|
641 src = htmlMediaElement.getAttribute('src'),
|
gyorgy@0
|
642 pluginName,
|
gyorgy@0
|
643 pluginVersions,
|
gyorgy@0
|
644 pluginInfo;
|
gyorgy@0
|
645
|
gyorgy@0
|
646 // clean up src attr
|
gyorgy@0
|
647 if (src == 'undefined' || src == '' || src === null)
|
gyorgy@0
|
648 src = null;
|
gyorgy@0
|
649
|
gyorgy@0
|
650 // STEP 1: Get URL and type from <video src> or <source src>
|
gyorgy@0
|
651
|
gyorgy@0
|
652 // supplied type overrides all HTML
|
gyorgy@0
|
653 if (typeof (options.type) != 'undefined' && options.type !== '') {
|
gyorgy@0
|
654 mediaFiles.push({type:options.type, url:src});
|
gyorgy@0
|
655
|
gyorgy@0
|
656 // test for src attribute first
|
gyorgy@0
|
657 } else if (src !== null) {
|
gyorgy@0
|
658 type = this.checkType(src, htmlMediaElement.getAttribute('type'), isVideo);
|
gyorgy@0
|
659 mediaFiles.push({type:type, url:src});
|
gyorgy@0
|
660
|
gyorgy@0
|
661 // then test for <source> elements
|
gyorgy@0
|
662 } else {
|
gyorgy@0
|
663 // test <source> types to see if they are usable
|
gyorgy@0
|
664 for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
|
gyorgy@0
|
665 n = htmlMediaElement.childNodes[i];
|
gyorgy@0
|
666 if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
|
gyorgy@0
|
667 src = n.getAttribute('src');
|
gyorgy@0
|
668 type = this.checkType(src, n.getAttribute('type'), isVideo);
|
gyorgy@0
|
669 mediaFiles.push({type:type, url:src});
|
gyorgy@0
|
670 }
|
gyorgy@0
|
671 }
|
gyorgy@0
|
672 }
|
gyorgy@0
|
673
|
gyorgy@0
|
674 // STEP 2: Test for playback method
|
gyorgy@0
|
675
|
gyorgy@0
|
676 // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
|
gyorgy@0
|
677 if (mejs.MediaFeatures.isBustedAndroid) {
|
gyorgy@0
|
678 htmlMediaElement.canPlayType = function(type) {
|
gyorgy@0
|
679 return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
|
gyorgy@0
|
680 };
|
gyorgy@0
|
681 }
|
gyorgy@0
|
682
|
gyorgy@0
|
683
|
gyorgy@0
|
684 // test for native playback first
|
gyorgy@0
|
685 if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'native')) {
|
gyorgy@0
|
686 for (i=0; i<mediaFiles.length; i++) {
|
gyorgy@0
|
687 // normal check
|
gyorgy@0
|
688 if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
|
gyorgy@0
|
689 // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
|
gyorgy@0
|
690 || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
|
gyorgy@0
|
691 result.method = 'native';
|
gyorgy@0
|
692 result.url = mediaFiles[i].url;
|
gyorgy@0
|
693 return result;
|
gyorgy@0
|
694 }
|
gyorgy@0
|
695 }
|
gyorgy@0
|
696 }
|
gyorgy@0
|
697
|
gyorgy@0
|
698 // if native playback didn't work, then test plugins
|
gyorgy@0
|
699 if (options.mode === 'auto' || options.mode === 'shim') {
|
gyorgy@0
|
700 for (i=0; i<mediaFiles.length; i++) {
|
gyorgy@0
|
701 type = mediaFiles[i].type;
|
gyorgy@0
|
702
|
gyorgy@0
|
703 // test all plugins in order of preference [silverlight, flash]
|
gyorgy@0
|
704 for (j=0; j<options.plugins.length; j++) {
|
gyorgy@0
|
705
|
gyorgy@0
|
706 pluginName = options.plugins[j];
|
gyorgy@0
|
707
|
gyorgy@0
|
708 // test version of plugin (for future features)
|
gyorgy@0
|
709 pluginVersions = mejs.plugins[pluginName];
|
gyorgy@0
|
710 for (k=0; k<pluginVersions.length; k++) {
|
gyorgy@0
|
711 pluginInfo = pluginVersions[k];
|
gyorgy@0
|
712
|
gyorgy@0
|
713 // test if user has the correct plugin version
|
gyorgy@0
|
714 if (mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
|
gyorgy@0
|
715
|
gyorgy@0
|
716 // test for plugin playback types
|
gyorgy@0
|
717 for (l=0; l<pluginInfo.types.length; l++) {
|
gyorgy@0
|
718 // find plugin that can play the type
|
gyorgy@0
|
719 if (type == pluginInfo.types[l]) {
|
gyorgy@0
|
720 result.method = pluginName;
|
gyorgy@0
|
721 result.url = mediaFiles[i].url;
|
gyorgy@0
|
722 return result;
|
gyorgy@0
|
723 }
|
gyorgy@0
|
724 }
|
gyorgy@0
|
725 }
|
gyorgy@0
|
726 }
|
gyorgy@0
|
727 }
|
gyorgy@0
|
728 }
|
gyorgy@0
|
729 }
|
gyorgy@0
|
730
|
gyorgy@0
|
731 // what if there's nothing to play? just grab the first available
|
gyorgy@0
|
732 if (result.method === '') {
|
gyorgy@0
|
733 result.url = mediaFiles[0].url;
|
gyorgy@0
|
734 }
|
gyorgy@0
|
735
|
gyorgy@0
|
736 return result;
|
gyorgy@0
|
737 },
|
gyorgy@0
|
738
|
gyorgy@0
|
739 checkType: function(url, type, isVideo) {
|
gyorgy@0
|
740 var ext;
|
gyorgy@0
|
741
|
gyorgy@0
|
742 // if no type is supplied, fake it with the extension
|
gyorgy@0
|
743 if (url && !type) {
|
gyorgy@0
|
744 ext = url.substring(url.lastIndexOf('.') + 1);
|
gyorgy@0
|
745 return ((isVideo) ? 'video' : 'audio') + '/' + ext;
|
gyorgy@0
|
746 } else {
|
gyorgy@0
|
747 // only return the mime part of the type in case the attribute contains the codec
|
gyorgy@0
|
748 // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
|
gyorgy@0
|
749 // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
|
gyorgy@0
|
750
|
gyorgy@0
|
751 if (type && ~type.indexOf(';')) {
|
gyorgy@0
|
752 return type.substr(0, type.indexOf(';'));
|
gyorgy@0
|
753 } else {
|
gyorgy@0
|
754 return type;
|
gyorgy@0
|
755 }
|
gyorgy@0
|
756 }
|
gyorgy@0
|
757 },
|
gyorgy@0
|
758
|
gyorgy@0
|
759 createErrorMessage: function(htmlMediaElement, options, downloadUrl, poster) {
|
gyorgy@0
|
760 var errorContainer = document.createElement('div');
|
gyorgy@0
|
761 errorContainer.className = 'me-cannotplay';
|
gyorgy@0
|
762
|
gyorgy@0
|
763 try {
|
gyorgy@0
|
764 errorContainer.style.width = htmlMediaElement.width + 'px';
|
gyorgy@0
|
765 errorContainer.style.height = htmlMediaElement.height + 'px';
|
gyorgy@0
|
766 } catch (e) {}
|
gyorgy@0
|
767
|
gyorgy@0
|
768 errorContainer.innerHTML = (poster !== '') ?
|
gyorgy@0
|
769 '<a href="' + downloadUrl + '"><img src="' + poster + '" /></a>' :
|
gyorgy@0
|
770 '<a href="' + downloadUrl + '"><span>Download File</span></a>';
|
gyorgy@0
|
771
|
gyorgy@0
|
772 htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
|
gyorgy@0
|
773 htmlMediaElement.style.display = 'none';
|
gyorgy@0
|
774
|
gyorgy@0
|
775 options.error(htmlMediaElement);
|
gyorgy@0
|
776 },
|
gyorgy@0
|
777
|
gyorgy@0
|
778 createPlugin:function(htmlMediaElement, options, isVideo, pluginType, mediaUrl, poster, autoplay, preload, controls) {
|
gyorgy@0
|
779 var width = 1,
|
gyorgy@0
|
780 height = 1,
|
gyorgy@0
|
781 pluginid = 'me_' + pluginType + '_' + (mejs.meIndex++),
|
gyorgy@0
|
782 pluginMediaElement = new mejs.PluginMediaElement(pluginid, pluginType, mediaUrl),
|
gyorgy@0
|
783 container = document.createElement('div'),
|
gyorgy@0
|
784 specialIEContainer,
|
gyorgy@0
|
785 node,
|
gyorgy@0
|
786 initVars;
|
gyorgy@0
|
787
|
gyorgy@0
|
788 // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
|
gyorgy@0
|
789 node = htmlMediaElement.parentNode;
|
gyorgy@0
|
790 while (node !== null && node.tagName.toLowerCase() != 'body') {
|
gyorgy@0
|
791 if (node.parentNode.tagName.toLowerCase() == 'p') {
|
gyorgy@0
|
792 node.parentNode.parentNode.insertBefore(node, node.parentNode);
|
gyorgy@0
|
793 break;
|
gyorgy@0
|
794 }
|
gyorgy@0
|
795 node = node.parentNode;
|
gyorgy@0
|
796 }
|
gyorgy@0
|
797
|
gyorgy@0
|
798 if (isVideo) {
|
gyorgy@0
|
799 width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
|
gyorgy@0
|
800 height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
|
gyorgy@0
|
801 } else {
|
gyorgy@0
|
802 if (options.enablePluginDebug) {
|
gyorgy@0
|
803 width = 320;
|
gyorgy@0
|
804 height = 240;
|
gyorgy@0
|
805 }
|
gyorgy@0
|
806 }
|
gyorgy@0
|
807
|
gyorgy@0
|
808 // register plugin
|
gyorgy@0
|
809 pluginMediaElement.success = options.success;
|
gyorgy@0
|
810 mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
|
gyorgy@0
|
811
|
gyorgy@0
|
812 // add container (must be added to DOM before inserting HTML for IE)
|
gyorgy@0
|
813 container.className = 'me-plugin';
|
gyorgy@0
|
814 htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
|
gyorgy@0
|
815
|
gyorgy@0
|
816 // flash/silverlight vars
|
gyorgy@0
|
817 initVars = [
|
gyorgy@0
|
818 'id=' + pluginid,
|
gyorgy@0
|
819 'isvideo=' + ((isVideo) ? "true" : "false"),
|
gyorgy@0
|
820 'autoplay=' + ((autoplay) ? "true" : "false"),
|
gyorgy@0
|
821 'preload=' + preload,
|
gyorgy@0
|
822 'width=' + width,
|
gyorgy@0
|
823 'startvolume=' + options.startVolume,
|
gyorgy@0
|
824 'timerrate=' + options.timerRate,
|
gyorgy@0
|
825 'height=' + height];
|
gyorgy@0
|
826
|
gyorgy@0
|
827 if (mediaUrl !== null) {
|
gyorgy@0
|
828 if (pluginType == 'flash') {
|
gyorgy@0
|
829 initVars.push('file=' + mejs.Utility.encodeUrl(mediaUrl));
|
gyorgy@0
|
830 } else {
|
gyorgy@0
|
831 initVars.push('file=' + mediaUrl);
|
gyorgy@0
|
832 }
|
gyorgy@0
|
833 }
|
gyorgy@0
|
834 if (options.enablePluginDebug) {
|
gyorgy@0
|
835 initVars.push('debug=true');
|
gyorgy@0
|
836 }
|
gyorgy@0
|
837 if (options.enablePluginSmoothing) {
|
gyorgy@0
|
838 initVars.push('smoothing=true');
|
gyorgy@0
|
839 }
|
gyorgy@0
|
840 if (controls) {
|
gyorgy@0
|
841 initVars.push('controls=true'); // shows controls in the plugin if desired
|
gyorgy@0
|
842 }
|
gyorgy@0
|
843
|
gyorgy@0
|
844 switch (pluginType) {
|
gyorgy@0
|
845 case 'silverlight':
|
gyorgy@0
|
846 container.innerHTML =
|
gyorgy@0
|
847 '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
|
gyorgy@0
|
848 '<param name="initParams" value="' + initVars.join(',') + '" />' +
|
gyorgy@0
|
849 '<param name="windowless" value="true" />' +
|
gyorgy@0
|
850 '<param name="background" value="black" />' +
|
gyorgy@0
|
851 '<param name="minRuntimeVersion" value="3.0.0.0" />' +
|
gyorgy@0
|
852 '<param name="autoUpgrade" value="true" />' +
|
gyorgy@0
|
853 '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
|
gyorgy@0
|
854 '</object>';
|
gyorgy@0
|
855 break;
|
gyorgy@0
|
856
|
gyorgy@0
|
857 case 'flash':
|
gyorgy@0
|
858
|
gyorgy@0
|
859 if (mejs.MediaFeatures.isIE) {
|
gyorgy@0
|
860 specialIEContainer = document.createElement('div');
|
gyorgy@0
|
861 container.appendChild(specialIEContainer);
|
gyorgy@0
|
862 specialIEContainer.outerHTML =
|
gyorgy@0
|
863 '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
|
gyorgy@0
|
864 'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
|
gyorgy@0
|
865 '<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
|
gyorgy@0
|
866 '<param name="flashvars" value="' + initVars.join('&') + '" />' +
|
gyorgy@0
|
867 '<param name="quality" value="high" />' +
|
gyorgy@0
|
868 '<param name="bgcolor" value="#000000" />' +
|
gyorgy@0
|
869 '<param name="wmode" value="transparent" />' +
|
gyorgy@0
|
870 '<param name="allowScriptAccess" value="always" />' +
|
gyorgy@0
|
871 '<param name="allowFullScreen" value="true" />' +
|
gyorgy@0
|
872 '</object>';
|
gyorgy@0
|
873
|
gyorgy@0
|
874 } else {
|
gyorgy@0
|
875
|
gyorgy@0
|
876 container.innerHTML =
|
gyorgy@0
|
877 '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
|
gyorgy@0
|
878 'play="true" ' +
|
gyorgy@0
|
879 'loop="false" ' +
|
gyorgy@0
|
880 'quality="high" ' +
|
gyorgy@0
|
881 'bgcolor="#000000" ' +
|
gyorgy@0
|
882 'wmode="transparent" ' +
|
gyorgy@0
|
883 'allowScriptAccess="always" ' +
|
gyorgy@0
|
884 'allowFullScreen="true" ' +
|
gyorgy@0
|
885 'type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" ' +
|
gyorgy@0
|
886 'src="' + options.pluginPath + options.flashName + '" ' +
|
gyorgy@0
|
887 'flashvars="' + initVars.join('&') + '" ' +
|
gyorgy@0
|
888 'width="' + width + '" ' +
|
gyorgy@0
|
889 'height="' + height + '"></embed>';
|
gyorgy@0
|
890 }
|
gyorgy@0
|
891 break;
|
gyorgy@0
|
892 }
|
gyorgy@0
|
893 // hide original element
|
gyorgy@0
|
894 htmlMediaElement.style.display = 'none';
|
gyorgy@0
|
895
|
gyorgy@0
|
896 // FYI: options.success will be fired by the MediaPluginBridge
|
gyorgy@0
|
897
|
gyorgy@0
|
898 return pluginMediaElement;
|
gyorgy@0
|
899 },
|
gyorgy@0
|
900
|
gyorgy@0
|
901 updateNative: function(htmlMediaElement, options, autoplay, preload, playback) {
|
gyorgy@0
|
902 // add methods to video object to bring it into parity with Flash Object
|
gyorgy@0
|
903 for (var m in mejs.HtmlMediaElement) {
|
gyorgy@0
|
904 htmlMediaElement[m] = mejs.HtmlMediaElement[m];
|
gyorgy@0
|
905 }
|
gyorgy@0
|
906
|
gyorgy@0
|
907 /*
|
gyorgy@0
|
908 Chrome now supports preload="none"
|
gyorgy@0
|
909 if (mejs.MediaFeatures.isChrome) {
|
gyorgy@0
|
910
|
gyorgy@0
|
911 // special case to enforce preload attribute (Chrome doesn't respect this)
|
gyorgy@0
|
912 if (preload === 'none' && !autoplay) {
|
gyorgy@0
|
913
|
gyorgy@0
|
914 // forces the browser to stop loading (note: fails in IE9)
|
gyorgy@0
|
915 htmlMediaElement.src = '';
|
gyorgy@0
|
916 htmlMediaElement.load();
|
gyorgy@0
|
917 htmlMediaElement.canceledPreload = true;
|
gyorgy@0
|
918
|
gyorgy@0
|
919 htmlMediaElement.addEventListener('play',function() {
|
gyorgy@0
|
920 if (htmlMediaElement.canceledPreload) {
|
gyorgy@0
|
921 htmlMediaElement.src = playback.url;
|
gyorgy@0
|
922 htmlMediaElement.load();
|
gyorgy@0
|
923 htmlMediaElement.play();
|
gyorgy@0
|
924 htmlMediaElement.canceledPreload = false;
|
gyorgy@0
|
925 }
|
gyorgy@0
|
926 }, false);
|
gyorgy@0
|
927 // for some reason Chrome forgets how to autoplay sometimes.
|
gyorgy@0
|
928 } else if (autoplay) {
|
gyorgy@0
|
929 htmlMediaElement.load();
|
gyorgy@0
|
930 htmlMediaElement.play();
|
gyorgy@0
|
931 }
|
gyorgy@0
|
932 }
|
gyorgy@0
|
933 */
|
gyorgy@0
|
934
|
gyorgy@0
|
935 // fire success code
|
gyorgy@0
|
936 options.success(htmlMediaElement, htmlMediaElement);
|
gyorgy@0
|
937
|
gyorgy@0
|
938 return htmlMediaElement;
|
gyorgy@0
|
939 }
|
gyorgy@0
|
940 };
|
gyorgy@0
|
941
|
gyorgy@0
|
942 window.mejs = mejs;
|
gyorgy@0
|
943 window.MediaElement = mejs.MediaElement;
|