uploading works, but AV info is not automatically detected and video activation featu...
[living-lab-site.git] / js / jquery.ui.nsvideo.js
index 1a026f5..2d87c07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * jQuery UI NS-Video @VERSION
+ * jQuery UI NS-Video 1.0.0 beta
  *
  * Copyright 2011, Călin-Andrei Burloiu
  * Dual licensed under the MIT or GPL Version 2 licenses.
  *   jquery.ui.core.js
  *   jquery.ui.widget.js
  */
-
-function padWithZeros(number, length)
-{
-               if (!length)
-                       length = 2;
-               
-               var str = '';
-               
-               if (isNaN(number))
-               {
-                       for (var i=0; i<length; i++)
-                               str += '-';
-                       return str;
-               }
-               
-               str += number;
-               while (str.length < length) 
-               {
-                       str = '0' + str;
-               }
-
-               return str;
-       }
-
 (function( $, undefined ) {
 
 $.widget( "ui.nsvideo", {
-       version: "@VERSION",
+       version: "1.0.0 beta",
        options: {
                type: 'ns-html5',
-               //src: 'http://10.38.128.248/devel/data/torrents/rtt01a_600p.ogv.tstream' // TODO no default src
-               //src: 'http://10.38.128.248/devel/data/torrents/IndependentaRomaniei_240p.ogv.tstream' // TODO no default src
+               srcIndex: 0,
+               width: 0,
+               height: 0,
+               minWidth: 0,
+               maxWidth: 0,
+               showState: true,
+               refreshInterval: 0.1,   // seconds
+               autoplay: false,
+               initialDuration: "--:--"
        },
-
-       min: 0,
-
+       
        _create: function() {
-               var widget = this;
+               widget = this;
                
                widget.element
                        .addClass( "ui-widget ui-widget-content ui-corner-all" );
                
-               widget.$nsPlugin = $('<div class="ui-nsvideo-nsplugin"></div>')
+               widget.$videoContainer = $('<div class="ui-nsvideo-nsplugin"></div>')
                        .appendTo(widget.element);
                widget.$progressContainer = $('<div class="ui-nsvideo-progress-container ui-widget-content ui-corner-top"></div>')
                        .appendTo(widget.element);
@@ -63,7 +44,7 @@ $.widget( "ui.nsvideo", {
                widget.$controls = $('<div class="ui-nsvideo-controls ui-widget-content ui-corner-bottom"></div>')
                        .appendTo(widget.element);
                
-               widget.setVideo();
+               widget.video();
                
                // Time progress slider with load progress also
                widget.$loadedProgress
@@ -75,47 +56,61 @@ $.widget( "ui.nsvideo", {
                        .slider({
                                        value: 0,
                                        min: 0,
-                                       max: 1000, //Math.floor(widget.$video[0].duration),
+                                       max: 1000,
                                        slide: function(event, ui) {
-                                               widget.$video[0].currentTime = 
-                                                       ui.value / 1000 * widget.$video[0].duration;
+                                               widget.videoPlugin('crtTime', [ui.value]);
+                                               widget.videoPlugin('refreshTime');
+                                               widget.videoPlugin('refreshState');
                                        }
                        });
                
                // Play / Pause
-               $('<button class="ui-nsvideo-play ui-nsvideo-control-left">Play / Pause</button>')
+               $('<button class="ui-nsvideo-play ui-nsvideo-button ui-nsvideo-control-left">Play / Pause</button>')
                        .appendTo(widget.$controls)
                        .button({
                                text: false,
                                icons: { primary: "ui-icon-play" }
                        })
                        .click(function() {
-                               widget.togglePlay();
+                               widget.videoPlugin('togglePlay');
                        });
                
                // Time information (current and total)
-               $('<div class="ui-nsvideo-time ui-nsvideo-control-left">--:-- / --:--</div>')
+               widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">00:00 / ' + widget.options.initialDuration + '</div>')
                        .appendTo(widget.$controls);
+                       
+               // Full screen
+               $('<button class="ui-nsvideo-fullscreen ui-nsvideo-button ui-nsvideo-control-right">Full Screen</button>')
+                       .appendTo(widget.$controls)
+                       .button({
+                               text: false,
+                               icons: { primary: "ui-icon-arrow-4-diag" }
+                       })
+                       .click(function() {
+                               widget.videoPlugin('fullscreen');
+                       });
 
-               // Video definition buttonset
+               // Video format buttonset
                if (typeof widget.options.src == 'object')
                {
-                       var $definitions = $('<form><div class="ui-nsvideo-definitions ui-nsvideo-control-right"></div></form>')
+                       var $formats = $('<form><div class="ui-nsvideo-formats ui-nsvideo-control-right"></div></form>')
                                .appendTo(widget.$controls);
-                       $definitions = $('.ui-nsvideo-definitions', $definitions[0]);
+                       $formats = $('.ui-nsvideo-formats', $formats[0]);
                        $.each(widget.options.src, function(index, value) {
-                               id = widget.element.attr('id') + '-def-' + index;
-                               $('<input type="radio" id="' + id + '" name="definition" />')
-                                       .appendTo($definitions)
-                                       .attr('checked', (index == widget.options.definition))
+                               var id = widget.element.attr('id') + '-format-' + index;
+                               var definition = value.res.substring(value.res.indexOf('x')+1)+'p';
+                               $('<input type="radio" id="' + id + '" name="format" />')
+                                       .appendTo($formats)
+                                       .attr('checked', (index == widget.options.srcIndex))
                                        .click(function() {
-                                               widget.setDefinition(index);
+                                               widget.videoPlugin('pause');
+                                               widget.srcIndex(index);
                                        });
-                               $('<label for="' + id + '">' + index + '</label>')
-                                       .appendTo($definitions);
+                               $('<label for="' + id + '">' + definition + '</label>')
+                                       .appendTo($formats);
                        });
                        
-                       $definitions.buttonset();
+                       $formats.buttonset();
                }
                
                // Volume
@@ -126,22 +121,31 @@ $.widget( "ui.nsvideo", {
                                min: 0,
                                max: 100,
                                slide: function(event, ui) {
-                                       widget.unmuteHtml5();
-                                       widget.$video[0].volume = ui.value / 100;
+                                       widget.videoPlugin('volume', [ui.value]);
                                }
                        });
                
                // Toggle Mute
-               $('<button class="ui-nsvideo-mute ui-nsvideo-control-right">Mute</button>')
+               $('<button class="ui-nsvideo-mute ui-nsvideo-button ui-nsvideo-control-right">Mute</button>')
                        .appendTo(widget.$controls)
                        .button({
                                text: false,
                                icons: { primary: "ui-icon-volume-on" }
                        })
                        .click(function() {
-                               widget.toggleMute();
+                               widget.videoPlugin('toggleMute');
                        });
                        
+               // Status information
+               widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
+                       .appendTo(widget.$controls)
+                       .css('cursor', 'pointer')
+                       .click(function() {
+                               widget.videoPlugin('refreshAll');
+                       });
+               if (! widget.options.showState)
+                       widget.$stateText.hide();
+               
                // Clear fix helper
                $('<div class="ui-helper-clearfix"></div>')
                        .appendTo(widget.$controls);
@@ -152,6 +156,7 @@ $.widget( "ui.nsvideo", {
        },
 
        _setOption: function( key, value ) {
+               // TODO
                if ( key === "TODO" ) {
                        
                }
@@ -159,264 +164,918 @@ $.widget( "ui.nsvideo", {
                this._super( "_setOption", key, value );
        },
        
-       setVideo: function() {
-               widget = this;
+       _leadingZeros: function(number, length) {
+               if (!length)
+                       length = 2;
+               
+               var str = '';
+               
+               if (isNaN(number))
+               {
+                       for (var i=0; i<length; i++)
+                               str += '-';
+                       return str;
+               }
+               
+               str += number;
+               while (str.length < length) 
+               {
+                       str = '0' + str;
+               }
+
+               return str;
+       },
+       
+       video: function() {
+               var widget = this;
                
                // Select video source.
                // If src option is string, that's the source.
-               // If src is an object, properties are definitions and values are
-               // sources.
-               var src = widget.getCrtSrc();
+               // If src is an object, there is a list of associative arrays, each
+               // one having the mandatory keys "src" and "res" (resolution).
+               var src = widget.crtSrc();
                if (src == null)
                        return widget;
                
-               widget.$nsPlugin.html('');
+               widget.$videoContainer.html('');
+               
+               // Install buttons or not supported message if required
+               if (typeof $.fn.nsinstall == 'function')
+               {
+                       widget.$installContainer = $('<div class="container-install-in-widget"></div>')
+                               .appendTo(widget.$videoContainer);
+                       widget.$installContainer
+                               .nsinstall({
+                                       type: widget.options.type,
+                                       hideIfAlreadyInstalled: true
+                               });
+                       if (widget.$installContainer.nsinstall('option', 'error')
+                                       == 'already installed')
+                               widget.$installContainer.hide();
+               }
+               
+               var width = widget.options.width;
+               var height = widget.options.height;
                
+               // HTML5
                if (widget.options.type == 'ns-html5'
                        || widget.options.type == 'html5')
                {
-                       widget.$video = $('<video id="vid" src="' + src + '" width="800" height="450" preload="auto">'
+                       widget.$video = $('<video id="' + widget.element.attr('id') + '-video" src="' + src + '"' + (width == 0 ? '' : ' width="' + width + '"') + (height == 0 ? '' : ' height="' + height + '"') + ' preload="auto"' + (widget.options.autoplay ? ' autoplay="autoplay"' : '') + '>'
                                +'Error: Your browser does not support HTML5 or the video format!'
                        +'</video>')
-                               .appendTo(widget.$nsPlugin)
+                               .appendTo(widget.$videoContainer)
                                .bind({
                                        ended: function() {
-                                               widget.pauseHtml5();
+                                               widget.html5.pause();
+                                               widget.html5.refreshState();
                                        },
                                        play: function() {
-                                               widget.playHtml5();
+                                               widget.html5.play();
+                                               widget.html5.refreshState();
                                        },
                                        pause: function() {
-                                               widget.pauseHtml5();
+                                               widget.html5.pause();
+                                               widget.html5.refreshState();
                                        },
                                        timeupdate: function() {
-                                               widget.refreshTimeHtml5();
+                                               widget.html5.refreshTime();
                                        },
                                        progress: function() {
-                                               widget.refreshLoadedProgressHtml5();
+                                               widget.html5.refreshLoadedProgress();
                                        },
                                        loadedmetadata: function() {
-                                               widget.refreshTimeHtml5();
-                                               widget.refreshVolumeHtml5();
+                                               widget.html5.refreshTime();
+                                               widget.html5.refreshVolume();
+                                               widget.html5.refreshState();
+                                               widget._setWidgetWidth();
+                                               
+                                               if (widget.$video[0].error != 3
+                                                               && widget.$video[0].error != 4)
+                                                       widget.$installContainer.hide();
                                        },
                                        seeked: function() {
-                                               widget.playHtml5();
+                                               widget.html5.play();
+                                               widget.html5.refreshState();
                                        },
                                        volumechange: function() {
-                                               widget.refreshVolumeHtml5();
+                                               widget.html5.refreshVolume();
+                                       },
+                                       
+                                       loadstart: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       suspend: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       abort: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       error: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       emptied: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       stalled: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       loadeddata: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       waiting: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       seeking: function() {
+                                               widget.html5.refreshState();
                                        }
                                });
                }
+               // VLC
+               else if (widget.options.type == 'ns-vlc'
+                       || widget.options.type == 'vlc')
+               {
+                       var embedType;
+                       if (widget.options.type == 'ns-vlc')
+                               embedType = 'application/x-ns-stream';
+                       else
+                               embedType = 'application/x-vlc-plugin';
+                       
+                       if (navigator.appName == "Netscape")
+                       {
+                               widget.$video = $('<embed type="' + embedType + '" name="vlcVideo" id="' + widget.element.attr('id') + '-video" autoplay="' + (widget.options.autoplay ? 'yes' : 'no') + '" loop="no" width="' + (width == 0 ? '640' : width) + '" height="' + (height == 0 ? '480' : height) + '" target="' + src + '" />')
+                                       .appendTo(widget.$videoContainer);
+                       }
+                       else
+                       {
+                               widget.$video = $('<object classid="clsid:1800B8AF-4E33-43C0-AFC7-894433C13538" width="' + (width == 0 ? '640' : width) + '" height="' + (height == 0 ? '480' : height) + '" id="' + widget.element.attr('id') + '-video" name="vlcVideo" events="True" target="">'
+                                               + '<param name="Src" value="' + src + '" />'
+                                               + '<param name="ShowDisplay" value="True" />'
+                                               + '<param name="Loop" value="False" />'
+                                               + '<param name="AutoPlay" value="' + (widget.options.autoplay ? 'True' : 'False') + '" />'
+                                               + '<param name="Toolbar" value="False" />'
+                                       + '</object>')
+                                       .appendTo(widget.$videoContainer);
+                       }
+               }
+               
+               //  BUG: this if is because of a NS-VLC bug.
+               if (widget.options.type != 'ns-vlc')
+                       widget.$video.css('position', 'relative');
+               
+               // Adjust video size for auto-resizing within ranges minWidth and
+               // maxWidth.
+               if ( (width == 0 || height == 0)
+                       && (widget.options.minWidth != 0 && widget.options.maxWidth != 0
+                               || this.options.type.indexOf('vlc') != -1) )
+               {
+                       widget.adjustVideoSizeFromMeta();
+               }
+               
+               // Initialize video plugin
+               widget.$video.ready(function() {
+                       widget.videoPlugin('init');
+               });
+               
+               widget._setWidgetWidth();
        },
        
-       playHtml5: function() {
-               if (this.$video[0].paused)
-                       this.$video[0].play();
-               
-               $('button.ui-nsvideo-play', this.element[0])
-                       .button('option', 'icons', { primary: "ui-icon-pause" })
-                       .button('refresh');
+       adjustVideoSizeFromMeta: function() {
+               var widget = this;
                
-               return this;
+               if (typeof widget.options.src == 'object'
+                       && (typeof widget.options.src[ widget.options.srcIndex ].res)
+                               != 'undefined'
+                       && (typeof widget.options.src[ widget.options.srcIndex ].dar)
+                               != 'undefined')
+               {
+                       var resolution = widget.options.src[ widget.options.srcIndex ].res;
+                       var dar = widget.options.src[ widget.options.srcIndex ].dar;
+                       var darL = parseInt(
+                               dar.substring(0, dar.indexOf(':')));
+                       var darR = parseInt(
+                               dar.substring(dar.indexOf(':') + 1));
+                       var videoHeight = parseInt(
+                               resolution.substring(resolution.indexOf('x') + 1));
+                       var videoWidth = Math.round(videoHeight * darL / darR);
+                       
+                       // Video width must be between minWidth and maxWidth pixels.
+                       if (widget.options.minWidth != 0 && widget.options.maxWidth != 0)
+                       {
+                               if (videoWidth > widget.options.maxWidth)
+                               {
+                                       videoHeight = Math.round(widget.options.maxWidth / videoWidth
+                                               * videoHeight);
+                                       videoWidth = widget.options.maxWidth;
+                               }
+                               else if (videoWidth < widget.options.minWidth)
+                               {
+                                       videoHeight = Math.round(widget.options.minWidth / videoWidth
+                                               * videoHeight);
+                                       videoWidth = widget.options.minWidth;
+                               }
+                       }
+                       
+                       widget.$video.css('width', videoWidth);
+                       widget.$video.css('height', videoHeight);
+               }
        },
        
-       pauseHtml5: function() {
-               if (!this.$video[0].paused)
-                       this.$video[0].pause();
+       _setWidgetWidth: function() {
+        var widget = this;
+        
+               if (widget.$video.width() < 640)
+               {
+                       widget.element.css('width',
+                                                       640 + 8 + 'px');
+                       widget.$video.css('left', 
+                               Math.round(widget.$videoContainer.width()/2 
+                               - widget.$video.width()/2)
+                               + 'px');
+               }
+               else
+               {
+                       widget.element.css('width',
+                                                       widget.$video.width() + 8 + 'px');
+                       widget.$video.css('left', '0');
+               }
                
-               $('button.ui-nsvideo-play', this.element[0])
+               this._trigger('resize');
+       },
+       
+       setPlayButton: function() {
+               $('button.ui-nsvideo-play', widget.element[0])
                        .button('option', 'icons', { primary: "ui-icon-play" })
                        .button('refresh');
+       },
+       setPauseButton: function() {
+               $('button.ui-nsvideo-play', widget.element[0])
+                       .button('option', 'icons', { primary: "ui-icon-pause" })
+                       .button('refresh');
+       },
+       setMuteButton: function() {
+               $('button.ui-nsvideo-mute', widget.element[0])
+                       .button('option', 'icons', { primary: "ui-icon-volume-off" })
+                       .button('refresh');
+       },
+       setUnmuteButton: function() {
+               $('button.ui-nsvideo-mute', widget.element[0])
+                       .button('option', 'icons', { primary: "ui-icon-volume-on" })
+                       .button('refresh');
+       },
+       setTimeText: function(text) {
+               //$('.ui-nsvideo-time', widget.element[0])
+               this.$time
+                       .html(text);
+       },
+       setVolumeSlider: function(vol) {
+               $('.ui-nsvideo-volume', widget.element[0])
+                       .slider('value', vol);
+       },
+       setProgressSlider: function(prog) {
+               $('.ui-nsvideo-progress', widget.element[0])
+                       .slider('value', prog);
+       },
+       setLoadedProgressSlider: function(prog) {
+               $('.ui-nsvideo-loaded-progress', widget.element[0])
+                       .progressbar('value', prog);
+       },
+       
+       videoPlugin: function(method, args) {
+               if (typeof args == 'undefined')
+                       args = [];
+               var videoPlugin = null;
                
-               return this;
+               if (this.options.type.indexOf('html5') != -1)
+               {
+                       videoPlugin = this.html5;
+               }
+               else if (this.options.type.indexOf('vlc') != -1)
+               {
+                       videoPlugin = this.vlc;
+               }
+               
+               if (videoPlugin)
+                       return videoPlugin[method].apply(this, args);
+               
+               return null;
        },
        
-       refreshTimeHtml5: function() {
+       srcIndex: function(srcIndex) {
                var widget = this;
                
-               if (widget.$video[0].seeking)
-                       return widget;
+               if (typeof srcIndex == 'undefined')
+                       return widget.options.srcIndex;
                
-               var crtTime = widget.$video[0].currentTime;
-               var totTime = widget.$video[0].duration;
+               widget.options.srcIndex = srcIndex;
                
-               // Refresh only at 0.1 s to save CPU time.
-               var delta = crtTime - widget.lastTime;
-               if (typeof widget.lastTime != "undefined" && delta >= 0 && delta < 0.1)
-                       return widget;
-               widget.lastTime = crtTime;
-               
-               // Current time string
-               var crtH = Math.floor(crtTime / 3600);
-               var crtM = Math.floor((crtTime / 60) % 60);
-               var crtS = Math.floor(crtTime % 60);
-               var strCrtTime = 
-                       (crtH == 0 ? '' : (padWithZeros(crtH) + ':'))
-                       + padWithZeros(crtM) + ':' + padWithZeros(crtS);
-                       
-               // Total time string
-               var totH = Math.floor(totTime / 3600);
-               var totM = Math.floor((totTime / 60) % 60);
-               var totS = Math.floor(totTime % 60);
-               var strTotTime = 
-                       (totH == 0 || isNaN(totH) ? '' : (padWithZeros(totH) + ':'))
-                       + padWithZeros(totM) + ':' + padWithZeros(totS);
-               
-               $('.ui-nsvideo-time', widget.element[0])
-                       .html('' + strCrtTime + ' / ' + strTotTime);
-               
-               // Update time progress slider.
-               widget.refreshProgressHtml5();
+               // Refresh.
+               widget.video();
                
                return widget;
        },
        
-       muteHtml5: function() {
-               if (!this.$video[0].muted)
-                       this.$video[0].muted = true;
+       type: function(type) {
+               var widget = this;
                
-               $('button.ui-nsvideo-mute', this.element[0])
-                       .button('option', 'icons', { primary: "ui-icon-volume-off" })
-                       .button('refresh');
+               if (typeof type == 'undefined')
+                       return widget.options.type;
                
-               return this;
-       },
-       
-       unmuteHtml5: function() {
-               if (this.$video[0].muted)
-                       this.$video[0].muted = false;
+               widget.videoPlugin('pause');
+               if (widget.vlc.timerHandle)
+                       clearTimeout(widget.vlc.timerHandle);
                
-               $('button.ui-nsvideo-mute', this.element[0])
-                       .button('option', 'icons', { primary: "ui-icon-volume-on" })
-                       .button('refresh');
+               widget.options.type = type;
+               widget.video();
+               
+               // Initialize video plugin
+               widget.$video.ready(function() {
+                       widget.videoPlugin('init');
+               });
                
-               return this;
+               return widget;
        },
        
-       refreshVolumeHtml5: function() {
-               var vol;
+       crtSrc: function() {
+               var src;
+               var widget = this;
                
-               if (this.$video[0].muted)
-                       vol = 0;
-               else
-                       vol = Math.floor(this.$video[0].volume * 100);
+               if (typeof widget.options.src == 'string')
+                       src = widget.options.src;
+               else if (typeof widget.options.src == 'object')
+               {
+                       if (typeof widget.options.srcIndex == 'undefined')
+                               return null;
+                       
+                       if (typeof widget.options.src[ widget.options.srcIndex ].src
+                               == 'undefined')
+                               return null;
+                       
+                       src = widget.options.src[ widget.options.srcIndex ].src;
+               }
                
-               $('.ui-nsvideo-volume', this.element[0])
-                       .slider('value', vol);
+               if (widget.options.type == 'ns-html5')
+                       src = 'tribe://' + src;
                
-               return this;
+               return src;
        },
        
-       refreshProgressHtml5: function() {
-               var crtTime = this.$video[0].currentTime;
-               var totTime = this.$video[0].duration;
-               var permilia;
-               if (isNaN(totTime) || totTime == 0)
-                       permilia = 0
-               else
-                       permilia = Math.floor(crtTime / totTime * 1000);
+       html5: {
+               widget: this,
+               //lastTime: null,
                
-               $('.ui-nsvideo-progress', this.element[0])
-                       .slider('value', permilia);
+               ERR_STATES: {
+                       MEDIA_ERR_ABORTED: [1, "error: aborted"],
+                       MEDIA_ERR_NETWORK: [2, "network error"],
+                       MEDIA_ERR_DECODE: [3, "decode error"],
+                       MEDIA_ERR_SRC_NOT_SUPPORTED: [4, "error: source not supported"]
+               },
                
-               return this;
-       },
-       
-       /**
-        * Supported for Firefox 4.0 or later.
-        */
-       refreshLoadedProgressHtml5: function() {
-               // Return if buffering status not available in browser.
-               if (typeof this.$video[0].buffered == 'undefined'
-                       || this.$video[0].buffered.length === 0)
-                       return this;
-               
-               var loadedTime = this.$video[0].buffered.end(0);
-               var totTime = this.$video[0].duration;
-               var percent;
-               if (isNaN(totTime) || totTime == 0)
-                       percent = 0
-               else
-                       percent = Math.floor(loadedTime / totTime * 100);
+               NETWORK_STATES: {
+                       NETWORK_EMPTY: [0, "no data from network"],
+                       NETWORK_IDLE: [1, ""],
+                       NETWORK_LOADING: [2, "loading..."],
+                       NETWORK_LOADED: [3, "loading completed"],
+                       NETWORK_NO_SOURCE: [4, "network: no source"]
+               },
                
-               $('.ui-nsvideo-loaded-progress', this.element[0])
-                       .progressbar('value', percent);
+               READY_STATES: {
+                       HAVE_NOTHING: [0, "please wait..."],
+                       HAVE_METADATA: [1, ""],
+                       HAVE_CURRENT_DATA: [2, ""],
+                       HAVE_FUTURE_DATA: [3, ""],
+                       HAVE_ENOUGH_DATA: [4, "have enough data"]
+               },
                
-               return this;
-       },
-       
-       togglePlay: function() {
-               if (this.options.type.indexOf('html5') != -1)
-               {
-                       if (this.$video[0].paused)
+               init: function() {
+                       //widget.html5.refreshAll();
+                       
+                       widget.html5.refreshState();
+                       
+                       //if (widget.options.autoplay)
+                       //      widget.html5.play();
+               },
+               
+               togglePlay: function() {
+                       if (widget.$video[0].paused)
                        {
-                               this.playHtml5();
+                               widget.html5.play();
                        }
                        else
                        {
-                               this.pauseHtml5();
+                               widget.html5.pause();
                        }
-               }
-               else if (this.options.type == 'ns-vlc')
-               {
+               },
+
+               play: function() {
+                       if (widget.$video[0].paused)
+                               widget.$video[0].play();
                        
-               }
+                       widget.setPauseButton();
+                       
+                       return widget;
+               },
                
-               return this;
-       },
-       
-       toggleMute: function() {
-               if (this.options.type.indexOf('html5') != -1)
-               {
-                       if (!this.$video[0].muted)
+               pause: function() {
+                       if (!widget.$video[0].paused)
+                               widget.$video[0].pause();
+                       
+                       widget.setPlayButton();
+
+                       return widget;
+               },
+               
+               toggleMute: function() {
+                       if (!widget.$video[0].muted)
                        {
-                               this.muteHtml5();
+                               widget.html5.mute();
                        }
                        else
                        {
-                               this.unmuteHtml5();
+                               widget.html5.unmute();
                        }
-               }
-               else if (this.options.type == 'ns-vlc')
-               {
+               },
+                 
+               mute: function() {
+                       if (!widget.$video[0].muted)
+                               widget.$video[0].muted = true;
                        
-               }
+                       widget.setMuteButton();
+                       
+                       return widget;
+               },
                
-               return this;
-       },
-       
-       getCrtSrc: function() {
-               var src;
-               var widget = this;
+               unmute: function() {
+                       if (widget.$video[0].muted)
+                               widget.$video[0].muted = false;
+                       
+                       widget.setUnmuteButton();
+                       
+                       return widget;
+               },
                
-               if (typeof widget.options.src == 'string')
-                       src = widget.options.src;
-               else if (typeof widget.options.src == 'object')
-               {
-                       if (typeof widget.options.definition == 'undefined')
-                               return null;
+               /**
+               * Volume value is expressed in percents.
+               */
+               volume: function(vol) {
+                       if (typeof vol == 'undefined')
+                               return Math.round(widget.$video[0].volume * 100);
                        
-                       if (typeof widget.options.src[ widget.options.definition ]
-                               == 'undefined')
-                               return null;
+                       widget.html5.unmute();
+                       widget.$video[0].volume = vol / 100;
                        
-                       src = widget.options.src[ widget.options.definition ];
-               }
+                       return widget;
+               },
                
-               if (widget.options.type == 'ns-html5')
-                       src = 'tribe://' + src;
+               /**
+                * Seek position is a value between 0 and 1000.
+                */
+               crtTime: function(pos) {
+                       // getter
+                       if (typeof pos == 'undefined')
+                       {
+                               var crtTime = widget.$video[0].currentTime;
+                               var totTime = widget.$video[0].duration;
+                               if (isNaN(totTime) || totTime == 0)
+                                       return 0;
+                               else
+                                       return Math.round(crtTime / totTime * 1000.0);
+                       }
+                       
+                       // setter
+                       widget.$video[0].currentTime = 
+                               pos / 1000 * widget.$video[0].duration;
+               },
+                 
+               refreshAll: function() {
+                       widget.html5.refreshState();
+                       widget.html5.refreshVolume();
+                       widget.html5.refreshLoadedProgress();
+                       widget.html5.refreshTime();
+               },
                
-               return src;
+               refreshTime: function() {
+                       if (widget.$video[0].seeking)
+                               return widget;
+                       
+                       var crtTime = widget.$video[0].currentTime;
+                       var totTime = widget.$video[0].duration;
+                       
+                       // Refresh only at refreshInterval seconds to save CPU time.
+                       var delta = crtTime - widget.html5.lastTime;
+                       if (typeof widget.html5.lastTime !== "undefined"
+                               && delta >= 0 && delta < widget.options.refreshInterval)
+                               return widget;
+                       widget.html5.lastTime = crtTime;
+                       
+                       // Current time string
+                       var crtH = Math.floor(crtTime / 3600);
+                       var crtM = Math.floor((crtTime / 60) % 60);
+                       var crtS = Math.floor(crtTime % 60);
+                       var strCrtTime = 
+                               (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
+                               + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
+                               
+                       // Total time string
+                       var totH = Math.floor(totTime / 3600);
+                       var totM = Math.floor((totTime / 60) % 60);
+                       var totS = Math.floor(totTime % 60);
+                       var strTotTime = 
+                               (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
+                               + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
+                       
+                       widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
+                       
+                       // Update time progress slider.
+                       widget.html5.refreshProgress();
+                       
+                       return widget;
+               },
+               
+               _state: function(type, code) {
+                       var r;
+                       $.each(widget.html5[type + '_STATES'], function(index, value) {
+                               if ('' + code == '' + value[0])
+                               {
+                                       r = value;
+                                       return false;
+                               }
+                       });
+                       
+                       return r;
+               },
+               
+               refreshState: function() {
+            var widget = this;
+            
+                       var err = "";
+                       var normal = "";
+                       var network = "";
+                       var ready = "";
+                       var state = "";
+                       
+                       if (widget.$video[0].error)
+                               err = widget.html5._state('ERR',
+                                                                                 widget.$video[0].error.code)[1];
+                         
+                       if (! widget.$video[0].paused)
+                               normal = "playing...";
+                       else
+                       {
+                               normal = "paused";
+                       }
+                       if (widget.$video[0].seeking)
+                               normal = "seeking";
+                       if (widget.$video[0].ended)
+                               normal = "ended";
+                       
+                       network = widget.html5._state('NETWORK',
+                                                                       widget.$video[0].networkState)[1]; 
+                       
+                       ready = widget.html5._state('READY',
+                                                                       widget.$video[0].readyState)[1];
+                       
+                       if (err !== "")
+                               state = err;
+                       else
+                       {
+                               state = normal;
+                               
+                               if (normal !== "" && (network !== "" || ready !== "") )
+                                       state += ' / ';
+                               
+                               if (network !== "")
+                                       state += network;
+                               
+                               if (network !== "" && ready !== "")
+                                       state += ' / ';
+                               
+                               if (ready !== "")
+                                       state += ready;
+                       }
+                       
+                       widget.$stateText
+                               .html(state);
+                       
+                       return widget;
+               },
+
+               refreshVolume: function() {
+                       var vol;
+                       
+                       if (widget.$video[0].muted)
+                               vol = 0;
+                       else
+                               vol = Math.floor(widget.$video[0].volume * 100);
+                       
+                       widget.setVolumeSlider(vol);
+                       
+                       return widget;
+               },
+               
+               refreshProgress: function() {
+                       widget.setProgressSlider(widget.html5.crtTime());
+                       
+                       return widget;
+               },
+               
+               /**
+               * Supported for Firefox 4.0 or later.
+               */
+               refreshLoadedProgress: function() {
+                       // Return if buffering status not available in browser.
+                       if (typeof widget.$video[0].buffered == 'undefined'
+                               || widget.$video[0].buffered.length === 0)
+                               return widget;
+                       
+                       var loadedTime = widget.$video[0].buffered.end(0);
+                       var totTime = widget.$video[0].duration;
+                       var percent;
+                       if (isNaN(totTime) || totTime == 0)
+                               percent = 0
+                       else
+                               percent = Math.floor(loadedTime / totTime * 100);
+                       
+                       widget.setLoadedProgressSlider(percent);
+                       
+                       return widget;
+               },
+
+               fullscreen: function() {
+                       alert('Your web browser does not support switching to full screen in HTML5 mode with this button. You can switch to full screen manually by right clicking on the video and choosing "Full Screen" from the popup menu.');
+               }
        },
        
-       setDefinition: function(definition) {
-               if (this.options.type.indexOf('html5') != -1)
-               {
-                       this.options.definition = definition;
-                       this.setVideo();
-               }
+       vlc: {
+               widget: this,
+               timerHandle: null,
+               idleRefreshInterval: 1, // seconds
+               
+               STATES: {
+                       IDLE: [0, "idle"],
+                       OPENING: [1, "opening..."],
+                       BUFFERING: [2, "buffering..."],
+                       PLAYING: [3, "playing..."],
+                       PAUSED: [4, "paused"],
+                       STOPPING: [5, "stopping..."],
+                       ENDED: [6, "ended"],
+                       ERROR: [7, "error!"]
+               },
+               
+               init: function() {
+                       if (widget.options.autoplay)
+                               widget.vlc.play();
+                       widget.vlc.refreshAll();
+               },
+               
+               togglePlay: function() {
+                       if (! widget.$video[0].playlist.isPlaying)
+                       {
+                               widget.vlc.play();
+                       }
+                       else
+                       {
+                               widget.vlc.pause();
+                       }
+               },
+               
+               play: function() {
+                       if(typeof widget.$video[0].playlist.isPlaying == 'undefined')
+                               return widget;
+                       
+                       widget.$installContainer.hide();
+                       
+                       if (! widget.$video[0].playlist.isPlaying)
+                               widget.$video[0].playlist.play();
+                       
+                       widget.setPauseButton();
+                       
+                       // Schedule information refreshment at refreshInterval seconds.
+                       if (! widget.vlc.timerHandle)
+                               widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
+                                                                               widget.options.refreshInterval * 1000);
+                               
+                       widget.vlc.refreshState();
+                       
+                       return widget;
+               },
+               
+               pause: function() {
+                       if (typeof widget.$video[0].playlist === 'undefined')
+                               return widget;
+                       
+                       if (widget.$video[0].playlist.isPlaying)
+                               widget.$video[0].playlist.togglePause();
+                       
+                       widget.setPlayButton();
+                       
+                       // Cancel information refreshment scheduling.
+                       clearTimeout(widget.vlc.timerHandle);
+                       widget.vlc.timerHandle = null;
+                       
+                       widget.vlc.refreshState();
+
+                       return widget;
+               },
+               
+               toggleMute: function() {
+                       if (! widget.$video[0].audio.mute)
+                       {
+                               widget.vlc.mute();
+                       }
+                       else
+                       {
+                               widget.vlc.unmute();
+                       }
+               },
+                 
+               mute: function() {
+                       if (! widget.$video[0].audio.mute)
+                               widget.$video[0].audio.toggleMute();
+                       
+                       widget.setMuteButton();
+                       
+                       widget.vlc.refreshVolume();
+                       
+                       return widget;
+               },
+               
+               unmute: function() {
+                       if (widget.$video[0].audio.mute)
+                               widget.$video[0].audio.toggleMute();
+                       
+                       widget.setUnmuteButton();
+                       
+                       widget.vlc.refreshVolume();
+                       
+                       return widget;
+               },
+               
+               /**
+               * Volume value is expressed in percents.
+               */
+               volume: function(vol) {
+                       if (typeof vol == 'undefined')
+                               return Math.round(widget.$video[0].audio.volume);
+                       
+                       widget.vlc.unmute();
+                       widget.$video[0].audio.volume = vol;
+                       
+                       return widget;
+               },
                
-               return this;
+               /**
+                * Seek position is a value between 0 and 1000.
+                */
+               crtTime: function(pos) {
+                       // getter
+                       if (typeof pos == 'undefined')
+                       {
+                               var crtTime = widget.$video[0].input.time;
+                               var totTime = widget.$video[0].input.length;
+                               if (isNaN(totTime) || totTime == 0)
+                                       return 0;
+                               else
+                                       return Math.round(crtTime / totTime * 1000.0);
+                       }
+                       
+                       // setter
+                       widget.$video[0].input.time = 
+                               pos / 1000 * widget.$video[0].input.length;
+                               
+                       widget.vlc.refreshState();
+               },
+               
+               /**
+                * Timeout callback called at refreshInterval during playing in order
+                * to refresh information.
+                */
+               refreshHandler: function() {
+                       if (widget.$video[0].input.state
+                               == widget.vlc.STATES.PLAYING[0])
+                       {
+                               widget.vlc.refreshTime();
+                               widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
+                                                                               widget.options.refreshInterval * 1000);
+                       }
+                       else
+                       {
+                               if (widget.$video[0].input.state == widget.vlc.STATES.ENDED[0])
+                               {
+                                       widget.vlc.pause();
+                                       try {
+                                               widget.$video[0].playlist.stop();
+                                       } catch(e) {
+                                               console.log('Exception: ' + e);
+                                       }
+                               }
+                               
+                               widget.vlc.refreshTime();
+                               widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
+                                                                               widget.vlc.idleRefreshInterval * 1000);
+                       }
+                       
+                       widget.vlc.refreshState();
+               },
+               
+               refreshAll: function() {
+                       widget.vlc.refreshState();
+                       widget.vlc.refreshVolume();
+                       widget.vlc.refreshLoadedProgress();
+                       
+                       try {
+                               widget.vlc.refreshTime();
+                       } catch(e) {
+                               console.log('Exception: ' + e);
+                               widget.$time.html('00:00 / ' + widget.options.initialDuration);
+                       }
+               },
+               
+               refreshTime: function() {
+                       // TODO while seeking (maybe not necessary for VLC)
+//                     if (widget.$video[0].seeking)
+//                             return widget;
+                       
+                       // Time values in seconds.
+                       var crtTime = widget.$video[0].input.time / 1000.0;
+                       var totTime = widget.$video[0].input.length / 1000.0;
+                       //var crtTime = widget.$video[0].input.position * totTime;
+                       
+                       // Current time string
+                       var crtH = Math.floor(crtTime / 3600);
+                       var crtM = Math.floor((crtTime / 60) % 60);
+                       var crtS = Math.floor(crtTime % 60);
+                       var strCrtTime = 
+                               (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
+                               + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
+                               
+                       // Total time string
+                       var totH = Math.floor(totTime / 3600);
+                       var totM = Math.floor((totTime / 60) % 60);
+                       var totS = Math.floor(totTime % 60);
+                       var strTotTime = 
+                               (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
+                               + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
+                       
+                       widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
+                       
+                       // Update time progress slider.
+                       widget.vlc.refreshProgress();
+                       
+                       return widget;
+               },
+               
+               _state: function(code) {
+                       var r;
+                       $.each(widget.vlc.STATES, function(index, value) {
+                               if ('' + code == '' + value[0])
+                               {
+                                       r = value;
+                                       return false;
+                               }
+                       });
+                       
+                       return r;
+               },
+               
+               refreshState: function() {
+                       widget.$stateText
+                               .html(widget.vlc._state(widget.$video[0].input.state)[1]);
+                               
+                       return widget;
+               },
+
+               refreshVolume: function() {
+                       var vol;
+                       
+                       if (widget.$video[0].audio.mute)
+                               vol = 0;
+                       else
+                               vol = Math.floor(widget.$video[0].audio.volume);
+                       
+                       widget.setVolumeSlider(vol);
+                       
+                       return widget;
+               },
+               
+               refreshProgress: function() {
+                       widget.setProgressSlider(widget.vlc.crtTime());
+                       
+                       return widget;
+               },
+               
+               /**
+               * Not supported for VLC.
+               */
+               refreshLoadedProgress: function() {
+                       // TODO Currently not possible through VLC API.
+                       
+                       return widget;
+               },
+
+               fullscreen: function() {
+                       widget.$video[0].video.toggleFullscreen();
+               }
        }
 });