diff options
author | Victor Dubiniuk <victor.dubiniuk@gmail.com> | 2014-04-24 16:38:24 +0400 |
---|---|---|
committer | Victor Dubiniuk <victor.dubiniuk@gmail.com> | 2014-04-24 16:38:24 +0400 |
commit | e31c19a2a9c5c874526dafc7f27686f85e45e833 (patch) | |
tree | 124a6ab188b0ad180ee998827099349c1ddb846e /files_videoviewer | |
parent | de807fc1cb669f827435ce152434ddc0e9671635 (diff) |
Update mediaelement to 2.4.12. Fix #1766
Diffstat (limited to 'files_videoviewer')
19 files changed, 3291 insertions, 113 deletions
diff --git a/files_videoviewer/css/mediaelementplayer.css b/files_videoviewer/css/mediaelementplayer.css index 0c2ae2cfa..8ee248385 100644 --- a/files_videoviewer/css/mediaelementplayer.css +++ b/files_videoviewer/css/mediaelementplayer.css @@ -20,6 +20,11 @@ overflow: hidden; } +.mejs-fullscreen { + /* set it to not show scroll bars so 100% will work */ + overflow: hidden !important; +} + .mejs-container-fullscreen { position: fixed; left: 0; @@ -35,12 +40,17 @@ height: 100%; } +.mejs-clear { + clear: both; +} + /* Start: LAYERS */ .mejs-background { position: absolute; top: 0; left: 0; } + .mejs-mediaelement { position: absolute; top: 0; @@ -48,25 +58,35 @@ width: 100%; height: 100%; } + .mejs-poster { position: absolute; top: 0; left: 0; + background-size: contain ; + background-position: 50% 50% ; + background-repeat: no-repeat ; +} +:root .mejs-poster img { + display: none ; } + .mejs-poster img { border: 0; padding: 0; border: 0; - display: block; } + .mejs-overlay { position: absolute; top: 0; left: 0; } + .mejs-overlay-play { cursor: pointer; } + .mejs-overlay-button { position: absolute; top: 50%; @@ -76,12 +96,15 @@ margin: -50px 0 0 -50px; background: url('../img/skin/bigplay.svg') no-repeat; } + .no-svg .mejs-overlay-button { background-image: url('../img/skin/bigplay.png'); } + .mejs-overlay:hover .mejs-overlay-button { background-position: 0 -100px ; } + .mejs-overlay-loading { position: absolute; top: 50%; @@ -99,11 +122,12 @@ background: -ms-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9)); background: linear-gradient(rgba(50,50,50,0.9), rgba(0,0,0,0.9)); } + .mejs-overlay-loading span { display: block; width: 80px; height: 80px; - background: transparent url('../img/skin/loading.gif) 50% 50% no-repeat; + background: transparent url('../img/skin/loading.gif') 50% 50% no-repeat; } /* End: LAYERS */ @@ -111,7 +135,6 @@ /* Start: CONTROL BAR */ .mejs-container .mejs-controls { position: absolute; - background: none; list-style-type: none; margin: 0; padding: 0; @@ -139,7 +162,6 @@ height: 26px; font-size: 11px; line-height: 11px; - background: 0; font-family: Helvetica, Arial; border: 0; } @@ -165,12 +187,12 @@ /* :focus for accessibility */ .mejs-controls .mejs-button button:focus { - outline: solid 1px yellow; + outline: dotted 1px #999; } /* End: CONTROL BAR */ -/* Start: Time (current / duration) */ +/* Start: Time (Current / Duration) */ .mejs-container .mejs-controls .mejs-time { color: #fff; display: block; @@ -179,44 +201,43 @@ padding: 8px 3px 0 3px ; overflow: hidden; text-align: center; - padding: auto 4px; - box-sizing: content-box; -moz-box-sizing: content-box; -webkit-box-sizing: content-box; + box-sizing: content-box; } + .mejs-container .mejs-controls .mejs-time span { - font-size: 11px; color: #fff; + font-size: 11px; line-height: 12px; display: block; float: left; margin: 1px 2px 0 0; width: auto; } -/* End: Time (current / duration) */ - +/* End: Time (Current / Duration) */ -/* Start: Play/pause */ +/* Start: Play/Pause/Stop */ .mejs-controls .mejs-play button { background-position: 0 0; } + .mejs-controls .mejs-pause button { background-position: 0 -16px; } -/* End: Play/pause */ - -/* Stop */ .mejs-controls .mejs-stop button { background-position: -112px 0; } -/* End: Play/pause */ +/* Start: Play/Pause/Stop */ -/* Start: Progress bar */ +/* Start: Progress Bar */ .mejs-controls div.mejs-time-rail { + direction: ltr; width: 200px; padding-top: 5px; } + .mejs-controls .mejs-time-rail span { display: block; position: absolute; @@ -227,6 +248,7 @@ border-radius: 2px; cursor: pointer; } + .mejs-controls .mejs-time-rail .mejs-time-total { margin: 5px; background: #333; @@ -238,6 +260,7 @@ background: -ms-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8)); background: linear-gradient(rgba(30,30,30,0.8), rgba(60,60,60,0.8)); } + .mejs-controls .mejs-time-rail .mejs-time-buffering { width: 100%; background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); @@ -274,8 +297,8 @@ background: linear-gradient(rgba(44,124,145,0.8), rgba(78,183,212,0.8)); width: 0; } + .mejs-controls .mejs-time-rail .mejs-time-current { - width: 0; background: #fff; background: rgba(255,255,255,0.8); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255,255,255,0.9)), to(rgba(200,200,200,0.8))); @@ -284,6 +307,7 @@ background: -o-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8)); background: -ms-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8)); background: linear-gradient(rgba(255,255,255,0.9), rgba(200,200,200,0.8)); + width: 0; } .mejs-controls .mejs-time-rail .mejs-time-handle { @@ -321,6 +345,7 @@ text-align: center; left: 0; } + .mejs-controls .mejs-time-rail .mejs-time-float-corner { position: absolute; display: block; @@ -334,7 +359,6 @@ border-radius: 0; top: 15px; left: 13px; - } .mejs-long-video .mejs-controls .mejs-time-rail .mejs-time-float { @@ -349,21 +373,18 @@ left: 18px; } - - - - /* .mejs-controls .mejs-time-rail:hover .mejs-time-handle { visibility:visible; } */ -/* End: Progress bar */ +/* End: Progress Bar */ /* Start: Fullscreen */ .mejs-controls .mejs-fullscreen-button button { background-position: -32px 0; } + .mejs-controls .mejs-unfullscreen button { background-position: -32px -16px; } @@ -401,11 +422,13 @@ position: absolute; margin: 0; } + .mejs-controls .mejs-volume-button:hover { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } + /* .mejs-controls .mejs-volume-button:hover .mejs-volume-slider { display: block; @@ -449,9 +472,7 @@ margin: 0; } - /* horizontal version */ - .mejs-controls div.mejs-horizontal-volume-slider { height: 26px; width: 60px; @@ -467,11 +488,9 @@ margin: 0; padding: 0; font-size: 1px; - -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; - background: #333; background: rgba(50,50,50,0.8); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(30,30,30,0.8)), to(rgba(60,60,60,0.8))); @@ -480,7 +499,6 @@ background: -o-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8)); background: -ms-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8)); background: linear-gradient(rgba(30,30,30,0.8), rgba(60,60,60,0.8)); - } .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current { @@ -492,11 +510,9 @@ margin: 0; padding: 0; font-size: 1px; - -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; - background: #fff; background: rgba(255,255,255,0.8); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255,255,255,0.9)), to(rgba(200,200,200,0.8))); @@ -505,20 +521,15 @@ background: -o-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8)); background: -ms-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8)); background: linear-gradient(rgba(255,255,255,0.9), rgba(200,200,200,0.8)); - } - .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-handle { display: none; } /* End: Mute/Volume */ - - - -/* Start: TRACK (Captions and Chapters) */ +/* Start: Track (Captions and Chapters) */ .mejs-controls .mejs-captions-button { position: relative; } @@ -542,6 +553,7 @@ -moz-border-radius: 0; border-radius: 0; } + /* .mejs-controls .mejs-captions-button:hover .mejs-captions-selector { visibility: visible; @@ -555,6 +567,7 @@ list-style-type: none !important; overflow: hidden; } + .mejs-controls .mejs-captions-button .mejs-captions-selector ul li { margin: 0 0 6px 0; padding: 0; @@ -563,11 +576,13 @@ color: #fff; overflow: hidden; } + .mejs-controls .mejs-captions-button .mejs-captions-selector ul li input { clear: both; float: left; margin: 3px 3px 0 5px; } + .mejs-controls .mejs-captions-button .mejs-captions-selector ul li label { width: 100px; float: left; @@ -582,7 +597,6 @@ margin: 0 0 5px 0; } - .mejs-chapters { position: absolute; top: 0; @@ -591,6 +605,7 @@ width: 10000px; z-index: 1; } + .mejs-chapters .mejs-chapter { position: absolute; float: left; @@ -606,6 +621,7 @@ overflow: hidden; border: 0; } + .mejs-chapters .mejs-chapter .mejs-chapter-block { font-size: 11px; color: #fff; @@ -615,12 +631,12 @@ border-bottom: solid 1px #333; cursor: pointer; } + .mejs-chapters .mejs-chapter .mejs-chapter-block-last { border-right: none; } .mejs-chapters .mejs-chapter .mejs-chapter-block:hover { - /*background: #333;*/ background: #666; background: rgba(102,102,102, 0.7); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(102,102,102,0.7)), to(rgba(50,50,50,0.6))); @@ -631,6 +647,7 @@ background: linear-gradient(rgba(102,102,102,0.7), rgba(50,50,50,0.6)); filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr=#666666,endColorstr=#323232); } + .mejs-chapters .mejs-chapter .mejs-chapter-block .ch-title { font-size: 12px; font-weight: bold; @@ -640,6 +657,7 @@ margin: 0 0 3px 0; line-height: 12px; } + .mejs-chapters .mejs-chapter .mejs-chapter-block .ch-timespan { font-size: 12px; line-height: 12px; @@ -649,21 +667,21 @@ text-overflow: ellipsis; } - .mejs-captions-layer { position: absolute; bottom: 0; left: 0; text-align:center; - /*font-weight: bold;*/ line-height: 22px; font-size: 12px; color: #fff; } + .mejs-captions-layer a { color: #fff; text-decoration: underline; } + .mejs-captions-layer[lang=ar] { font-size: 20px; font-weight: normal; @@ -686,52 +704,50 @@ background: rgba(20, 20, 20, 0.8); } -/* End: TRACK (Captions and Chapters) */ - - - -.mejs-clear { - clear: both; -} +/* End: Track (Captions and Chapters) */ -/* Start: ERROR */ +/* Start: Error */ .me-cannotplay { } + .me-cannotplay a { color: #fff; font-weight: bold; } + .me-cannotplay span { padding: 15px; display: block; } -/* End: ERROR */ +/* End: Error */ /* Start: Loop */ .mejs-controls .mejs-loop-off button { background-position: -64px -16px; } + .mejs-controls .mejs-loop-on button { background-position: -64px 0; } + /* End: Loop */ /* Start: backlight */ .mejs-controls .mejs-backlight-off button { background-position: -80px -16px; } + .mejs-controls .mejs-backlight-on button { background-position: -80px 0; } /* End: backlight */ - -/* Start: picture controls */ +/* Start: Picture Controls */ .mejs-controls .mejs-picturecontrols-button { background-position: -96px 0; } -/* End: picture controls */ +/* End: Picture Controls */ /* context menu */ @@ -765,8 +781,7 @@ color: #fff; } - -/* Start: SourceChooser */ +/* Start: Source Chooser */ .mejs-controls .mejs-sourcechooser-button { position: relative; } @@ -774,6 +789,7 @@ .mejs-controls .mejs-sourcechooser-button button { background-position: -128px 0; } + .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector { visibility: hidden; position: absolute; @@ -798,6 +814,7 @@ list-style-type: none !important; overflow: hidden; } + .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li { margin: 0 0 6px 0; padding: 0; @@ -806,11 +823,13 @@ color: #fff; overflow: hidden; } + .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li input { clear: both; float: left; margin: 3px 3px 0 5px; } + .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li label { width: 100px; float: left; @@ -819,8 +838,7 @@ font-family: helvetica, arial; font-size: 10px; } -/* End: SourceChooser */ - +/* End: Source Chooser */ /* Start: Postroll */ .mejs-postroll-layer { diff --git a/files_videoviewer/js/flashmediaelement.swf b/files_videoviewer/js/flashmediaelement.swf Binary files differindex 2a5cb8da7..18daaad70 100644 --- a/files_videoviewer/js/flashmediaelement.swf +++ b/files_videoviewer/js/flashmediaelement.swf diff --git a/files_videoviewer/js/mediaelement-and-player.js b/files_videoviewer/js/mediaelement-and-player.js index 9b0d668da..7b52c33a8 100644 --- a/files_videoviewer/js/mediaelement-and-player.js +++ b/files_videoviewer/js/mediaelement-and-player.js @@ -7,7 +7,7 @@ * for browsers that don't understand HTML5 or can't play the provided codec * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3 * -* Copyright 2010-2013, John Dyer (http://j.hn) +* Copyright 2010-2014, John Dyer (http://j.hn) * License: MIT * */ @@ -15,7 +15,7 @@ var mejs = mejs || {}; // version number -mejs.version = '2.13.2'; +mejs.version = '2.14.2'; // player number (for missing, same id attr) @@ -535,7 +535,7 @@ mejs.PluginMediaElement.prototype = { // HTML5 methods play: function () { if (this.pluginApi != null) { - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { this.pluginApi.playVideo(); } else { this.pluginApi.playMedia(); @@ -545,7 +545,7 @@ mejs.PluginMediaElement.prototype = { }, load: function () { if (this.pluginApi != null) { - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { } else { this.pluginApi.loadMedia(); } @@ -555,7 +555,7 @@ mejs.PluginMediaElement.prototype = { }, pause: function () { if (this.pluginApi != null) { - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { this.pluginApi.pauseVideo(); } else { this.pluginApi.pauseMedia(); @@ -567,7 +567,7 @@ mejs.PluginMediaElement.prototype = { }, stop: function () { if (this.pluginApi != null) { - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { this.pluginApi.stopVideo(); } else { this.pluginApi.stopMedia(); @@ -637,7 +637,7 @@ mejs.PluginMediaElement.prototype = { }, setCurrentTime: function (time) { if (this.pluginApi != null) { - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { this.pluginApi.seekTo(time); } else { this.pluginApi.setCurrentTime(time); @@ -651,7 +651,7 @@ mejs.PluginMediaElement.prototype = { setVolume: function (volume) { if (this.pluginApi != null) { // same on YouTube and MEjs - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { this.pluginApi.setVolume(volume * 100); } else { this.pluginApi.setVolume(volume); @@ -661,7 +661,7 @@ mejs.PluginMediaElement.prototype = { }, setMuted: function (muted) { if (this.pluginApi != null) { - if (this.pluginType == 'youtube') { + if (this.pluginType == 'youtube' || this.pluginType == 'vimeo') { if (muted) { this.pluginApi.mute(); } else { @@ -719,7 +719,7 @@ mejs.PluginMediaElement.prototype = { var callbacks = this.events[eventName]; if (!callbacks) return true; if (!callback) { this.events[eventName] = []; return true; } - for (i = 0; i < callbacks.length; i++) { + for (var i = 0; i < callbacks.length; i++) { if (callbacks[i] === callback) { this.events[eventName].splice(i, 1); return true; @@ -1051,7 +1051,9 @@ mejs.HtmlMediaElementShim = { // normal check if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== '' // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg') - || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') { + || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '' + // special case for m4a supported by detecting mp4 support + || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/m4a/,'mp4')).replace(/no/, '') !== '') { result.method = 'native'; result.url = mediaFiles[i].url; break; @@ -1152,6 +1154,7 @@ mejs.HtmlMediaElementShim = { switch (ext) { case 'mp4': case 'm4v': + case 'm4a': return 'mp4'; case 'webm': case 'webma': @@ -1217,8 +1220,8 @@ mejs.HtmlMediaElementShim = { // check for placement inside a <p> tag (sometimes WYSIWYG editors do this) node = htmlMediaElement.parentNode; - while (node !== null && node.tagName.toLowerCase() != 'body') { - if (node.parentNode.tagName.toLowerCase() == 'p') { + while (node !== null && node.tagName.toLowerCase() !== 'body' && node.parentNode != null) { + if (node.parentNode.tagName.toLowerCase() === 'p') { node.parentNode.parentNode.insertBefore(node, node.parentNode); break; } @@ -1345,9 +1348,18 @@ mejs.HtmlMediaElementShim = { case 'youtube': - var + var videoId; + // youtu.be url from share button + if (playback.url.lastIndexOf("youtu.be") != -1) { + videoId = playback.url.substr(playback.url.lastIndexOf('/')+1); + if (videoId.indexOf('?') != -1) { + videoId = videoId.substr(0, videoId.indexOf('?')); + } + } + else { videoId = playback.url.substr(playback.url.lastIndexOf('=')+1); - youtubeSettings = { + } + youtubeSettings = { container: container, containerId: container.id, pluginMediaElement: pluginMediaElement, @@ -1367,23 +1379,57 @@ mejs.HtmlMediaElementShim = { // DEMO Code. Does NOT work. case 'vimeo': - // - + var player_id = pluginid + "_player"; pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1); - container.innerHTML ='<iframe src="http://player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?portrait=0&byline=0&title=0" width="' + width +'" height="' + height +'" frameborder="0" class="mejs-shim"></iframe>'; - - /* - container.innerHTML = - '<object width="' + width + '" height="' + height + '" class="mejs-shim">' + - '<param name="allowfullscreen" value="true" />' + - '<param name="allowscriptaccess" value="always" />' + - '<param name="flashvars" value="api=1" />' + - '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid + '&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" />' + - '<embed src="//vimeo.com/moogaloop.swf?api=1&clip_id=' + pluginMediaElement.vimeoid + '&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '" class="mejs-shim"></embed>' + - '</object>'; - */ - + container.innerHTML ='<iframe src="//player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?api=1&portrait=0&byline=0&title=0&player_id=' + player_id + '" width="' + width +'" height="' + height +'" frameborder="0" class="mejs-shim" id="' + player_id + '"></iframe>'; + if (typeof($f) == 'function') { // froogaloop available + var player = $f(container.childNodes[0]); + player.addEvent('ready', function() { + player.playVideo = function() { + player.api('play'); + }; + player.pauseVideo = function() { + player.api('pause'); + }; + player.seekTo = function(seconds) { + player.api('seekTo', seconds); + }; + function createEvent(player, pluginMediaElement, eventName, e) { + var obj = { + type: eventName, + target: pluginMediaElement + }; + if (eventName == 'timeupdate') { + pluginMediaElement.currentTime = obj.currentTime = e.seconds; + pluginMediaElement.duration = obj.duration = e.duration; + } + pluginMediaElement.dispatchEvent(obj.type, obj); + } + player.addEvent('play', function() { + createEvent(player, pluginMediaElement, 'play'); + createEvent(player, pluginMediaElement, 'playing'); + }); + player.addEvent('pause', function() { + createEvent(player, pluginMediaElement, 'pause'); + }); + + player.addEvent('finish', function() { + createEvent(player, pluginMediaElement, 'ended'); + }); + player.addEvent('playProgress', function(e) { + createEvent(player, pluginMediaElement, 'timeupdate', e); + }); + pluginMediaElement.pluginApi = player; + + // init mejs + mejs.MediaPluginBridge.initPlugin(pluginid); + + }); + } + else { + console.warn("You need to include froogaloop for vimeo to work"); + } break; } // hide original element @@ -1539,7 +1585,7 @@ mejs.YouTubeApi = { }, length: 1 }; - + } // send event up the chain @@ -2417,8 +2463,8 @@ if (typeof jQuery != 'undefined') { } catch (e) { // TODO: report control error //throw e; - // - // + + } } } @@ -2455,7 +2501,7 @@ if (typeof jQuery != 'undefined') { // create callback here since it needs access to current // MediaElement object - mejs.MediaElementPlayer.prototype.clickToPlayPauseCallback = function() { + t.clickToPlayPauseCallback = function() { // if (t.options.clickToPlayPause) { @@ -2656,6 +2702,11 @@ if (typeof jQuery != 'undefined') { parentWidth = t.container.parent().closest(':visible').width(), newHeight = t.isVideo || !t.options.autosizeProgress ? parseInt(parentWidth * nativeHeight/nativeWidth, 10) : nativeHeight; + // When we use percent, the newHeight can't be calculated so we get the container height + if(isNaN(newHeight)) { + newHeight = t.container.parent().closest(':visible').height(); + } + if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) { parentWidth = $(window).width(); newHeight = $(window).height(); @@ -2715,7 +2766,14 @@ if (typeof jQuery != 'undefined') { total = t.controls.find('.mejs-time-total'), current = t.controls.find('.mejs-time-current'), loaded = t.controls.find('.mejs-time-loaded'), - others = rail.siblings(); + others = rail.siblings(), + lastControl = others.last(), + lastControlPosition = null; + + // skip calculation if hidden + if (!t.container.is(':visible') || !rail.length || !rail.is(':visible')) { + return; + } // allow the size to come from custom CSS @@ -2739,12 +2797,22 @@ if (typeof jQuery != 'undefined') { // fit the rail into the remaining space railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width()); } - - // outer area - rail.width(railWidth); - // dark space - total.width(railWidth - (total.outerWidth(true) - total.width())); - + + // resize the rail, + // but then check if the last control (say, the fullscreen button) got pushed down + // this often happens when zoomed + do { + // outer area + rail.width(railWidth); + // dark space + total.width(railWidth - (total.outerWidth(true) - total.width())); + + if (lastControl.css('position') != 'absolute') { + lastControlPosition = lastControl.position(); + railWidth--; + } + } while (lastControlPosition != null && lastControlPosition.top > 0 && railWidth > 0); + if (t.setProgressRail) t.setProgressRail(); if (t.setCurrentRail) @@ -2823,7 +2891,7 @@ if (typeof jQuery != 'undefined') { .bind('click touchstart', function() { if (t.options.clickToPlayPause) { if (media.paused) { - t.play(); + media.play(); } } }); @@ -2924,9 +2992,7 @@ if (typeof jQuery != 'undefined') { // check if someone clicked outside a player region, then kill its focus t.globalBind('click', function(event) { - if ($(event.target).closest('.mejs-container').length == 0) { - player.hasFocus = false; - } + player.hasFocus = $(event.target).closest('.mejs-container').length != 0; }); }, @@ -3027,7 +3093,9 @@ if (typeof jQuery != 'undefined') { // Remove the player from the mejs.players object so that pauseOtherPlayers doesn't blow up when trying to pause a non existance flash api. delete mejs.players[t.id]; - t.container.remove(); + if (typeof t.container == 'object') { + t.container.remove(); + } t.globalUnbind(); delete t.node.player; } @@ -3210,9 +3278,14 @@ if (typeof jQuery != 'undefined') { timefloat = controls.find('.mejs-time-float'), timefloatcurrent = controls.find('.mejs-time-float-current'), handleMouseMove = function (e) { - // mouse position relative to the object - var x = e.pageX, - offset = total.offset(), + // mouse or touch position relative to the object + if (e.originalEvent.changedTouches) { + var x = e.originalEvent.changedTouches[0].pageX; + }else{ + var x = e.pageX; + } + + var offset = total.offset(), width = total.outerWidth(true), percentage = 0, newTime = 0, @@ -3249,15 +3322,15 @@ if (typeof jQuery != 'undefined') { // handle clicks //controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove); total - .bind('mousedown', function (e) { - // only handle left clicks - if (e.which === 1) { + .bind('mousedown touchstart', function (e) { + // only handle left clicks or touch + if (e.which === 1 || e.which === 0) { mouseIsDown = true; handleMouseMove(e); - t.globalBind('mousemove.dur', function(e) { + t.globalBind('mousemove.dur touchmove.dur', function(e) { handleMouseMove(e); }); - t.globalBind('mouseup.dur', function (e) { + t.globalBind('mouseup.dur touchend.dur', function (e) { mouseIsDown = false; timefloat.hide(); t.globalUnbind('.dur'); @@ -3454,7 +3527,7 @@ if (typeof jQuery != 'undefined') { buildvolume: function(player, controls, layers, media) { // Android and iOS don't support volume controls - if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices) + if ((mejs.MediaFeatures.isAndroid || mejs.MediaFeatures.isiOS) && this.options.hideVolumeOnTouchDevices) return; var t = this, @@ -3988,9 +4061,16 @@ if (typeof jQuery != 'undefined') { setTimeout(function checkFullscreen() { if (t.isNativeFullScreen) { + var zoomMultiplier = window["devicePixelRatio"] || 1; + // Use a percent error margin since devicePixelRatio is a float and not exact. + var percentErrorMargin = 0.002; // 0.2% + var windowWidth = zoomMultiplier * $(window).width(); + var screenWidth = screen.width; + var absDiff = Math.abs(screenWidth - windowWidth); + var marginError = screenWidth * percentErrorMargin; // check if the video is suddenly not really fullscreen - if ($(window).width() !== screen.width) { + if (absDiff > marginError) { // manually exit t.exitFullScreen(); } else { diff --git a/files_videoviewer/src/flash/FlashMediaElement.as b/files_videoviewer/src/flash/FlashMediaElement.as new file mode 100644 index 000000000..5d11d20b5 --- /dev/null +++ b/files_videoviewer/src/flash/FlashMediaElement.as @@ -0,0 +1,1087 @@ +package +{ + import flash.display.*; + import flash.events.*; + import flash.media.*; + import flash.net.*; + import flash.text.*; + import flash.system.*; + + import flash.media.Video; + import flash.net.NetConnection; + import flash.net.NetStream; + + import flash.geom.ColorTransform; + + import flash.filters.DropShadowFilter; + import flash.utils.Timer; + import flash.external.ExternalInterface; + import flash.geom.Rectangle; + + import htmlelements.IMediaElement; + import htmlelements.VideoElement; + import htmlelements.AudioElement; + import htmlelements.YouTubeElement; + + public class FlashMediaElement extends MovieClip { + + private var _mediaUrl:String; + private var _autoplay:Boolean; + private var _preload:String; + private var _debug:Boolean; + private var _isVideo:Boolean; + private var _video:DisplayObject; + private var _timerRate:Number; + private var _stageWidth:Number; + private var _stageHeight:Number; + private var _enableSmoothing:Boolean; + private var _allowedPluginDomain:String; + private var _isFullScreen:Boolean = false; + private var _startVolume:Number; + private var _controlStyle:String; + private var _autoHide:Boolean = true; + private var _streamer:String = ""; + private var _enablePseudoStreaming:Boolean; + private var _pseudoStreamingStartQueryParam:String; + + // native video size (from meta data) + private var _nativeVideoWidth:Number = 0; + private var _nativeVideoHeight:Number = 0; + + // visual elements + private var _output:TextField; + private var _fullscreenButton:SimpleButton; + + // media + private var _mediaElement:IMediaElement; + + // connection to fullscreen + private var _connection:LocalConnection; + private var _connectionName:String; + + //private var fullscreen_btn:SimpleButton; + + // CONTROLS + private var _alwaysShowControls:Boolean; + private var _controlBar:MovieClip; + private var _controlBarBg:MovieClip; + private var _scrubBar:MovieClip; + private var _scrubTrack:MovieClip; + private var _scrubOverlay:MovieClip; + private var _scrubLoaded:MovieClip; + private var _hoverTime:MovieClip; + private var _hoverTimeText:TextField; + private var _playButton:SimpleButton; + private var _pauseButton:SimpleButton; + private var _duration:TextField; + private var _currentTime:TextField; + private var _fullscreenIcon:SimpleButton; + private var _volumeMuted:SimpleButton; + private var _volumeUnMuted:SimpleButton; + private var _scrubTrackColor:String; + private var _scrubBarColor:String; + private var _scrubLoadedColor:String; + + // IDLE Timer for mouse for showing/hiding controls + private var _inactiveTime:int; + private var _timer:Timer; + private var _idleTime:int; + private var _isMouseActive:Boolean + private var _isOverStage:Boolean = false; + + // security checkes + private var securityIssue:Boolean = false; // When SWF parameters contain illegal characters + private var directAccess:Boolean = false; // When SWF visited directly with no parameters (or when security issue detected) + + + public function FlashMediaElement() { + // check for security issues (borrowed from jPLayer) + checkFlashVars(loaderInfo.parameters); + + // allows this player to be called from a different domain than the HTML page hosting the player + //Security.allowDomain("*"); + //Security.allowInsecureDomain('*'); + + + // add debug output + _output = new TextField(); + _output.textColor = 0xeeeeee; + _output.width = stage.stageWidth - 100; + _output.height = stage.stageHeight; + _output.multiline = true; + _output.wordWrap = true; + _output.border = false; + _output.filters = [new DropShadowFilter(1, 0x000000, 45, 1, 2, 2, 1)]; + + _output.text = "Initializing...\n"; + addChild(_output); + _output.visible = securityIssue; + + if (securityIssue) { + _output.text = "WARNING: Security issue detected. Player stopped."; + return; + } + + // get parameters + // Use only FlashVars, ignore QueryString + var params:Object, pos:int, query:Object; + + params = LoaderInfo(this.root.loaderInfo).parameters; + pos = root.loaderInfo.url.indexOf('?'); + if (pos !== -1) { + query = parseStr(root.loaderInfo.url.substr(pos + 1)); + + for (var key:String in params) { + if (query.hasOwnProperty(trim(key))) { + delete params[key]; + } + } + } + + _mediaUrl = (params['file'] != undefined) ? String(params['file']) : ""; + _autoplay = (params['autoplay'] != undefined) ? (String(params['autoplay']) == "true") : false; + _debug = (params['debug'] != undefined) ? (String(params['debug']) == "true") : false; + _isVideo = (params['isvideo'] != undefined) ? ((String(params['isvideo']) == "false") ? false : true ) : true; + _timerRate = (params['timerrate'] != undefined) ? (parseInt(params['timerrate'], 10)) : 250; + _alwaysShowControls = (params['controls'] != undefined) ? (String(params['controls']) == "true") : false; + _enableSmoothing = (params['smoothing'] != undefined) ? (String(params['smoothing']) == "true") : false; + _startVolume = (params['startvolume'] != undefined) ? (parseFloat(params['startvolume'])) : 0.8; + _preload = (params['preload'] != undefined) ? params['preload'] : "none"; + _controlStyle = (params['controlstyle'] != undefined) ? (String(params['controlstyle'])) : ""; // blank or "floating" + _autoHide = (params['autohide'] != undefined) ? (String(params['autohide']) == "true") : true; + _scrubTrackColor = (params['scrubtrackcolor'] != undefined) ? (String(params['scrubtrackcolor'])) : "0x333333"; + _scrubBarColor = (params['scrubbarcolor'] != undefined) ? (String(params['scrubbarcolor'])) : "0xefefef"; + _scrubLoadedColor = (params['scrubloadedcolor'] != undefined) ? (String(params['scrubloadedcolor'])) : "0x3CACC8"; + _enablePseudoStreaming = (params['pseudostreaming'] != undefined) ? (String(params['pseudostreaming']) == "true") : false; + _pseudoStreamingStartQueryParam = (params['pseudostreamstart'] != undefined) ? (String(params['pseudostreamstart'])) : "start"; + _streamer = (params['flashstreamer'] != undefined) ? (String(params['flashstreamer'])) : ""; + + // for audio them controls always show them + + if (!_isVideo && _alwaysShowControls) { + _autoHide = false; + } + + _output.visible = _debug; + + if (isNaN(_timerRate)) + _timerRate = 250; + + // setup stage and player sizes/scales + stage.align = StageAlign.TOP_LEFT; + stage.scaleMode = StageScaleMode.NO_SCALE; + _stageWidth = stage.stageWidth; + _stageHeight = stage.stageHeight; + + //_autoplay = true; + //_mediaUrl = "http://mediafiles.dts.edu/chapel/mp4/20100609.mp4"; + //_alwaysShowControls = true; + //_mediaUrl = "../media/Parades-PastLives.mp3"; + //_mediaUrl = "../media/echo-hereweare.mp4"; + + //_mediaUrl = "http://video.ted.com/talks/podcast/AlGore_2006_480.mp4"; + //_mediaUrl = "rtmp://stream2.france24.yacast.net/france24_live/en/f24_liveen"; + + //_mediaUrl = "http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0"; // hosea + //_mediaUrl = "http://www.youtube.com/watch?feature=player_embedded&v=m5VDDJlsD6I"; // railer with notes + + //_alwaysShowControls = true; + + //_debug=true; + + + + + // position and hide + _fullscreenButton = getChildByName("fullscreen_btn") as SimpleButton; + _fullscreenButton.visible = _isVideo; + _fullscreenButton.alpha = 0; + _fullscreenButton.addEventListener(MouseEvent.CLICK, fullscreenClick, false); + _fullscreenButton.x = stage.stageWidth - _fullscreenButton.width; + _fullscreenButton.y = stage.stageHeight - _fullscreenButton.height; + + + // create media element + if (_isVideo) { + + if (_mediaUrl.indexOf("youtube.com") > -1 || _mediaUrl.indexOf("youtu.be") > -1) { + + //Security.allowDomain("http://www.youtube.com"); + + _mediaElement = new YouTubeElement(this, _autoplay, _preload, _timerRate, _startVolume); + _video = (_mediaElement as YouTubeElement).player; + + // these are set and then used once the player is loaded + (_mediaElement as YouTubeElement).initWidth = _stageWidth; + (_mediaElement as YouTubeElement).initHeight = _stageHeight; + + } else { + + _mediaElement = new VideoElement(this, _autoplay, _preload, _timerRate, _startVolume, _streamer); + _video = (_mediaElement as VideoElement).video; + _video.width = _stageWidth; + _video.height = _stageHeight; + (_video as Video).smoothing = _enableSmoothing; + (_mediaElement as VideoElement).setReference(this); + (_mediaElement as VideoElement).setPseudoStreaming(_enablePseudoStreaming); + (_mediaElement as VideoElement).setPseudoStreamingStartParam(_pseudoStreamingStartQueryParam); + //_video.scaleMode = VideoScaleMode.MAINTAIN_ASPECT_RATIO; + addChild(_video); + } + } else { + + //var player2:AudioDecoder = new com.automatastudios.audio.audiodecoder.AudioDecoder(); + _mediaElement = new AudioElement(this, _autoplay, _preload, _timerRate, _startVolume); + } + + + // controls! + _controlBar = getChildByName("controls_mc") as MovieClip; + _controlBarBg = _controlBar.getChildByName("controls_bg_mc") as MovieClip; + _scrubTrack = _controlBar.getChildByName("scrubTrack") as MovieClip; + _scrubBar = _controlBar.getChildByName("scrubBar") as MovieClip; + _scrubOverlay = _controlBar.getChildByName("scrubOverlay") as MovieClip; + _scrubLoaded = _controlBar.getChildByName("scrubLoaded") as MovieClip; + + _scrubOverlay.buttonMode = true; + _scrubOverlay.useHandCursor = true + + applyColor(_scrubTrack, _scrubTrackColor); + applyColor(_scrubBar, _scrubBarColor); + applyColor(_scrubLoaded, _scrubLoadedColor); + + _fullscreenIcon = _controlBar.getChildByName("fullscreenIcon") as SimpleButton; + _fullscreenIcon.visible = _isVideo; + + // New fullscreenIcon for new fullscreen floating controls + //if(_alwaysShowControls && _controlStyle.toUpperCase()=="FLOATING") { + _fullscreenIcon.addEventListener(MouseEvent.CLICK, fullScreenIconClick, false); + //} + + _volumeMuted = _controlBar.getChildByName("muted_mc") as SimpleButton; + _volumeUnMuted = _controlBar.getChildByName("unmuted_mc") as SimpleButton; + + _volumeMuted.addEventListener(MouseEvent.CLICK, toggleVolume, false); + _volumeUnMuted.addEventListener(MouseEvent.CLICK, toggleVolume, false); + + _playButton = _controlBar.getChildByName("play_btn") as SimpleButton; + _playButton.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) { + _mediaElement.play(); + }); + _pauseButton = _controlBar.getChildByName("pause_btn") as SimpleButton; + _pauseButton.addEventListener(MouseEvent.CLICK, function(e:MouseEvent) { + _mediaElement.pause(); + }); + _pauseButton.visible = false; + _duration = _controlBar.getChildByName("duration_txt") as TextField; + _currentTime = _controlBar.getChildByName("currentTime_txt") as TextField; + _hoverTime = _controlBar.getChildByName("hoverTime") as MovieClip; + _hoverTimeText = _hoverTime.getChildByName("hoverTime_txt") as TextField; + _hoverTime.visible=false; + _hoverTime.y=(_hoverTime.height/2)+1; + _hoverTime.x=0; + + + + // Add new timeline scrubber events + _scrubOverlay.addEventListener(MouseEvent.MOUSE_MOVE, scrubMove); + _scrubOverlay.addEventListener(MouseEvent.CLICK, scrubClick); + _scrubOverlay.addEventListener(MouseEvent.MOUSE_OVER, scrubOver); + _scrubOverlay.addEventListener(MouseEvent.MOUSE_OUT, scrubOut); + + if (_autoHide) { // && _alwaysShowControls) { + // Add mouse activity for show/hide of controls + stage.addEventListener(Event.MOUSE_LEAVE, mouseActivityLeave); + stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseActivityMove); + _inactiveTime = 2500; + _timer = new Timer(_inactiveTime) + _timer.addEventListener(TimerEvent.TIMER, idleTimer); + _timer.start(); + // set + } + + if(_startVolume<=0) { + trace("INITIAL VOLUME: "+_startVolume+" MUTED"); + _volumeMuted.visible=true; + _volumeUnMuted.visible=false; + } else { + trace("INITIAL VOLUME: "+_startVolume+" UNMUTED"); + _volumeMuted.visible=false; + _volumeUnMuted.visible=true; + } + + _controlBar.visible = _alwaysShowControls; + + setControlDepth(); + + _output.appendText("stage: " + stage.stageWidth + "x" + stage.stageHeight + "\n"); + _output.appendText("file: " + _mediaUrl + "\n"); + _output.appendText("autoplay: " + _autoplay.toString() + "\n"); + _output.appendText("preload: " + _preload.toString() + "\n"); + _output.appendText("isvideo: " + _isVideo.toString() + "\n"); + _output.appendText("smoothing: " + _enableSmoothing.toString() + "\n"); + _output.appendText("timerrate: " + _timerRate.toString() + "\n"); + _output.appendText("displayState: " +(stage.hasOwnProperty("displayState")).toString() + "\n"); + + // attach javascript + _output.appendText("ExternalInterface.available: " + ExternalInterface.available.toString() + "\n"); + _output.appendText("ExternalInterface.objectID: " + ((ExternalInterface.objectID != null)? ExternalInterface.objectID.toString() : "null") + "\n"); + + if (_mediaUrl != "") { + _mediaElement.setSrc(_mediaUrl); + } + + positionControls(); + + // Fire this once just to set the width on some dynamically sized scrub bar items; + _scrubBar.scaleX=0; + _scrubLoaded.scaleX=0; + + + if (ExternalInterface.available) { // && !_alwaysShowControls + + _output.appendText("Adding callbacks...\n"); + try { + if (ExternalInterface.objectID != null && ExternalInterface.objectID.toString() != "") { + + // add HTML media methods + ExternalInterface.addCallback("playMedia", playMedia); + ExternalInterface.addCallback("loadMedia", loadMedia); + ExternalInterface.addCallback("pauseMedia", pauseMedia); + ExternalInterface.addCallback("stopMedia", stopMedia); + + ExternalInterface.addCallback("setSrc", setSrc); + ExternalInterface.addCallback("setCurrentTime", setCurrentTime); + ExternalInterface.addCallback("setVolume", setVolume); + ExternalInterface.addCallback("setMuted", setMuted); + + ExternalInterface.addCallback("setFullscreen", setFullscreen); + ExternalInterface.addCallback("setVideoSize", setVideoSize); + + ExternalInterface.addCallback("positionFullscreenButton", positionFullscreenButton); + ExternalInterface.addCallback("hideFullscreenButton", hideFullscreenButton); + + // fire init method + ExternalInterface.call("mejs.MediaPluginBridge.initPlugin", ExternalInterface.objectID); + } + + _output.appendText("Success...\n"); + + } catch (error:SecurityError) { + _output.appendText("A SecurityError occurred: " + error.message + "\n"); + } catch (error:Error) { + _output.appendText("An Error occurred: " + error.message + "\n"); + } + + } + + if (_preload != "none") { + _mediaElement.load(); + + if (_autoplay) { + _mediaElement.play(); + } + } else if (_autoplay) { + _mediaElement.load(); + _mediaElement.play(); + } + + // listen for resize + stage.addEventListener(Event.RESIZE, resizeHandler); + + // send click events up to javascript + stage.addEventListener(MouseEvent.CLICK, stageClicked); + + // resize + stage.addEventListener(FullScreenEvent.FULL_SCREEN, stageFullScreenChanged); + } + + public function setControlDepth():void { + // put these on top + addChild(_output); + addChild(_controlBar); + addChild(_fullscreenButton); + + } + + // borrowed from jPLayer + // https://github.com/happyworm/jPlayer/blob/e8ca190f7f972a6a421cb95f09e138720e40ed6d/actionscript/Jplayer.as#L228 + private function checkFlashVars(p:Object):void { + var i:Number = 0; + for (var s:String in p) { + if (isIllegalChar(p[s], s === 'file')) { + securityIssue = true; // Illegal char found + } + i++; + } + if(i === 0 || securityIssue) { + directAccess = true; + } + } + + private static function parseStr (str:String) : Object { + var hash:Object = {}, + arr1:Array, arr2:Array; + + str = unescape(str).replace(/\+/g, " "); + + arr1 = str.split('&'); + if (!arr1.length) { + return {}; + } + + for (var i:uint = 0, length:uint = arr1.length; i < length; i++) { + arr2 = arr1[i].split('='); + if (!arr2.length) { + continue; + } + hash[trim(arr2[0])] = trim(arr2[1]); + } + return hash; + } + + + private static function trim(str:String) : String { + if (!str) { + return str; + } + + return str.toString().replace(/^\s*/, '').replace(/\s*$/, ''); + } + + private function isIllegalChar(s:String, isUrl:Boolean):Boolean { + var illegals:String = "' \" ( ) { } * + \\ < >"; + if(isUrl) { + illegals = "\" { } \\ < >"; + } + if(Boolean(s)) { // Otherwise exception if parameter null. + for each (var illegal:String in illegals.split(' ')) { + if(s.indexOf(illegal) >= 0) { + return true; // Illegal char found + } + } + } + return false; + } + + + // START: Controls and events + function mouseActivityMove(event:MouseEvent):void { + + // if mouse is in the video area + if (_autoHide && (mouseX>=0 && mouseX<=stage.stageWidth) && (mouseY>=0 && mouseY<=stage.stageHeight)) { + + // This could be move to a nice fade at some point... + _controlBar.visible = (_alwaysShowControls || _isFullScreen); + _isMouseActive = true; + _idleTime = 0; + _timer.reset(); + _timer.start() + } + } + + function mouseActivityLeave(event:Event):void { + if (_autoHide) { + _isOverStage = false; + // This could be move to a nice fade at some point... + _controlBar.visible = false; + _isMouseActive = false; + _idleTime = 0; + _timer.reset(); + _timer.stop(); + } + } + + function idleTimer(event:TimerEvent):void { + + if (_autoHide) { + // This could be move to a nice fade at some point... + _controlBar.visible = false; + _isMouseActive = false; + _idleTime += _inactiveTime; + _idleTime = 0; + _timer.reset(); + _timer.stop(); + } + } + + + function scrubMove(event:MouseEvent):void { + + //if (_alwaysShowControls) { + if (_hoverTime.visible) { + var seekBarPosition:Number = ((event.localX / _scrubTrack.width) *_mediaElement.duration())*_scrubTrack.scaleX; + var hoverPos:Number = (seekBarPosition / _mediaElement.duration()) *_scrubTrack.scaleX; + + if (_isFullScreen) { + _hoverTime.x=event.target.parent.mouseX; + } else { + _hoverTime.x=mouseX; + } + _hoverTime.y = _scrubBar.y - (_hoverTime.height/2); + _hoverTimeText.text = secondsToTimeCode(seekBarPosition); + } + //} + //trace(event); + } + + function scrubOver(event:MouseEvent):void { + _hoverTime.y = _scrubBar.y-(_hoverTime.height/2)+1; + _hoverTime.visible = true; + trace(event); + } + + function scrubOut(event:MouseEvent):void { + _hoverTime.y = _scrubBar.y+(_hoverTime.height/2)+1; + _hoverTime.visible = false; + //_hoverTime.x=0; + //trace(event); + } + + function scrubClick(event:MouseEvent):void { + //trace(event); + var seekBarPosition:Number = ((event.localX / _scrubTrack.width) *_mediaElement.duration())*_scrubTrack.scaleX; + + var tmp:Number = (_mediaElement.currentTime()/_mediaElement.duration())*_scrubTrack.width; + var canSeekToPosition:Boolean = _scrubLoaded.scaleX > (seekBarPosition / _mediaElement.duration()) *_scrubTrack.scaleX; + //var canSeekToPosition:Boolean = true; + + /* + amountLoaded = ns.bytesLoaded / ns.bytesTotal; + loader.loadbar._width = amountLoaded * 208.9; + loader.scrub._x = ns.time / duration * 208.9; + */ + + trace("seekBarPosition:"+seekBarPosition, "CanSeekToPosition: "+canSeekToPosition); + + if (seekBarPosition>0 && seekBarPosition<_mediaElement.duration() && canSeekToPosition) { + _mediaElement.setCurrentTime(seekBarPosition); + } + } + + function toggleVolume(event:MouseEvent):void { + trace(event.currentTarget.name); + switch(event.currentTarget.name) { + case "muted_mc": + setMuted(false); + break; + case "unmuted_mc": + setMuted(true); + break; + } + } + + function toggleVolumeIcons(volume:Number) { + if(volume<=0) { + _volumeMuted.visible = true; + _volumeUnMuted.visible = false; + } else { + _volumeMuted.visible = false; + _volumeUnMuted.visible = true; + } + } + + public function positionControls(forced:Boolean=false) { + + + if ( _controlStyle.toUpperCase() == "FLOATING" && _isFullScreen) { + + trace("CONTROLS: floating"); + _hoverTime.y=(_hoverTime.height/2)+1; + _hoverTime.x=0; + _controlBarBg.width = 300; + _controlBarBg.height = 93; + //_controlBarBg.x = (stage.stageWidth/2) - (_controlBarBg.width/2); + //_controlBarBg.y = stage.stageHeight - 300; + + _pauseButton.scaleX = _playButton.scaleX=3.5; + _pauseButton.scaleY= _playButton.scaleY=3.5; + // center the play button and make it big and at the top + _pauseButton.x = _playButton.x = (_controlBarBg.width/2)-(_playButton.width/2)+7; + _pauseButton.y = _playButton.y = _controlBarBg.height-_playButton.height-(14) + + _controlBar.x = (stage.stageWidth/2) -150; + _controlBar.y = stage.stageHeight - _controlBar.height-100; + + + // reposition the time and duration items + + _duration.x = _controlBarBg.width - _duration.width - 10; + _duration.y = _controlBarBg.height - _duration.height -7; + //_currentTime.x = _controlBarBg.width - _duration.width - 10 - _currentTime.width - 10; + _currentTime.x = 5 + _currentTime.y= _controlBarBg.height - _currentTime.height-7; + + _fullscreenIcon.x = _controlBarBg.width - _fullscreenIcon.width - 7; + _fullscreenIcon.y = 7; + + _volumeMuted.x = _volumeUnMuted.x = 7; + _volumeMuted.y = _volumeUnMuted.y = 7; + + _scrubLoaded.x = _scrubBar.x = _scrubOverlay.x = _scrubTrack.x =_currentTime.x+_currentTime.width+7; + _scrubLoaded.y = _scrubBar.y = _scrubOverlay.y = _scrubTrack.y=_controlBarBg.height-_scrubTrack.height-10; + + _scrubBar.width = _scrubOverlay.width = _scrubTrack.width = (_duration.x-_duration.width-14); + + + } else { + trace("CONTROLS: normal, original"); + + /* + // Original style bottom display + _hoverTime.y=(_hoverTime.height/2)+1; + _hoverTime.x=0; + _controlBarBg.width = stage.stageWidth; + _controlBar.y = stage.stageHeight - _controlBar.height; + _duration.x = stage.stageWidth - _duration.width - 10; + //_currentTime.x = stage.stageWidth - _duration.width - 10 - _currentTime.width - 10; + _currentTime.x = _playButton.x+_playButton.width; + _scrubTrack.width = (_duration.x-_duration.width-10)-_duration.width+10; + _scrubOverlay.width = _scrubTrack.width; + _scrubBar.width = _scrubTrack.width; + */ + + // FLOATING MODE BOTTOM DISPLAY - similar to normal + trace("THAT WAY!"); + _hoverTime.y=(_hoverTime.height/2)+1; + _hoverTime.x=0; + _controlBarBg.width = stage.stageWidth; + _controlBarBg.height = 30; + _controlBarBg.y=0; + _controlBarBg.x=0; + // _controlBarBg.x = 0; + // _controlBarBg.y = stage.stageHeight - _controlBar.height; + + _pauseButton.scaleX = _playButton.scaleX=1; + _pauseButton.scaleY = _playButton.scaleY=1; + + _pauseButton.x = _playButton.x = 7; + _pauseButton.y = _playButton.y = _controlBarBg.height-_playButton.height-2; + + + //_currentTime.x = stage.stageWidth - _duration.width - 10 - _currentTime.width - 10; + _currentTime.x = _playButton.x+_playButton.width; + + _fullscreenIcon.x = _controlBarBg.width - _fullscreenIcon.width - 7; + _fullscreenIcon.y = 8; + + _volumeMuted.x = _volumeUnMuted.x = (_isVideo ? _fullscreenIcon.x : _controlBarBg.width) - _volumeMuted.width - 10; + _volumeMuted.y = _volumeUnMuted.y = 10; + + _duration.x = _volumeMuted.x - _volumeMuted.width - _duration.width + 5; + _duration.y = _currentTime.y = _controlBarBg.height - _currentTime.height - 7; + + _scrubLoaded.x = _scrubBar.x = _scrubOverlay.x = _scrubTrack.x = _currentTime.x + _currentTime.width + 10; + _scrubLoaded.y = _scrubBar.y = _scrubOverlay.y = _scrubTrack.y = _controlBarBg.height - _scrubTrack.height - 9; + + _scrubBar.width = _scrubOverlay.width = _scrubTrack.width = (_duration.x-_duration.width-10)-_duration.width+5; + _controlBar.x = 0; + _controlBar.y = stage.stageHeight - _controlBar.height; + + } + + } + + // END: Controls + + + function stageClicked(e:MouseEvent):void { + //_output.appendText("click: " + e.stageX.toString() +","+e.stageY.toString() + "\n"); + if (e.target == stage) { + sendEvent("click", ""); + } + } + + function resizeHandler(e:Event):void { + //_video.scaleX = stage.stageWidth / _stageWidth; + //_video.scaleY = stage.stageHeight / _stageHeight; + //positionControls(); + + repositionVideo(); + } + + // START: Fullscreen + function enterFullscreen() { + + _output.appendText("enterFullscreen()\n"); + + var screenRectangle:Rectangle = new Rectangle(0, 0, flash.system.Capabilities.screenResolutionX, flash.system.Capabilities.screenResolutionY); + stage.fullScreenSourceRect = screenRectangle; + + stage.displayState = StageDisplayState.FULL_SCREEN; + + repositionVideo(); + positionControls(); + updateControls(HtmlMediaEvent.FULLSCREENCHANGE); + + _controlBar.visible = true; + + _isFullScreen = true; + } + + function exitFullscreen() { + + stage.displayState = StageDisplayState.NORMAL; + + + _controlBar.visible = false; + + _isFullScreen = false; + } + + function setFullscreen(gofullscreen:Boolean) { + + _output.appendText("setFullscreen: " + gofullscreen.toString() + "\n"); + + try { + //_fullscreenButton.visible = false; + + if (gofullscreen) { + enterFullscreen(); + + } else { + exitFullscreen(); + } + + } catch (error:Error) { + + // show the button when the security error doesn't let it work + //_fullscreenButton.visible = true; + _fullscreenButton.alpha = 1; + + _isFullScreen = false; + + _output.appendText("error setting fullscreen: " + error.message.toString() + "\n"); + } + } + + // control bar button/icon + function fullScreenIconClick(e:MouseEvent) { + try { + _controlBar.visible = true; + setFullscreen(!_isFullScreen); + repositionVideo(); + } catch (error:Error) { + } + } + + // special floating fullscreen icon + function fullscreenClick(e:MouseEvent) { + //_fullscreenButton.visible = false; + _fullscreenButton.alpha = 0 + + try { + _controlBar.visible = true; + setFullscreen(true); + repositionVideo(); + positionControls(); + } catch (error:Error) { + } + } + + + function stageFullScreenChanged(e:FullScreenEvent) { + _output.appendText("fullscreen event: " + e.fullScreen.toString() + "\n"); + + //_fullscreenButton.visible = false; + _fullscreenButton.alpha = 0; + _isFullScreen = e.fullScreen; + + sendEvent(HtmlMediaEvent.FULLSCREENCHANGE, "isFullScreen:" + e.fullScreen ); + + if (!e.fullScreen) { + _controlBar.visible = _alwaysShowControls; + } + } + // END: Fullscreen + + // START: external interface + function playMedia() { + _output.appendText("play\n"); + _mediaElement.play(); + } + + function loadMedia() { + _output.appendText("load\n"); + _mediaElement.load(); + } + + function pauseMedia() { + _output.appendText("pause\n"); + _mediaElement.pause(); + } + + function setSrc(url:String) { + _output.appendText("setSrc: " + url + "\n"); + _mediaElement.setSrc(url); + } + + function stopMedia() { + _output.appendText("stop\n"); + _mediaElement.stop(); + } + + function setCurrentTime(time:Number) { + _output.appendText("seek: " + time.toString() + "\n"); + _mediaElement.setCurrentTime(time); + } + + function setVolume(volume:Number) { + _output.appendText("volume: " + volume.toString() + "\n"); + _mediaElement.setVolume(volume); + toggleVolumeIcons(volume); + } + + function setMuted(muted:Boolean) { + _output.appendText("muted: " + muted.toString() + "\n"); + _mediaElement.setMuted(muted); + toggleVolumeIcons(_mediaElement.getVolume()); + } + + function setVideoSize(width:Number, height:Number) { + _output.appendText("setVideoSize: " + width.toString() + "," + height.toString() + "\n"); + + _stageWidth = width; + _stageHeight = height; + + if (_video != null) { + repositionVideo(); + positionControls(); + //_fullscreenButton.x = stage.stageWidth - _fullscreenButton.width - 10; + _output.appendText("result: " + _video.width.toString() + "," + _video.height.toString() + "\n"); + } + + + } + + function positionFullscreenButton(x:Number, y:Number, visibleAndAbove:Boolean ) { + + _output.appendText("position FS: " + x.toString() + "x" + y.toString() + "\n"); + + // bottom corner + /* + _fullscreenButton.x = stage.stageWidth - _fullscreenButton.width + _fullscreenButton.y = stage.stageHeight - _fullscreenButton.height; + */ + + // position just above + if (visibleAndAbove) { + _fullscreenButton.x = x+1; + _fullscreenButton.y = y - _fullscreenButton.height+1; + } else { + _fullscreenButton.x = x; + _fullscreenButton.y = y; + } + + // check for oversizing + if ((_fullscreenButton.x + _fullscreenButton.width) > stage.stageWidth) + _fullscreenButton.x = stage.stageWidth - _fullscreenButton.width; + + // show it! + if (visibleAndAbove) { + _fullscreenButton.alpha = 1; + } + } + + function hideFullscreenButton() { + + //_fullscreenButton.visible = false; + _fullscreenButton.alpha = 0; + } + + // END: external interface + + + function repositionVideo():void { + + if (stage.displayState == "fullScreen") { + fullscreen = true; + } else { + fullscreen = false; + } + + _output.appendText("positioning video "+stage.displayState+"\n"); + + if (_mediaElement is VideoElement) { + + if (isNaN(_nativeVideoWidth) || isNaN(_nativeVideoHeight) || _nativeVideoWidth <= 0 || _nativeVideoHeight <= 0) { + _output.appendText("ERR: I dont' have the native dimension\n"); + return; + } + + // calculate ratios + var stageRatio, nativeRatio; + + _video.x = 0; + _video.y = 0; + + if(fullscreen == true) { + stageRatio = flash.system.Capabilities.screenResolutionX/flash.system.Capabilities.screenResolutionY; + nativeRatio = _nativeVideoWidth/_nativeVideoHeight; + + // adjust size and position + if (nativeRatio > stageRatio) { + _mediaElement.setSize(flash.system.Capabilities.screenResolutionX, _nativeVideoHeight * flash.system.Capabilities.screenResolutionX / _nativeVideoWidth); + _video.y = flash.system.Capabilities.screenResolutionY/2 - _video.height/2; + } else if (stageRatio > nativeRatio) { + _mediaElement.setSize(_nativeVideoWidth * flash.system.Capabilities.screenResolutionY / _nativeVideoHeight, flash.system.Capabilities.screenResolutionY); + _video.x = flash.system.Capabilities.screenResolutionX/2 - _video.width/2; + } else if (stageRatio == nativeRatio) { + _mediaElement.setSize(flash.system.Capabilities.screenResolutionX, flash.system.Capabilities.screenResolutionY); + } + + } else { + stageRatio = _stageWidth/_stageHeight; + nativeRatio = _nativeVideoWidth/_nativeVideoHeight; + + // adjust size and position + if (nativeRatio > stageRatio) { + _mediaElement.setSize(_stageWidth, _nativeVideoHeight * _stageWidth / _nativeVideoWidth); + _video.y = _stageHeight/2 - _video.height/2; + } else if (stageRatio > nativeRatio) { + _mediaElement.setSize( _nativeVideoWidth * _stageHeight / _nativeVideoHeight, _stageHeight); + _video.x = _stageWidth/2 - _video.width/2; + } else if (stageRatio == nativeRatio) { + _mediaElement.setSize(_stageWidth, _stageHeight); + } + + } + + } else if (_mediaElement is YouTubeElement) { + if(fullscreen == true) { + _mediaElement.setSize(flash.system.Capabilities.screenResolutionX, flash.system.Capabilities.screenResolutionY); + + } else { + _mediaElement.setSize(_stageWidth, _stageHeight); + + } + + } + + positionControls(); + } + + // SEND events to JavaScript + public function sendEvent(eventName:String, eventValues:String) { + + // special video event + if (eventName == HtmlMediaEvent.LOADEDMETADATA && _isVideo) { + + _output.appendText("METADATA RECEIVED: "); + + try { + if (_mediaElement is VideoElement) { + _nativeVideoWidth = (_mediaElement as VideoElement).videoWidth; + _nativeVideoHeight = (_mediaElement as VideoElement).videoHeight; + } + } catch (e:Error) { + _output.appendText(e.toString() + "\n"); + } + + _output.appendText(_nativeVideoWidth.toString() + "x" + _nativeVideoHeight.toString() + "\n"); + + + if(stage.displayState == "fullScreen" ) { + setVideoSize(_nativeVideoWidth, _nativeVideoHeight); + } + repositionVideo(); + + } + + updateControls(eventName); + + //trace((_mediaElement.duration()*1).toString() + " / " + (_mediaElement.currentTime()*1).toString()); + //trace("CurrentProgress:"+_mediaElement.currentProgress()); + + if (ExternalInterface.objectID != null && ExternalInterface.objectID.toString() != "") { + + //_output.appendText("event:" + eventName + " : " + eventValues); + //trace("event", eventName, eventValues); + + if (eventValues == null) + eventValues == ""; + + if (_isVideo) { + eventValues += (eventValues != "" ? "," : "") + "isFullScreen:" + _isFullScreen; + } + + eventValues = "{" + eventValues + "}"; + + /* + OLD DIRECT METHOD + ExternalInterface.call( + "function(id, name) { mejs.MediaPluginBridge.fireEvent(id,name," + eventValues + "); }", + ExternalInterface.objectID, + eventName); + */ + + // use set timeout for performance reasons + //if (!_alwaysShowControls) { + ExternalInterface.call("setTimeout", "mejs.MediaPluginBridge.fireEvent('" + ExternalInterface.objectID + "','" + eventName + "'," + eventValues + ")",0); + //} + } + } + + + function updateControls(eventName:String):void { + + //trace("updating controls"); + + try { + // update controls + switch (eventName) { + case "pause": + case "paused": + case "ended": + _playButton.visible = true; + _pauseButton.visible = false; + break; + case "play": + case "playing": + _playButton.visible = false; + _pauseButton.visible = true; + break; + } + + if (eventName == HtmlMediaEvent.TIMEUPDATE || + eventName == HtmlMediaEvent.PROGRESS || + eventName == HtmlMediaEvent.FULLSCREENCHANGE) { + + //_duration.text = (_mediaElement.duration()*1).toString(); + _duration.text = secondsToTimeCode(_mediaElement.duration()); + //_currentTime.text = (_mediaElement.currentTime()*1).toString(); + _currentTime.text = secondsToTimeCode(_mediaElement.currentTime()); + + var pct:Number = (_mediaElement.currentTime() / _mediaElement.duration()) *_scrubTrack.scaleX; + + _scrubBar.scaleX = pct; + _scrubLoaded.scaleX = (_mediaElement.currentProgress()*_scrubTrack.scaleX)/100; + } + } catch (error:Error) { + trace("error: " + error.toString()); + + } + + } + + // START: utility + function secondsToTimeCode(seconds:Number):String { + var timeCode:String = ""; + seconds = Math.round(seconds); + var minutes:Number = Math.floor(seconds / 60); + timeCode = (minutes >= 10) ? minutes.toString() : "0" + minutes.toString(); + seconds = Math.floor(seconds % 60); + timeCode += ":" + ((seconds >= 10) ? seconds.toString() : "0" + seconds.toString()); + return timeCode; //minutes.toString() + ":" + seconds.toString(); + } + + function applyColor(item:Object, color:String):void { + + var myColor:ColorTransform = item.transform.colorTransform; + myColor.color = Number(color); + item.transform.colorTransform = myColor; + } + // END: utility + + } +}
\ No newline at end of file diff --git a/files_videoviewer/src/flash/FlashMediaElement.fla b/files_videoviewer/src/flash/FlashMediaElement.fla Binary files differnew file mode 100644 index 000000000..adf6e99fc --- /dev/null +++ b/files_videoviewer/src/flash/FlashMediaElement.fla diff --git a/files_videoviewer/src/flash/HtmlMediaEvent.as b/files_videoviewer/src/flash/HtmlMediaEvent.as new file mode 100644 index 000000000..d12c0fedf --- /dev/null +++ b/files_videoviewer/src/flash/HtmlMediaEvent.as @@ -0,0 +1,29 @@ +package { + + public class HtmlMediaEvent { + + public static var LOADED_DATA:String = "loadeddata"; + public static var PROGRESS:String = "progress"; + public static var TIMEUPDATE:String = "timeupdate"; + public static var SEEKED:String = "seeked"; + public static var PLAY:String = "play"; + public static var PLAYING:String = "playing"; + public static var PAUSE:String = "pause"; + public static var LOADEDMETADATA:String = "loadedmetadata"; + public static var ENDED:String = "ended"; + public static var VOLUMECHANGE:String = "volumechange"; + public static var STOP:String = "stop"; + + // new : 2/15/2011 + public static var LOADSTART:String = "loadstart"; + public static var CANPLAY:String = "canplay"; + // new : 3/3/2011 + public static var LOADEDDATA:String = "loadeddata"; + + // new : 4/12/2011 + public static var SEEKING:String = "seeking"; + + // new : 1/2/2012 + public static var FULLSCREENCHANGE:String = "fullscreenchange"; + } +} diff --git a/files_videoviewer/src/flash/htmlelements/AudioElement.as b/files_videoviewer/src/flash/htmlelements/AudioElement.as new file mode 100644 index 000000000..750599d4a --- /dev/null +++ b/files_videoviewer/src/flash/htmlelements/AudioElement.as @@ -0,0 +1,332 @@ + +package htmlelements +{ + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.ProgressEvent; + import flash.events.TimerEvent; + import flash.media.ID3Info; + import flash.media.Sound; + import flash.media.SoundChannel; + import flash.media.SoundLoaderContext; + import flash.media.SoundTransform; + import flash.net.URLRequest; + import flash.utils.Timer; + + + + /** + * ... + * @author DefaultUser (Tools -> Custom Arguments...) + */ + public class AudioElement implements IMediaElement + { + + private var _sound:Sound; + private var _soundTransform:SoundTransform; + private var _soundChannel:SoundChannel; + private var _soundLoaderContext:SoundLoaderContext; + + private var _volume:Number = 1; + private var _preMuteVolume:Number = 0; + private var _isMuted:Boolean = false; + private var _isPaused:Boolean = true; + private var _isEnded:Boolean = false; + private var _isLoaded:Boolean = false; + private var _currentTime:Number = 0; + private var _duration:Number = 0; + private var _bytesLoaded:Number = 0; + private var _bytesTotal:Number = 0; + private var _bufferedTime:Number = 0; + private var _bufferingChanged:Boolean = false; + + private var _currentUrl:String = ""; + private var _autoplay:Boolean = true; + private var _preload:String = ""; + + private var _element:FlashMediaElement; + private var _timer:Timer; + private var _firedCanPlay:Boolean = false; + + public function setSize(width:Number, height:Number):void { + // do nothing! + } + + public function duration():Number { + return _duration; + } + + public function currentTime():Number { + return _currentTime; + } + + public function currentProgress():Number { + return Math.round(_bytesLoaded/_bytesTotal*100); + } + + public function AudioElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number) + { + _element = element; + _autoplay = autoplay; + _volume = startVolume; + _preload = preload; + + _timer = new Timer(timerRate); + _timer.addEventListener(TimerEvent.TIMER, timerEventHandler); + + _soundTransform = new SoundTransform(_volume); + _soundLoaderContext = new SoundLoaderContext(); + } + + // events + function progressHandler(e:ProgressEvent):void { + + _bytesLoaded = e.bytesLoaded; + _bytesTotal = e.bytesTotal; + + // this happens too much to send every time + //sendEvent(HtmlMediaEvent.PROGRESS); + + // so now we just trigger a flag and send with the timer + _bufferingChanged = true; + } + + function id3Handler(e:Event):void { + sendEvent(HtmlMediaEvent.LOADEDMETADATA); + + try { + var id3:ID3Info = _sound.id3; + var obj = { + type:'id3', + album:id3.album, + artist:id3.artist, + comment:id3.comment, + genre:id3.genre, + songName:id3.songName, + track:id3.track, + year:id3.year + } + } catch (err:Error) {} + + + } + + function timerEventHandler(e:TimerEvent) { + _currentTime = _soundChannel.position/1000; + + // calculate duration + var duration = Math.round(_sound.length * _sound.bytesTotal/_sound.bytesLoaded/100) / 10; + + // check to see if the estimated duration changed + if (_duration != duration && !isNaN(duration)) { + + _duration = duration; + sendEvent(HtmlMediaEvent.LOADEDMETADATA); + } + + // check for progress + if (_bufferingChanged) { + + sendEvent(HtmlMediaEvent.PROGRESS); + + _bufferingChanged = false; + } + + // send timeupdate + sendEvent(HtmlMediaEvent.TIMEUPDATE); + + // sometimes the ended event doesn't fire, here's a fake one + if (_duration > 0 && _currentTime >= _duration-0.2) { + handleEnded(); + } + } + + function soundCompleteHandler(e:Event) { + handleEnded(); + } + + function handleEnded():void { + _timer.stop(); + _currentTime = 0; + _isEnded = true; + + sendEvent(HtmlMediaEvent.ENDED); + } + + //events + + + // METHODS + public function setSrc(url:String):void { + _currentUrl = url; + _isLoaded = false; + } + + + public function load():void { + + if (_currentUrl == "") + return; + + _sound = new Sound(); + //sound.addEventListener(IOErrorEvent.IO_ERROR,errorHandler); + _sound.addEventListener(ProgressEvent.PROGRESS,progressHandler); + _sound.addEventListener(Event.ID3,id3Handler); + _sound.load(new URLRequest(_currentUrl)); + _currentTime = 0; + + sendEvent(HtmlMediaEvent.LOADSTART); + + _isLoaded = true; + + sendEvent(HtmlMediaEvent.LOADEDDATA); + sendEvent(HtmlMediaEvent.CANPLAY); + _firedCanPlay = true; + + if (_playAfterLoading) { + _playAfterLoading = false; + play(); + } + } + + private var _playAfterLoading:Boolean= false; + + public function play():void { + + if (!_isLoaded) { + _playAfterLoading = true; + load(); + return; + } + + _timer.stop(); + + _soundChannel = _sound.play(_currentTime*1000, 0, _soundTransform); + _soundChannel.removeEventListener(Event.SOUND_COMPLETE, soundCompleteHandler); + _soundChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler); + + _timer.start(); + + didStartPlaying(); + } + + public function pause():void { + + _timer.stop(); + if (_soundChannel != null) { + _currentTime = _soundChannel.position/1000; + _soundChannel.stop(); + } + + _isPaused = true; + sendEvent(HtmlMediaEvent.PAUSE); + } + + + public function stop():void { + if (_timer != null) { + _timer.stop(); + } + if (_soundChannel != null) { + _soundChannel.stop(); + _sound.close(); + } + unload(); + sendEvent(HtmlMediaEvent.STOP); + } + + public function setCurrentTime(pos:Number):void { + sendEvent(HtmlMediaEvent.SEEKING); + _timer.stop(); + _currentTime = pos; + _soundChannel.stop(); + _sound.length + _soundChannel = _sound.play(_currentTime * 1000, 0, _soundTransform); + sendEvent(HtmlMediaEvent.SEEKED); + + _timer.start(); + + didStartPlaying(); + } + + private function didStartPlaying():void { + _isPaused = false; + sendEvent(HtmlMediaEvent.PLAY); + sendEvent(HtmlMediaEvent.PLAYING); + if (!_firedCanPlay) { + sendEvent(HtmlMediaEvent.LOADEDDATA); + sendEvent(HtmlMediaEvent.CANPLAY); + _firedCanPlay = true; + } + } + + + public function setVolume(volume:Number):void { + + _volume = volume; + _soundTransform.volume = volume; + + if (_soundChannel != null) { + _soundChannel.soundTransform = _soundTransform; + } + + _isMuted = (_volume == 0); + + sendEvent(HtmlMediaEvent.VOLUMECHANGE); + } + + public function getVolume():Number { + if(_isMuted) { + return 0; + } else { + return _volume; + } + } + + + public function setMuted(muted:Boolean):void { + + // ignore if already set + if ( (muted && _isMuted) || (!muted && !_isMuted)) + return; + + if (muted) { + _preMuteVolume = _soundTransform.volume; + setVolume(0); + } else { + setVolume(_preMuteVolume); + } + + _isMuted = muted; + } + + public function unload():void { + _sound = null; + _isLoaded = false; + } + + private function sendEvent(eventName:String) { + + // calculate this to mimic HTML5 + _bufferedTime = _bytesLoaded / _bytesTotal * _duration; + + // build JSON + var values:String = "duration:" + _duration + + ",currentTime:" + _currentTime + + ",muted:" + _isMuted + + ",paused:" + _isPaused + + ",ended:" + _isEnded + + ",volume:" + _volume + + ",src:\"" + _currentUrl + "\"" + + ",bytesTotal:" + _bytesTotal + + ",bufferedBytes:" + _bytesLoaded + + ",bufferedTime:" + _bufferedTime + + ""; + + _element.sendEvent(eventName, values); + } + + } + +} + diff --git a/files_videoviewer/src/flash/htmlelements/IMediaElement.as b/files_videoviewer/src/flash/htmlelements/IMediaElement.as new file mode 100644 index 000000000..d62660795 --- /dev/null +++ b/files_videoviewer/src/flash/htmlelements/IMediaElement.as @@ -0,0 +1,35 @@ + +package htmlelements +{ + + public interface IMediaElement { + + function play():void; + + function pause():void; + + function load():void; + + function stop():void; + + function setSrc(url:String):void; + + function setSize(width:Number, height:Number):void; + + function setCurrentTime(pos:Number):void; + + function setVolume(vol:Number):void; + + function getVolume():Number; + + function setMuted(muted:Boolean):void; + + function duration():Number; + + function currentTime():Number; + + function currentProgress():Number; + + } + +} diff --git a/files_videoviewer/src/flash/htmlelements/VideoElement.as b/files_videoviewer/src/flash/htmlelements/VideoElement.as new file mode 100644 index 000000000..7673c4f6c --- /dev/null +++ b/files_videoviewer/src/flash/htmlelements/VideoElement.as @@ -0,0 +1 @@ +package htmlelements
{
import flash.display.Sprite;
import flash.events.*;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.media.SoundTransform;
import flash.utils.Timer;
import FlashMediaElement;
import HtmlMediaEvent;
public class VideoElement extends Sprite implements IMediaElement
{
private var _currentUrl:String = "";
private var _autoplay:Boolean = true;
private var _preload:String = "";
private var _isPreloading:Boolean = false;
private var _connection:NetConnection;
private var _stream:NetStream;
private var _video:Video;
private var _element:FlashMediaElement;
private var _soundTransform;
private var _oldVolume:Number = 1;
// event values
private var _duration:Number = 0;
private var _framerate:Number;
private var _isPaused:Boolean = true;
private var _isEnded:Boolean = false;
private var _volume:Number = 1;
private var _isMuted:Boolean = false;
private var _bytesLoaded:Number = 0;
private var _bytesTotal:Number = 0;
private var _bufferedTime:Number = 0;
private var _bufferEmpty:Boolean = false;
private var _bufferingChanged:Boolean = false;
private var _seekOffset:Number = 0;
private var _videoWidth:Number = -1;
private var _videoHeight:Number = -1;
private var _timer:Timer;
private var _isRTMP:Boolean = false;
private var _streamer:String = "";
private var _isConnected:Boolean = false;
private var _playWhenConnected:Boolean = false;
private var _hasStartedPlaying:Boolean = false;
private var _parentReference:Object;
private var _pseudoStreamingEnabled:Boolean = false;
private var _pseudoStreamingStartQueryParam:String = "start";
public function setReference(arg:Object):void {
_parentReference = arg;
}
public function setSize(width:Number, height:Number):void {
_video.width = width;
_video.height = height;
}
public function setPseudoStreaming(enablePseudoStreaming:Boolean):void {
_pseudoStreamingEnabled = enablePseudoStreaming;
}
public function setPseudoStreamingStartParam(pseudoStreamingStartQueryParam:String):void {
_pseudoStreamingStartQueryParam = pseudoStreamingStartQueryParam;
}
public function get video():Video {
return _video;
}
public function get videoHeight():Number {
return _videoHeight;
}
public function get videoWidth():Number {
return _videoWidth;
}
public function duration():Number {
return _duration;
}
public function currentProgress():Number {
if(_stream != null) {
return Math.round(_stream.bytesLoaded/_stream.bytesTotal*100);
} else {
return 0;
}
}
public function currentTime():Number {
var currentTime:Number = 0;
if (_stream != null) {
currentTime = _stream.time;
if (_pseudoStreamingEnabled) {
currentTime += _seekOffset;
}
}
return currentTime;
}
// (1) load()
// calls _connection.connect();
// waits for NetConnection.Connect.Success
// _stream gets created
public function VideoElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number, streamer:String)
{
_element = element;
_autoplay = autoplay;
_volume = startVolume;
_preload = preload;
_streamer = streamer;
_video = new Video();
addChild(_video);
_connection = new NetConnection();
_connection.client = { onBWDone: function():void{} };
_connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
//_connection.connect(null);
_timer = new Timer(timerRate);
_timer.addEventListener("timer", timerHandler);
}
private function timerHandler(e:TimerEvent) {
_bytesLoaded = _stream.bytesLoaded;
_bytesTotal = _stream.bytesTotal;
if (!_isPaused) {
sendEvent(HtmlMediaEvent.TIMEUPDATE);
}
//trace("bytes", _bytesLoaded, _bytesTotal);
if (_bytesLoaded < _bytesTotal)
sendEvent(HtmlMediaEvent.PROGRESS);
}
// internal events
private function netStatusHandler(event:NetStatusEvent):void {
trace("netStatus", event.info.code);
switch (event.info.code) {
case "NetStream.Buffer.Empty":
_bufferEmpty = true;
_isEnded ? sendEvent(HtmlMediaEvent.ENDED) : null;
break;
case "NetStream.Buffer.Full":
_bytesLoaded = _stream.bytesLoaded;
_bytesTotal = _stream.bytesTotal;
_bufferEmpty = false;
sendEvent(HtmlMediaEvent.PROGRESS);
break;
case "NetConnection.Connect.Success":
connectStream();
break;
case "NetStream.Play.StreamNotFound":
trace("Unable to locate video");
break;
// STREAM
case "NetStream.Play.Start":
_isPaused = false;
sendEvent(HtmlMediaEvent.LOADEDDATA);
sendEvent(HtmlMediaEvent.CANPLAY);
if (!_isPreloading) {
sendEvent(HtmlMediaEvent.PLAY);
sendEvent(HtmlMediaEvent.PLAYING);
}
_timer.start();
break;
case "NetStream.Seek.Notify":
sendEvent(HtmlMediaEvent.SEEKED);
break;
case "NetStream.Pause.Notify":
_isPaused = true;
sendEvent(HtmlMediaEvent.PAUSE);
break;
case "NetStream.Play.Stop":
_isEnded = true;
_isPaused = false;
_timer.stop();
_bufferEmpty ? sendEvent(HtmlMediaEvent.ENDED) : null;
break;
}
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
private function asyncErrorHandler(event:AsyncErrorEvent):void {
// ignore AsyncErrorEvent events.
}
private function onMetaDataHandler(info:Object):void {
// Only set the duration when we first load the video
if (_duration == 0) {
_duration = info.duration;
}
_framerate = info.framerate;
_videoWidth = info.width;
_videoHeight = info.height;
// set size?
sendEvent(HtmlMediaEvent.LOADEDMETADATA);
if (_isPreloading) {
_stream.pause();
_isPaused = true;
_isPreloading = false;
sendEvent(HtmlMediaEvent.PROGRESS);
sendEvent(HtmlMediaEvent.TIMEUPDATE);
}
}
// interface members
public function setSrc(url:String):void {
if (_isConnected && _stream) {
// stop and restart
_stream.pause();
}
_currentUrl = url;
_isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//) || _streamer != "";
_isConnected = false;
_hasStartedPlaying = false;
}
public function load():void {
// disconnect existing stream and connection
if (_isConnected && _stream) {
_stream.pause();
_stream.close();
_connection.close();
}
_isConnected = false;
_isPreloading = false;
_isEnded = false;
_bufferEmpty = false;
// start new connection
if (_isRTMP) {
var rtmpInfo:Object = parseRTMP(_currentUrl);
if (_streamer != "") {
rtmpInfo.server = _streamer;
rtmpInfo.stream = _currentUrl;
}
_connection.connect(rtmpInfo.server);
} else {
_connection.connect(null);
}
// in a few moments the "NetConnection.Connect.Success" event will fire
// and call createConnection which finishes the "load" sequence
sendEvent(HtmlMediaEvent.LOADSTART);
}
private function connectStream():void {
trace("connectStream");
_stream = new NetStream(_connection);
// explicitly set the sound since it could have come before the connection was made
_soundTransform = new SoundTransform(_volume);
_stream.soundTransform = _soundTransform;
// set the buffer to ensure nice playback
_stream.bufferTime = 1;
_stream.bufferTimeMax = 3;
_stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection
_stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
var customClient:Object = new Object();
customClient.onMetaData = onMetaDataHandler;
_stream.client = customClient;
_video.attachNetStream(_stream);
// start downloading without playing )based on preload and play() hasn't been called)
// I wish flash had a load() command to make this less awkward
if (_preload != "none" && !_playWhenConnected) {
_isPaused = true;
//stream.bufferTime = 20;
_stream.play(getCurrentUrl(0), 0, 0);
_stream.pause();
_isPreloading = true;
//_stream.pause();
//
//sendEvent(HtmlMediaEvent.PAUSE); // have to send this because the "playing" event gets sent via event handlers
}
_isConnected = true;
if (_playWhenConnected && !_hasStartedPlaying) {
play();
_playWhenConnected = false;
}
}
public function play():void {
if (!_hasStartedPlaying && !_isConnected) {
_playWhenConnected = true;
load();
return;
}
if (_hasStartedPlaying) {
if (_isPaused) {
_stream.resume();
_timer.start();
_isPaused = false;
sendEvent(HtmlMediaEvent.PLAY);
sendEvent(HtmlMediaEvent.PLAYING);
}
} else {
if (_isRTMP) {
var rtmpInfo:Object = parseRTMP(_currentUrl);
_stream.play(rtmpInfo.stream);
} else {
_stream.play(getCurrentUrl(0));
}
_timer.start();
_isPaused = false;
_hasStartedPlaying = true;
// don't toss play/playing events here, because we haven't sent a
// canplay / loadeddata event yet. that'll be handled in the net
// event listener
}
}
public function pause():void {
if (_stream == null)
return;
_stream.pause();
_isPaused = true;
if (_bytesLoaded == _bytesTotal) {
_timer.stop();
}
_isPaused = true;
sendEvent(HtmlMediaEvent.PAUSE);
}
public function stop():void {
if (_stream == null)
return;
_stream.close();
_isPaused = false;
_timer.stop();
sendEvent(HtmlMediaEvent.STOP);
}
public function setCurrentTime(pos:Number):void {
if (_stream == null) {
return;
}
// Calculate the position of the buffered video
var bufferPosition:Number = _bytesLoaded / _bytesTotal * _duration;
if (_pseudoStreamingEnabled) {
sendEvent(HtmlMediaEvent.SEEKING);
// Normal seek if it is in buffer and this is the first seek
if (pos < bufferPosition && _seekOffset == 0) {
_stream.seek(pos);
}
else {
// Uses server-side pseudo-streaming to seek
_stream.play(getCurrentUrl(pos));
_seekOffset = pos;
}
}
else {
sendEvent(HtmlMediaEvent.SEEKING);
_stream.seek(pos);
}
if (!_isEnded) {
sendEvent(HtmlMediaEvent.TIMEUPDATE);
}
}
public function setVolume(volume:Number):void {
if (_stream != null) {
_soundTransform = new SoundTransform(volume);
_stream.soundTransform = _soundTransform;
}
_volume = volume;
_isMuted = (_volume == 0);
sendEvent(HtmlMediaEvent.VOLUMECHANGE);
}
public function getVolume():Number {
if(_isMuted) {
return 0;
} else {
return _volume;
}
}
public function setMuted(muted:Boolean):void {
if (_isMuted == muted)
return;
if (muted) {
_oldVolume = (_stream == null) ? _oldVolume : _stream.soundTransform.volume;
setVolume(0);
} else {
setVolume(_oldVolume);
}
_isMuted = muted;
}
private function sendEvent(eventName:String) {
// calculate this to mimic HTML5
_bufferedTime = _bytesLoaded / _bytesTotal * _duration;
// build JSON
var values:String =
"duration:" + _duration +
",framerate:" + _framerate +
",currentTime:" + currentTime() +
",muted:" + _isMuted +
",paused:" + _isPaused +
",ended:" + _isEnded +
",volume:" + _volume +
",src:\"" + _currentUrl + "\"" +
",bytesTotal:" + _bytesTotal +
",bufferedBytes:" + _bytesLoaded +
",bufferedTime:" + _bufferedTime +
",videoWidth:" + _videoWidth +
",videoHeight:" + _videoHeight +
"";
_element.sendEvent(eventName, values);
}
private function parseRTMP(url:String) {
var match:Array = url.match(/(.*)\/((flv|mp4|mp3):.*)/);
var rtmpInfo:Object = {
server: null,
stream: null
};
if (match) {
rtmpInfo.server = match[1];
rtmpInfo.stream = match[2];
}
else {
rtmpInfo.server = url.replace(/\/[^\/]+$/,"/");
rtmpInfo.stream = url.split("/").pop();
}
trace("parseRTMP - server: " + rtmpInfo.server + " stream: " + rtmpInfo.stream);
return rtmpInfo;
}
private function getCurrentUrl(pos:Number):String {
var url:String = _currentUrl;
if (_pseudoStreamingEnabled) {
if (url.indexOf('?') > -1) {
url = url + '&' + _pseudoStreamingStartQueryParam + '=' + pos;
}
else {
url = url + '?' + _pseudoStreamingStartQueryParam + '=' + pos;
}
}
return url;
}
}
}
\ No newline at end of file diff --git a/files_videoviewer/src/flash/htmlelements/YouTubeElement.as b/files_videoviewer/src/flash/htmlelements/YouTubeElement.as new file mode 100644 index 000000000..80986fa62 --- /dev/null +++ b/files_videoviewer/src/flash/htmlelements/YouTubeElement.as @@ -0,0 +1,403 @@ +package htmlelements +{ + import flash.display.Sprite; + import flash.events.*; + import flash.net.NetConnection; + import flash.net.NetStream; + import flash.media.Video; + import flash.media.SoundTransform; + import flash.utils.Timer; + import flash.net.URLLoader; + import flash.net.URLRequest; + import flash.net.URLVariables; + import flash.net.URLRequestMethod; + import flash.display.MovieClip; + import flash.display.Loader; + import flash.display.DisplayObject; + + + + import FlashMediaElement; + import HtmlMediaEvent; + + public class YouTubeElement extends Sprite implements IMediaElement + { + private var _currentUrl:String = ""; + private var _autoplay:Boolean = true; + private var _preload:String = ""; + + private var _element:FlashMediaElement; + + // event values + private var _currentTime:Number = 0; + private var _duration:Number = 0; + private var _framerate:Number; + private var _isPaused:Boolean = true; + private var _isEnded:Boolean = false; + private var _volume:Number = 1; + private var _isMuted:Boolean = false; + + private var _bytesLoaded:Number = 0; + private var _bytesTotal:Number = 0; + private var _bufferedTime:Number = 0; + private var _bufferEmpty:Boolean = false; + + private var _videoWidth:Number = -1; + private var _videoHeight:Number = -1; + + private var _timer:Timer; + + // YouTube stuff + private var _playerLoader:Loader; + private var _player:Object = null; + private var _playerIsLoaded:Boolean = false; + private var _youTubeId:String = ""; + + //http://code.google.com/p/gdata-samples/source/browse/trunk/ytplayer/actionscript3/com/google/youtube/examples/AS3Player.as + private static const WIDESCREEN_ASPECT_RATIO:String = "widescreen"; + private static const QUALITY_TO_PLAYER_WIDTH:Object = { + small: 320, + medium: 640, + large: 854, + hd720: 1280 + }; + private static const STATE_ENDED:Number = 0; + private static const STATE_PLAYING:Number = 1; + private static const STATE_PAUSED:Number = 2; + private static const STATE_CUED:Number = 5; + + + public function get player():DisplayObject { + return _player; + } + + public function setSize(width:Number, height:Number):void { + if (_player != null) { + _player.setSize(width, height); + } else { + initHeight = height; + initWidth = width; + } + } + + public function get videoHeight():Number { + return _videoHeight; + } + + public function get videoWidth():Number { + return _videoWidth; + } + + + public function duration():Number { + return _duration; + } + + public function currentProgress():Number { + if(_bytesTotal> 0) { + return Math.round(_bytesLoaded/_bytesTotal*100); + } else { + return 0; + } + } + + public function currentTime():Number { + return _currentTime; + } + + + public var initHeight:Number; + public var initWidth:Number; + + // (1) load() + // calls _connection.connect(); + // waits for NetConnection.Connect.Success + // _stream gets created + + private var _isChromeless:Boolean = false; + + + public function YouTubeElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number) + { + _element = element; + _autoplay = autoplay; + _volume = startVolume; + _preload = preload; + initHeight = 0; + initWidth = 0; + + _playerLoader = new Loader(); + _playerLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, playerLoaderInitHandler); + + // chromeless + if (_isChromeless) { + _playerLoader.load(new URLRequest("//www.youtube.com/apiplayer?version=3&controls=1&rel=0&showinfo=0&iv_load_policy=1")); + } + + + _timer = new Timer(timerRate); + _timer.addEventListener("timer", timerHandler); + _timer.start(); + } + + private function playerLoaderInitHandler(event:Event):void { + + trace("yt player init"); + + _element.addChild(_playerLoader.content); + _element.setControlDepth(); + _playerLoader.content.addEventListener("onReady", onPlayerReady); + _playerLoader.content.addEventListener("onError", onPlayerError); + _playerLoader.content.addEventListener("onStateChange", onPlayerStateChange); + _playerLoader.content.addEventListener("onPlaybackQualityChange", onVideoPlaybackQualityChange); + } + + private function onPlayerReady(event:Event):void { + _playerIsLoaded = true; + + _player = _playerLoader.content; + + if (initHeight > 0 && initWidth > 0) + _player.setSize(initWidth, initHeight); + + if (_youTubeId != "") { // && _isChromeless) { + if (_autoplay) { + player.loadVideoById(_youTubeId); + } else { + player.cueVideoById(_youTubeId); + } + _timer.start(); + } + } + + private function onPlayerError(event:Event):void { + // trace("Player error:", Object(event).data); + } + + private function onPlayerStateChange(event:Event):void { + trace("State is", Object(event).data); + + _duration = _player.getDuration(); + + switch (Object(event).data) { + case STATE_ENDED: + _isEnded = true; + _isPaused = false; + + sendEvent(HtmlMediaEvent.ENDED); + + break; + + case STATE_PLAYING: + _isEnded = false; + _isPaused = false; + + sendEvent(HtmlMediaEvent.PLAY); + sendEvent(HtmlMediaEvent.PLAYING); + break; + + case STATE_PAUSED: + _isEnded = false; + _isPaused = true; + + sendEvent(HtmlMediaEvent.PAUSE); + + break; + + case STATE_CUED: + sendEvent(HtmlMediaEvent.CANPLAY); + + // resize? + + break; + } + } + + private function onVideoPlaybackQualityChange(event:Event):void { + trace("Current video quality:", Object(event).data); + //resizePlayer(Object(event).data); + } + + private function timerHandler(e:TimerEvent) { + + if (_playerIsLoaded) { + _bytesLoaded = _player.getVideoBytesLoaded(); + _bytesTotal = _player.getVideoBytesTotal(); + _currentTime = player.getCurrentTime(); + + if (!_isPaused) + sendEvent(HtmlMediaEvent.TIMEUPDATE); + + if (_bytesLoaded < _bytesTotal) + sendEvent(HtmlMediaEvent.PROGRESS); + } + + } + + private function getYouTubeId(url:String):String { + // http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0 + // http://www.youtube.com/v/VIDEO_ID?version=3 + // http://youtu.be/Djd6tPrxc08 + + url = unescape(url); + + var youTubeId:String = ""; + + if (url.indexOf("?") > 0) { + // assuming: http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0 + youTubeId = getYouTubeIdFromParam(url); + + // if it's http://www.youtube.com/v/VIDEO_ID?version=3 + if (youTubeId == "") { + youTubeId = getYouTubeIdFromUrl(url); + } + } else { + youTubeId = getYouTubeIdFromUrl(url); + } + + return youTubeId; + } + + // http://www.youtube.com/watch?feature=player_embedded&v=yyWWXSwtPP0 + private function getYouTubeIdFromParam(url:String):String { + + + var youTubeId:String = ""; + var parts:Array = url.split('?'); + var parameters:Array = parts[1].split('&'); + + for (var i:Number=0; i<parameters.length; i++) { + var paramParts = parameters[i].split('='); + if (paramParts[0] == "v") { + + youTubeId = paramParts[1]; + break; + } + + } + + + return youTubeId; + } + + + // http://www.youtube.com/v/VIDEO_ID?version=3 + // http://youtu.be/Djd6tPrxc08 + private function getYouTubeIdFromUrl(url:String):String { + + + var youTubeId:String = ""; + + // remove any querystring elements + var parts:Array = url.split('?'); + url = parts[0]; + + youTubeId = url.substring(url.lastIndexOf("/")+1); + + return youTubeId; + } + + + // interface members + public function setSrc(url:String):void { + trace("yt setSrc()" + url ); + + _currentUrl = url; + + _youTubeId = getYouTubeId(url); + + if (!_playerIsLoaded && !_isChromeless) { + _playerLoader.load(new URLRequest("//www.youtube.com/v/" + _youTubeId + "?version=3&controls=0&rel=0&showinfo=0&iv_load_policy=1")); + } + } + + + + + public function load():void { + // do nothing + trace("yt load()"); + + if (_playerIsLoaded) { + player.loadVideoById(_youTubeId); + _timer.start(); + } else { + /* + if (!_isChromless && _youTubeId != "") { + _playerLoader.load(new URLRequest("http://www.youtube.com/v/" + _youTubeId + "?version=3&controls=0&rel=0&showinfo=0&iv_load_policy=1")); + } + */ + } + } + + public function play():void { + if (_playerIsLoaded) { + _player.playVideo(); + } + + } + + public function pause():void { + if (_playerIsLoaded) { + _player.pauseVideo(); + } + } + + public function stop():void { + if (_playerIsLoaded) { + _player.pauseVideo(); + } + } + + public function setCurrentTime(pos:Number):void { + //_player.seekTo(pos, false); + _player.seekTo(pos, true); // works in all places now + } + + public function setVolume(volume:Number):void { + _player.setVolume(volume*100); + _volume = volume; + } + + public function getVolume():Number { + return _player.getVolume()*100; + } + + public function setMuted(muted:Boolean):void { + if (muted) { + _player.mute(); + + } else { + _player.unMute(); + } + _isMuted = _player.isMuted(); + sendEvent(HtmlMediaEvent.VOLUMECHANGE); + } + + + private function sendEvent(eventName:String) { + + // calculate this to mimic HTML5 + _bufferedTime = _bytesLoaded / _bytesTotal * _duration; + + // build JSON + var values:String = + "duration:" + _duration + + ",framerate:" + _framerate + + ",currentTime:" + _currentTime + + ",muted:" + _isMuted + + ",paused:" + _isPaused + + ",ended:" + _isEnded + + ",volume:" + _volume + + ",src:\"" + _currentUrl + "\"" + + ",bytesTotal:" + _bytesTotal + + ",bufferedBytes:" + _bytesLoaded + + ",bufferedTime:" + _bufferedTime + + ",videoWidth:" + _videoWidth + + ",videoHeight:" + _videoHeight + + ""; + + _element.sendEvent(eventName, values); + } + } +} diff --git a/files_videoviewer/src/silverlight/App.xaml b/files_videoviewer/src/silverlight/App.xaml new file mode 100644 index 000000000..47cf6fb13 --- /dev/null +++ b/files_videoviewer/src/silverlight/App.xaml @@ -0,0 +1,8 @@ +<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + x:Class="SilverlightMediaElement.App" + > + <Application.Resources> + + </Application.Resources> +</Application> diff --git a/files_videoviewer/src/silverlight/App.xaml.cs b/files_videoviewer/src/silverlight/App.xaml.cs new file mode 100644 index 000000000..be67bfbf7 --- /dev/null +++ b/files_videoviewer/src/silverlight/App.xaml.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; + +namespace SilverlightMediaElement +{ + public partial class App : Application + { + + public App() + { + this.Startup += this.Application_Startup; + this.Exit += this.Application_Exit; + this.UnhandledException += this.Application_UnhandledException; + + InitializeComponent(); + } + + private void Application_Startup(object sender, StartupEventArgs e) + { + this.RootVisual = new MainPage(e.InitParams); + } + + private void Application_Exit(object sender, EventArgs e) + { + + } + + private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) + { + // If the app is running outside of the debugger then report the exception using + // the browser's exception mechanism. On IE this will display it a yellow alert + // icon in the status bar and Firefox will display a script error. + if (!System.Diagnostics.Debugger.IsAttached) + { + + // NOTE: This will allow the application to continue running after an exception has been thrown + // but not handled. + // For production applications this error handling should be replaced with something that will + // report the error to the website and stop the application. + e.Handled = true; + Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); }); + } + } + + private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e) + { + try + { + string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; + errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n"); + + System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");"); + } + catch (Exception) + { + } + } + } +} diff --git a/files_videoviewer/src/silverlight/MainPage.xaml b/files_videoviewer/src/silverlight/MainPage.xaml new file mode 100644 index 000000000..54af028fe --- /dev/null +++ b/files_videoviewer/src/silverlight/MainPage.xaml @@ -0,0 +1,276 @@ + +<UserControl + x:Class="SilverlightMediaElement.MainPage" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" + mc:Ignorable="d" + Width="640" Height="360"> + <UserControl.Resources> + <Style x:Key="roundThumbStyle" TargetType="Thumb"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="Thumb"> + <Ellipse Stroke="#FFFFFFFF" StrokeThickness="2" Fill="#FF484848"/> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="SliderStyle" TargetType="Slider"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="Slider"> + <Grid x:Name="Root" Background="Transparent"> + <Grid.Resources> + <ControlTemplate x:Key="RightRepeatButtonTemplate"> + <Rectangle Height="8" Margin="-5,0,0,0" Grid.Column="0" Grid.ColumnSpan="3" + StrokeThickness="0.5" RadiusY="1" RadiusX="1" Fill="#FF484848"/> + </ControlTemplate> + <ControlTemplate x:Key="LeftRepeatButtonTemplate"> + <Rectangle Height="8" Margin="0,0,-5,0" Grid.Column="0" Grid.ColumnSpan="3" + StrokeThickness="0.5" RadiusY="1" RadiusX="1" Fill="#FFAFAFAF"/> + </ControlTemplate> + </Grid.Resources> + <Grid x:Name="HorizontalTemplate"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + + <RepeatButton x:Name="HorizontalTrackLargeChangeDecreaseRepeatButton" Grid.Column="0" + IsTabStop="False" Template="{StaticResource LeftRepeatButtonTemplate}"/> + <Rectangle x:Name="LeftTrack" Grid.Row="1" Fill="#00FFFFFF" Cursor="Hand" MouseLeftButtonDown="LeftTrack_MouseLeftButtonDown"/> + <Thumb Background="#00FFFFFF" Height="10" x:Name="HorizontalThumb" Width="10" + Grid.Column="1" Style="{StaticResource roundThumbStyle}" HorizontalAlignment="Left" + DragStarted="HorizontalThumb_DragStarted" DragCompleted="HorizontalThumb_DragCompleted" + Canvas.ZIndex="1"/> + <RepeatButton x:Name="HorizontalTrackLargeChangeIncreaseRepeatButton" Grid.Column="2" + IsTabStop="False" Template="{StaticResource RightRepeatButtonTemplate}"/> + <Rectangle x:Name="RightTrack" Grid.Column="2" Grid.Row="1" Fill="#00FFFFFF" Cursor="Hand" MouseLeftButtonDown="LeftTrack_MouseLeftButtonDown"/> + </Grid> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <ControlTemplate x:Key="PlayButtonTemplate" TargetType="ToggleButton"> + <Grid x:Name="grid" Background="Transparent"> + <vsm:VisualStateManager.VisualStateGroups> + <vsm:VisualStateGroup x:Name="FocusStates"> + <vsm:VisualState x:Name="Focused"> + <Storyboard> + </Storyboard> + </vsm:VisualState> + <vsm:VisualState x:Name="Unfocused"> + <Storyboard/> + </vsm:VisualState> + </vsm:VisualStateGroup> + <vsm:VisualStateGroup x:Name="CommonStates"> + <vsm:VisualState x:Name="Normal"> + <Storyboard/> + </vsm:VisualState> + <vsm:VisualState x:Name="MouseOver"> + <Storyboard> + </Storyboard> + </vsm:VisualState> + <vsm:VisualState x:Name="Pressed"> + <Storyboard/> + </vsm:VisualState> + </vsm:VisualStateGroup> + <vsm:VisualStateGroup x:Name="CheckStates"> + <vsm:VisualState x:Name="Checked"> + <Storyboard> + <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" + Storyboard.TargetName="playSymbol" + Storyboard.TargetProperty="(UIElement.Opacity)"> + <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/> + </DoubleAnimationUsingKeyFrames> + <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" + Storyboard.TargetName="pauseSymbol" + Storyboard.TargetProperty="(UIElement.Opacity)"> + <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/> + </DoubleAnimationUsingKeyFrames> + </Storyboard> + </vsm:VisualState> + <vsm:VisualState x:Name="Unchecked"> + <Storyboard> + <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="pauseSymbol" Storyboard.TargetProperty="(UIElement.Opacity)"> + <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/> + </DoubleAnimationUsingKeyFrames> + </Storyboard> + </vsm:VisualState> + </vsm:VisualStateGroup> + </vsm:VisualStateManager.VisualStateGroups> + <Grid Margin="11,3,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" + Opacity="1" x:Name="playSymbol" Width="21" Height="22"> + <Path Width="14" Height="15" Stretch="Fill" Fill="#FF7F7F7F" + Data="F1 M 15.1997,22.542L 29.7776,14.89L 15.2707,6.99886L 15.1997,22.542 Z "/> + </Grid> + <Grid Margin="11,2,0,0" Opacity="0" x:Name="pauseSymbol" Width="31" Height="15"> + <Rectangle Stretch="Fill" Fill="#FF7F7F7F" HorizontalAlignment="Left" + Margin="0,0,0,0" Width="6"/> + <Rectangle Stretch="Fill" Fill="#FF7F7F7F" HorizontalAlignment="Stretch" + Margin="6,0,13,0" Width="6"/> + </Grid> + </Grid> + </ControlTemplate> + + <ControlTemplate x:Key="MuteButtonTemplate" TargetType="ToggleButton"> + <Grid Background="Transparent" Cursor="Hand"> + <vsm:VisualStateManager.VisualStateGroups> + <vsm:VisualStateGroup x:Name="FocusStates"> + <vsm:VisualState x:Name="Focused"> + <Storyboard> + </Storyboard> + </vsm:VisualState> + <vsm:VisualState x:Name="Unfocused"> + <Storyboard/> + </vsm:VisualState> + </vsm:VisualStateGroup> + <vsm:VisualStateGroup x:Name="CommonStates"> + <vsm:VisualState x:Name="Normal"> + <Storyboard/> + </vsm:VisualState> + <vsm:VisualState x:Name="MouseOver"> + <Storyboard> + </Storyboard> + </vsm:VisualState> + <vsm:VisualState x:Name="Pressed"> + <Storyboard/> + </vsm:VisualState> + </vsm:VisualStateGroup> + <vsm:VisualStateGroup x:Name="CheckStates"> + <vsm:VisualState x:Name="Checked"> + <Storyboard> + <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" + Storyboard.TargetName="volumeSymbol" + Storyboard.TargetProperty="(UIElement.Opacity)"> + <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/> + </DoubleAnimationUsingKeyFrames> + </Storyboard> + </vsm:VisualState> + <vsm:VisualState x:Name="Unchecked"> + <Storyboard> + <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" + Storyboard.TargetName="volumeSymbol" + Storyboard.TargetProperty="(UIElement.Opacity)"> + <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/> + </DoubleAnimationUsingKeyFrames> + </Storyboard> + </vsm:VisualState> + </vsm:VisualStateGroup> + </vsm:VisualStateManager.VisualStateGroups> + <Grid HorizontalAlignment="Left" VerticalAlignment="Top" + Width="17"> + <Path HorizontalAlignment="Left" Stretch="Fill" + Fill="#FF7F7F7F" Data="F1 M 23.1457,26.5056L 23.1457,33.8944L 25.7913,33.8944L 28.8235,37.4722L 30.5346,37.4722L 30.5665,23.0833L 28.8995,23.0833L 25.8679,26.5056L 23.1457,26.5056 Z " + Width="7.421" Height="14.389" UseLayoutRounding="False" + Margin="0,6.5,0,6.5"/> + + <Grid HorizontalAlignment="Right" Width="7.003" x:Name="volumeSymbol" Margin="0,10"> + <Path HorizontalAlignment="Right" VerticalAlignment="Stretch" + Width="2.398" + Data="M0.5,0.5 C0.5,0.5 2.5939558,2.7128265 2.5946648,7.0504856 C2.5953746,11.391507 0.50033337,13.889001 0.50033337,13.889001" + Stretch="Fill" Stroke="#FF7F7F7F" Margin="0,0,-0.398,0" UseLayoutRounding="False"/> + <Path HorizontalAlignment="Stretch" Margin="2.4,2.384,2.317,1.584" VerticalAlignment="Stretch" + Data="M0.5,0.50000006 C0.5,0.50000006 1.4786903,2.1275051 1.4781417,4.9569001 C1.4776551,7.4670725 0.35717732,9.892808 0.35717732,9.892808" Stretch="Fill" Stroke="#FF7F7F7F" UseLayoutRounding="False"/> + <Path HorizontalAlignment="Left" Margin="0,4.36,0,3.46" VerticalAlignment="Stretch" Width="1.542" + Data="M0.5,0.5 C0.5,0.5 1.0412779,1.4903735 1.042276,3.1459465 C1.0429831,4.3189368 0.66544437,6.0685911 0.66544437,6.0685911" Stretch="Fill" Stroke="#FF7F7F7F" d:LayoutOverrides="Width"/> + </Grid> + </Grid> + </Grid> + </ControlTemplate> + + <ControlTemplate x:Key="ButtonTemplate" TargetType="Button"> + <Grid Background="Transparent"> + <ContentPresenter Width="Auto"/> + </Grid> + </ControlTemplate> + </UserControl.Resources> + + <Grid x:Name="LayoutRoot" Background="Black" Width="640" Height="360"> + + <MediaElement Grid.Row="0" Grid.Column="0" Width="640" Height="360" + CacheMode="BitmapCache" AutoPlay="false" Name="media"> + + </MediaElement> + <Button x:Name="bigPlayButton" Template="{StaticResource ButtonTemplate}" + Click="BigPlayButton_Click" Grid.Row="0" Visibility="Collapsed"> + <Canvas Width="100" Height="100"> + <Path Width="100" Height="100" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" + Fill="#77000000" Data="F1 M 15,0L 85,0C 93.2843,0 100,6.71573 100,15L 100,85C 100,93.2843 93.2843,100 85,100L 15,100C 6.71573,100 0,93.2843 0,85L 0,15C 0,6.71573 6.71573,0 15,0 Z "/> + <Path Width="40.8182" Height="47.1328" Canvas.Left="34.6439" + Canvas.Top="27.6003" Stretch="Fill" Fill="#FFFFFFFF" + Data="F1 M 75.4621,51.1667L 34.6439,27.6003L 34.6439,74.7331L 75.4621,51.1667 Z "/> + </Canvas> + </Button> + <TextBox Margin="25,25,0,0" Name="textBox1" VerticalScrollBarVisibility="Auto" Height="146" VerticalAlignment="Top" HorizontalAlignment="Left" Width="235" /> + <Button Content="" Height="36" HorizontalAlignment="Right" x:Name="FullscreenButton" VerticalAlignment="Bottom" Width="31" Click="FullscreenButton_Click" Opacity="0" Background="#00000000" Cursor="Hand" /> + + <Grid x:Name="transportControls" VerticalAlignment="Bottom" Height="40" Background="#FF000000" + Grid.Row="1" > + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="0" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" MinWidth="10" /> + <ColumnDefinition Width="Auto" MinWidth="10" /> + </Grid.ColumnDefinitions> + + <!-- play symbol showing is checked = false, Pause symbol showing is checked = true--> + <ToggleButton x:Name="playPauseButton" Template="{StaticResource PlayButtonTemplate}" + Click="PlayPauseButton_Click" IsChecked="false" Cursor="Hand"/> + + <Grid x:Name="time" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="40" /> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="10" /> + <ColumnDefinition Width="40" /> + </Grid.ColumnDefinitions> + + <TextBlock x:Name="currentTimeTextBlock" Margin="0,1.5,10,0" Height="12" + FontFamily="Verdana" FontSize="10" Text="00:00" TextWrapping="Wrap" + Foreground="#FFFFFFFF" FontStyle="Normal" HorizontalAlignment="Right" + TextAlignment="Right" Grid.Column="0"/> + + <Slider x:Name="timelineSlider" Margin="0,2,0,-1" + Maximum="1" Style="{StaticResource SliderStyle}" Grid.Column="1" + ValueChanged="TimelineSlider_ValueChanged" + Value="0"/> + + <TextBlock Margin="0,1.5,0,0" Height="12" FontFamily="Verdana" FontSize="10" + Text="" TextWrapping="Wrap" Foreground="#FFFFFFFF" + FontStyle="Normal" HorizontalAlignment="Center" TextAlignment="Right" + Grid.Column="2"/> + <TextBlock x:Name="totalTimeTextBlock" Margin="0,1.5,0,0" Height="12" + FontFamily="Verdana" FontSize="10" Text="00:00" TextWrapping="Wrap" + Foreground="#FFFFFFFF" FontStyle="Normal" HorizontalAlignment="Left" + TextAlignment="Right" Grid.Column="3"/> + </Grid> + + <ToggleButton IsChecked="false" Grid.Column="3" x:Name="muteButton" + Template="{StaticResource MuteButtonTemplate}" Click="MuteButton_Click" + VerticalAlignment="Center" Margin="0,0,6,0" Cursor="Hand"/> + + <Slider Grid.Column="4" HorizontalAlignment="Stretch" Margin="3,0,0,0" + VerticalAlignment="Center" Maximum="1" x:Name="volumeSlider" + Background="#FF777777" Style="{StaticResource SliderStyle}" Width="50" + Value="{Binding ElementName=media, Mode=TwoWay, Path=Volume, UpdateSourceTrigger=Default}"/> + + <Button x:Name="fullScreenButton" Grid.Column="5" Margin="8,10,4,10" Click="FullScreenButton_Click" + Template="{StaticResource ButtonTemplate}" VerticalAlignment="Center" Cursor="Hand"> + <Path Height="14.375" HorizontalAlignment="Stretch" + VerticalAlignment="Bottom" RenderTransformOrigin="0.212389379739761,0.208695650100708" + Data="M10.181361,8.375 L12.844413,11.008244 L14.125,9.7418737 L14.125,14.375 L9.675765,14.374833 L10.906104,13.158273 L8.125,10.408315 L10.181361,8.375 z M3.9666855,8.375 L6,10.431361 L3.3667567,13.094413 L4.6331258,14.375 L0,14.375 L0.00016707927,9.925765 L1.2167276,11.156104 L3.9666855,8.375 z M9.4918737,0 L14.125,0 L14.124833,4.449235 L12.908273,3.2188957 L10.158315,6 L8.125,3.943639 L10.758244,1.2805867 L9.4918737,0 z M0,0 L4.449235,0.00016686507 L3.2188957,1.2167276 L6,3.9666855 L3.943639,6 L1.280587,3.3667567 L0,4.6331258 L0,0 z" + Fill="#FF7F7F7F" Stretch="Fill" Stroke="#FF000000" StrokeThickness="0" /> + </Button> + </Grid> + </Grid> +</UserControl>
\ No newline at end of file diff --git a/files_videoviewer/src/silverlight/MainPage.xaml.cs b/files_videoviewer/src/silverlight/MainPage.xaml.cs new file mode 100644 index 000000000..5f5da703f --- /dev/null +++ b/files_videoviewer/src/silverlight/MainPage.xaml.cs @@ -0,0 +1,636 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; +using System.Windows.Browser; +using System.Globalization; + + +namespace SilverlightMediaElement +{ + [ScriptableType] + public partial class MainPage : UserControl + { + System.Windows.Threading.DispatcherTimer _timer; + + // work arounds for src, load(), play() compatibility + bool _isLoading = false; + bool _isAttemptingToPlay = false; + + // variables + string _mediaUrl; + string _preload; + string _htmlid; + bool _autoplay = false; + bool _debug = false; + int _width = 0; + int _height = 0; + int _timerRate = 0; + double _bufferedBytes = 0; + double _bufferedTime = 0; + double _volume = 1; + int _videoWidth = 0; + int _videoHeight = 0; + + // state + bool _isPaused = true; + bool _isEnded = false; + + // dummy + bool _firedCanPlay = false; + + // mediaElement.Position updates TimelineSlider.Value, and + // updating TimelineSlider.Value updates mediaElement.Position, + // this variable helps us break the infinite loop + private bool duringTickEvent = false; + + private bool playVideoWhenSliderDragIsOver = false; + + public MainPage(IDictionary<string, string> initParams) + { + InitializeComponent(); + + HtmlPage.RegisterScriptableObject("MediaElementJS", this); + + + // add events + media.BufferingProgressChanged += new RoutedEventHandler(media_BufferingProgressChanged); + media.DownloadProgressChanged += new RoutedEventHandler(media_DownloadProgressChanged); + media.CurrentStateChanged += new RoutedEventHandler(media_CurrentStateChanged); + media.MediaEnded += new RoutedEventHandler(media_MediaEnded); + media.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(media_MediaFailed); + media.MediaOpened += new RoutedEventHandler(media_MediaOpened); + media.MouseLeftButtonDown += new MouseButtonEventHandler(media_MouseLeftButtonDown); + CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering); + transportControls.Visibility = System.Windows.Visibility.Collapsed; + + // get parameters + if (initParams.ContainsKey("id")) + _htmlid = initParams["id"]; + if (initParams.ContainsKey("file")) + _mediaUrl = initParams["file"]; + if (initParams.ContainsKey("autoplay") && initParams["autoplay"] == "true") + _autoplay = true; + if (initParams.ContainsKey("debug") && initParams["debug"] == "true") + _debug = true; + if (initParams.ContainsKey("preload")) + _preload = initParams["preload"].ToLower(); + else + _preload = ""; + + if (!(new string[] { "none", "metadata", "auto" }).Contains(_preload)){ + _preload = "none"; + } + + if (initParams.ContainsKey("width")) + Int32.TryParse(initParams["width"], out _width); + if (initParams.ContainsKey("height")) + Int32.TryParse(initParams["height"], out _height); + if (initParams.ContainsKey("timerate")) + Int32.TryParse(initParams["timerrate"], out _timerRate); + if (initParams.ContainsKey("startvolume")) + Double.TryParse(initParams["startvolume"], out _volume); + + if (_timerRate == 0) + _timerRate = 250; + + // timer + _timer = new System.Windows.Threading.DispatcherTimer(); + _timer.Interval = new TimeSpan(0, 0, 0, 0, _timerRate); // 200 Milliseconds + _timer.Tick += new EventHandler(timer_Tick); + _timer.Stop(); + + //_mediaUrl = "http://local.mediaelement.com/media/jsaddington.mp4"; + //_autoplay = true; + + // set stage and media sizes + if (_width > 0) + LayoutRoot.Width = media.Width = this.Width = _width; + if (_height > 0) + LayoutRoot.Height = media.Height = this.Height = _height; + + // debug + textBox1.Visibility = (_debug) ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed; + textBox1.IsEnabled = false; + textBox1.Text = "id: " + _htmlid + "\n" + + "file: " + _mediaUrl + "\n"; + + + media.AutoPlay = _autoplay; + media.Volume = _volume; + if (!String.IsNullOrEmpty(_mediaUrl)) { + setSrc(_mediaUrl); + if (_autoplay || _preload != "none") + loadMedia(); + } + + media.MouseLeftButtonUp += new MouseButtonEventHandler(media_MouseLeftButtonUp); + + // full screen settings + Application.Current.Host.Content.FullScreenChanged += new EventHandler(DisplaySizeInformation); + Application.Current.Host.Content.Resized += new EventHandler(DisplaySizeInformation); + //FullscreenButton.Visibility = System.Windows.Visibility.Collapsed; + + // send out init call + //HtmlPage.Window.Invoke("html5_MediaPluginBridge_initPlugin", new object[] {_htmlid}); + try + { + HtmlPage.Window.Eval("mejs.MediaPluginBridge.initPlugin('" + _htmlid + "');"); + } + catch { } + } + + void media_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + switch (media.CurrentState) + { + case MediaElementState.Playing: + pauseMedia(); + break; + + case MediaElementState.Paused: + playMedia(); + break; + case MediaElementState.Stopped: + + break; + case MediaElementState.Buffering: + pauseMedia(); + break; + } + } + + void media_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { + SendEvent("click"); + } + + void media_MediaOpened(object sender, RoutedEventArgs e) { + + _videoWidth = Convert.ToInt32(media.NaturalVideoWidth); + _videoHeight = Convert.ToInt32(media.NaturalVideoHeight); + + TimeSpan duration = media.NaturalDuration.TimeSpan; + totalTimeTextBlock.Text = TimeSpanToString(duration); + UpdateVideoSize(); + + playPauseButton.IsChecked = true; + + SendEvent("loadedmetadata"); + } + + void timer_Tick(object sender, EventArgs e) { + SendEvent("timeupdate"); + } + + void StartTimer() { + _timer.Start(); + } + + void StopTimer() { + _timer.Stop(); + } + + void WriteDebug(string text) { + textBox1.Text += text + "\n"; + } + + void media_MediaFailed(object sender, ExceptionRoutedEventArgs e) { + SendEvent(e.ToString()); + } + + void media_MediaEnded(object sender, RoutedEventArgs e) { + _isEnded = true; + _isPaused = false; + SendEvent("ended"); + StopTimer(); + } + + void media_CurrentStateChanged(object sender, RoutedEventArgs e) { + + WriteDebug("state:" + media.CurrentState.ToString()); + + switch (media.CurrentState) + { + case MediaElementState.Opening: + SendEvent("loadstart"); + break; + case MediaElementState.Playing: + _isEnded = false; + _isPaused = false; + _isAttemptingToPlay = false; + StartTimer(); + + + SendEvent("play"); + SendEvent("playing"); + break; + + case MediaElementState.Paused: + _isEnded = false; + _isPaused = true; + + // special settings to allow play() to work + _isLoading = false; + WriteDebug("paused event, " + _isAttemptingToPlay); + if (_isAttemptingToPlay) { + this.playMedia(); + } + + StopTimer(); + SendEvent("paused"); + break; + case MediaElementState.Stopped: + _isEnded = false; + _isPaused = true; + StopTimer(); + SendEvent("paused"); + break; + case MediaElementState.Buffering: + SendEvent("progress"); + break; + } + + } + + void media_BufferingProgressChanged(object sender, RoutedEventArgs e) { + _bufferedTime = media.DownloadProgress * media.NaturalDuration.TimeSpan.TotalSeconds; + _bufferedBytes = media.BufferingProgress; + + + SendEvent("progress"); + } + + void media_DownloadProgressChanged(object sender, RoutedEventArgs e) { + _bufferedTime = media.DownloadProgress * media.NaturalDuration.TimeSpan.TotalSeconds; + _bufferedBytes = media.BufferingProgress; + + if (!_firedCanPlay) { + SendEvent("loadeddata"); + SendEvent("canplay"); + _firedCanPlay = true; + } + + SendEvent("progress"); + } + + + void SendEvent(string name) { + /* + * INVOKE + HtmlPage.Window.Invoke("html5_MediaPluginBridge_fireEvent", + _htmlid, + name, + @"'{" + + @"""name"": """ + name + @"""" + + @", ""currentTime"":" + (media.Position.TotalSeconds).ToString() + @"" + + @", ""duration"":" + (media.NaturalDuration.TimeSpan.TotalSeconds).ToString() + @"" + + @", ""paused"":" + (_isEnded).ToString().ToLower() + @"" + + @", ""muted"":" + (media.IsMuted).ToString().ToLower() + @"" + + @", ""ended"":" + (_isPaused).ToString().ToLower() + @"" + + @", ""volume"":" + (media.Volume).ToString() + @"" + + @", ""bufferedBytes"":" + (_bufferedBytes).ToString() + @"" + + @", ""bufferedTime"":" + (_bufferedTime).ToString() + @"" + + @"}'"); + */ + + /* + * EVAL + HtmlPage.Window.Eval("mejs.MediaPluginBridge.fireEvent('" + _htmlid + "','" + name + "'," + + @"{" + + @"""name"": """ + name + @"""" + + @", ""currentTime"":" + (media.Position.TotalSeconds).ToString() + @"" + + @", ""duration"":" + (media.NaturalDuration.TimeSpan.TotalSeconds).ToString() + @"" + + @", ""paused"":" + (_isEnded).ToString().ToLower() + @"" + + @", ""muted"":" + (media.IsMuted).ToString().ToLower() + @"" + + @", ""ended"":" + (_isPaused).ToString().ToLower() + @"" + + @", ""volume"":" + (media.Volume).ToString() + @"" + + @", ""bufferedBytes"":" + (_bufferedBytes).ToString() + @"" + + @", ""bufferedTime"":" + (_bufferedTime).ToString() + @"" + + @"});"); + * */ + + // setTimeout + try { + CultureInfo invCulture = CultureInfo.InvariantCulture; + + HtmlPage.Window.Invoke("setTimeout", "mejs.MediaPluginBridge.fireEvent('" + _htmlid + "','" + name + "'," + + @"{" + + @"""name"": """ + name + @"""" + + @", ""currentTime"":" + (media.Position.TotalSeconds).ToString(invCulture) + @"" + + @", ""duration"":" + (media.NaturalDuration.TimeSpan.TotalSeconds).ToString(invCulture) + @"" + + @", ""paused"":" + (_isPaused).ToString().ToLower() + @"" + + @", ""muted"":" + (media.IsMuted).ToString().ToLower() + @"" + + @", ""ended"":" + (_isEnded).ToString().ToLower() + @"" + + @", ""volume"":" + (media.Volume).ToString(invCulture) + @"" + + @", ""bufferedBytes"":" + (_bufferedBytes).ToString(invCulture) + @"" + + @", ""bufferedTime"":" + (_bufferedTime).ToString(invCulture) + @"" + + @", ""videoWidth"":" + (_videoWidth).ToString() + @"" + + @", ""videoHeight"":" + (_videoHeight).ToString() + @"" + + @"});", 0); + } catch { } + + } + + /* HTML5 wrapper methods */ + [ScriptableMember] + public void playMedia() { + WriteDebug("method:play " + media.CurrentState); + + // sometimes people forget to call load() first + if (_mediaUrl != "" && media.Source == null) { + _isAttemptingToPlay = true; + loadMedia(); + } + + // store and trigger with the state change above + if (media.CurrentState == MediaElementState.Closed && _isLoading) { + WriteDebug("storing _isAttemptingToPlay "); + _isAttemptingToPlay = true; + } + + media.Play(); + _isEnded = false; + _isPaused = false; + + playPauseButton.IsChecked = true; + + //StartTimer(); + } + + [ScriptableMember] + public void pauseMedia() { + WriteDebug("method:pause " + media.CurrentState); + + _isEnded = false; + _isPaused = true; + + media.Pause(); + StopTimer(); + playPauseButton.IsChecked = false; + } + + [ScriptableMember] + public void loadMedia() { + _isLoading = true; + _firedCanPlay = false; + + WriteDebug("method:load " + media.CurrentState); + WriteDebug(" - " + _mediaUrl.ToString()); + + media.Source = new Uri(_mediaUrl, UriKind.Absolute); + //media.Play(); + //media.Stop(); + } + + [ScriptableMember] + public void stopMedia() { + WriteDebug("method:stop " + media.CurrentState); + + _isEnded = true; + _isPaused = false; + + media.Stop(); + StopTimer(); + playPauseButton.IsChecked = false; + } + + [ScriptableMember] + public void setVolume(Double volume) { + WriteDebug("method:setvolume: " + volume.ToString()); + + media.Volume = volume; + + SendEvent("volumechange"); + } + + [ScriptableMember] + public void setMuted(bool isMuted) { + WriteDebug("method:setmuted: " + isMuted.ToString()); + + media.IsMuted = isMuted; + muteButton.IsChecked = isMuted; + SendEvent("volumechange"); + + } + + [ScriptableMember] + public void setCurrentTime(Double position) { + WriteDebug("method:setCurrentTime: " + position.ToString()); + + int milliseconds = Convert.ToInt32(position * 1000); + + SendEvent("seeking"); + media.Position = new TimeSpan(0, 0, 0, 0, milliseconds); + SendEvent("seeked"); + } + + [ScriptableMember] + public void setSrc(string url) { + _mediaUrl = url; + } + + [ScriptableMember] + public void setFullscreen(bool goFullscreen) { + + FullscreenButton.Visibility = System.Windows.Visibility.Visible; + } + + [ScriptableMember] + public void setVideoSize(int width, int height) { + this.Width = media.Width = width; + this.Height = media.Height = height; + } + + [ScriptableMember] + public void positionFullscreenButton(int x, int y,bool visibleAndAbove) { + if (visibleAndAbove) + { + //FullscreenButton.Visibility = System.Windows.Visibility.Collapsed; + } + else + { + //FullscreenButton.Visibility = System.Windows.Visibility.Visible; + } + } + + private void FullscreenButton_Click(object sender, RoutedEventArgs e) { + Application.Current.Host.Content.IsFullScreen = true; + //FullscreenButton.Visibility = System.Windows.Visibility.Collapsed; + } + + private void DisplaySizeInformation(Object sender, EventArgs e) { + this.Width = LayoutRoot.Width = media.Width = Application.Current.Host.Content.ActualWidth; + this.Height = LayoutRoot.Height = media.Height = Application.Current.Host.Content.ActualHeight; + + UpdateVideoSize(); + } + + + + + #region play button + + private void BigPlayButton_Click(object sender, RoutedEventArgs e) + { + playPauseButton.IsChecked = true; + PlayPauseButton_Click(sender, e); + } + + private void PlayPauseButton_Click(object sender, RoutedEventArgs e) + { + bigPlayButton.Visibility = Visibility.Collapsed; + + // this will be the toggle button state after the click has been processed + if (playPauseButton.IsChecked == true) + playMedia(); + else + pauseMedia(); + } + + + + #endregion + + #region timelineSlider + + private void Seek(double percentComplete) + { + if (duringTickEvent) + throw new Exception("Can't call Seek() now, you'll get an infinite loop"); + + TimeSpan duration = media.NaturalDuration.TimeSpan; + int newPosition = (int)(duration.TotalSeconds * percentComplete); + media.Position = new TimeSpan(0, 0, newPosition); + + // let the next CompositionTarget.Rendering take care of updating the text blocks + } + + private Slider GetSliderParent(object sender) + { + FrameworkElement element = (FrameworkElement)sender; + do + { + element = (FrameworkElement)VisualTreeHelper.GetParent(element); + } while (!(element is Slider)); + return (Slider)element; + } + + private void LeftTrack_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + FrameworkElement lefttrack = (sender as FrameworkElement).FindName("LeftTrack") as FrameworkElement; + FrameworkElement righttrack = (sender as FrameworkElement).FindName("RightTrack") as FrameworkElement; + double position = e.GetPosition(lefttrack).X; + double width = righttrack.TransformToVisual(lefttrack).Transform(new Point(righttrack.ActualWidth, righttrack.ActualHeight)).X; + double percent = position / width; + Slider slider = GetSliderParent(sender); + slider.Value = percent; + } + + private void HorizontalThumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) + { + if (GetSliderParent(sender) != timelineSlider) return; + + bool notPlaying = (media.CurrentState == MediaElementState.Paused + || media.CurrentState == MediaElementState.Stopped); + + if (notPlaying) + { + playVideoWhenSliderDragIsOver = false; + } + else + { + playVideoWhenSliderDragIsOver = true; + media.Pause(); + } + } + + private void HorizontalThumb_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e) + { + if (playVideoWhenSliderDragIsOver) + media.Play(); + } + + private void TimelineSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) + { + if (duringTickEvent) + return; + + Seek(timelineSlider.Value); + } + + #endregion + + #region updating current time + + private void CompositionTarget_Rendering(object sender, EventArgs e) + { + duringTickEvent = true; + + TimeSpan duration = media.NaturalDuration.TimeSpan; + if (duration.TotalSeconds != 0) + { + double percentComplete = (media.Position.TotalSeconds / duration.TotalSeconds); + timelineSlider.Value = percentComplete; + string text = TimeSpanToString(media.Position); + if (this.currentTimeTextBlock.Text != text) + this.currentTimeTextBlock.Text = text; + } + + duringTickEvent = false; + } + + private static string TimeSpanToString(TimeSpan time) + { + return string.Format("{0:00}:{1:00}", (time.Hours * 60) + time.Minutes, time.Seconds); + } + #endregion + + private void MuteButton_Click(object sender, RoutedEventArgs e) + { + //media.IsMuted = (bool)muteButton.IsChecked; + setMuted((bool)muteButton.IsChecked); + } + + #region fullscreen mode + + private void FullScreenButton_Click(object sender, RoutedEventArgs e) + { + var content = Application.Current.Host.Content; + content.IsFullScreen = !content.IsFullScreen; + } + + private void Content_FullScreenChanged(object sender, EventArgs e) + { + UpdateVideoSize(); + } + + private void UpdateVideoSize() + { + if (App.Current.Host.Content.IsFullScreen) + { + transportControls.Visibility = System.Windows.Visibility.Visible; + // mediaElement takes all available space + //VideoRow.Height = new GridLength(1, GridUnitType.Star); + //VideoColumn.Width = new GridLength(1, GridUnitType.Star); + } + else + { + transportControls.Visibility = System.Windows.Visibility.Collapsed; + // mediaElement is only as big as the source video + //VideoRow.Height = new GridLength(1, GridUnitType.Auto); + //VideoColumn.Width = new GridLength(1, GridUnitType.Auto); + } + } + + #endregion + } +} + diff --git a/files_videoviewer/src/silverlight/Properties/AppManifest.xml b/files_videoviewer/src/silverlight/Properties/AppManifest.xml new file mode 100644 index 000000000..6712a1178 --- /dev/null +++ b/files_videoviewer/src/silverlight/Properties/AppManifest.xml @@ -0,0 +1,6 @@ +<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" +> + <Deployment.Parts> + </Deployment.Parts> +</Deployment> diff --git a/files_videoviewer/src/silverlight/Properties/AssemblyInfo.cs b/files_videoviewer/src/silverlight/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8d8bbce31 --- /dev/null +++ b/files_videoviewer/src/silverlight/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SilverlightMediaElement")] +[assembly: AssemblyDescription("Silverlight player for http://mediaelementjs.com/")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("John Dyer")] +[assembly: AssemblyProduct("SilverlightMediaElement")] +[assembly: AssemblyCopyright("Copyright 2010 John Dyer")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("29fe7094-d10f-4359-8abb-1c76971133a4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/files_videoviewer/src/silverlight/SilverlightMediaElement.csproj b/files_videoviewer/src/silverlight/SilverlightMediaElement.csproj new file mode 100644 index 000000000..565830460 --- /dev/null +++ b/files_videoviewer/src/silverlight/SilverlightMediaElement.csproj @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.50727</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{CE832DD6-B659-4F3E-B49B-F297E2AC923A}</ProjectGuid> + <ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>SilverlightMediaElement</RootNamespace> + <AssemblyName>SilverlightMediaElement</AssemblyName> + <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion> + <SilverlightApplication>true</SilverlightApplication> + <SupportedCultures> + </SupportedCultures> + <XapOutputs>true</XapOutputs> + <GenerateSilverlightManifest>true</GenerateSilverlightManifest> + <XapFilename>silverlightmediaelement.xap</XapFilename> + <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate> + <SilverlightAppEntry>SilverlightMediaElement.App</SilverlightAppEntry> + <TestPageFileName>SilverlightMediaElementTestPage.html</TestPageFileName> + <CreateTestPage>true</CreateTestPage> + <ValidateXaml>true</ValidateXaml> + <EnableOutOfBrowser>false</EnableOutOfBrowser> + <OutOfBrowserSettingsFile>Properties\OutOfBrowserSettings.xml</OutOfBrowserSettingsFile> + <UsePlatformExtensions>false</UsePlatformExtensions> + <ThrowErrorsInValidation>true</ThrowErrorsInValidation> + <LinkedServerProject> + </LinkedServerProject> + <SignManifests>false</SignManifests> + <TargetFrameworkProfile /> + </PropertyGroup> + <!-- This property group is only here to support building this project using the + MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs + to set the TargetFrameworkVersion to v3.5 --> + <PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'"> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\..\build\</OutputPath> + <DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants> + <NoStdLib>true</NoStdLib> + <NoConfig>true</NoConfig> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>..\..\src\</OutputPath> + <DefineConstants>TRACE;SILVERLIGHT</DefineConstants> + <NoStdLib>true</NoStdLib> + <NoConfig>true</NoConfig> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <DocumentationFile> + </DocumentationFile> + </PropertyGroup> + <ItemGroup> + <Reference Include="mscorlib" /> + <Reference Include="System.Windows" /> + <Reference Include="system" /> + <Reference Include="System.Core" /> + <Reference Include="System.Net" /> + <Reference Include="System.Xml" /> + <Reference Include="System.Windows.Browser" /> + </ItemGroup> + <ItemGroup> + <Compile Include="App.xaml.cs"> + <DependentUpon>App.xaml</DependentUpon> + </Compile> + <Compile Include="MainPage.xaml.cs"> + <DependentUpon>MainPage.xaml</DependentUpon> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </ApplicationDefinition> + <Page Include="MainPage.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + </ItemGroup> + <ItemGroup> + <None Include="Properties\AppManifest.xml" /> + </ItemGroup> + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ProjectExtensions> + <VisualStudio> + <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}"> + <SilverlightProjectProperties /> + </FlavorProperties> + </VisualStudio> + </ProjectExtensions> +</Project>
\ No newline at end of file diff --git a/files_videoviewer/src/silverlight/SilverlightMediaElement.csproj.user b/files_videoviewer/src/silverlight/SilverlightMediaElement.csproj.user new file mode 100644 index 000000000..2fe79f9ea --- /dev/null +++ b/files_videoviewer/src/silverlight/SilverlightMediaElement.csproj.user @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectView>ShowAllFiles</ProjectView> + </PropertyGroup> + <ProjectExtensions> + <VisualStudio> + <FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}"> + <SilverlightProjectProperties> + <StartPageUrl> + </StartPageUrl> + <StartAction>DynamicPage</StartAction> + <AspNetDebugging>True</AspNetDebugging> + <NativeDebugging>False</NativeDebugging> + <SQLDebugging>False</SQLDebugging> + <ExternalProgram> + </ExternalProgram> + <StartExternalURL> + </StartExternalURL> + <StartCmdLineArguments> + </StartCmdLineArguments> + <StartWorkingDirectory> + </StartWorkingDirectory> + <ShowWebRefOnDebugPrompt>True</ShowWebRefOnDebugPrompt> + <OutOfBrowserProjectToDebug> + </OutOfBrowserProjectToDebug> + <ShowRiaSvcsOnDebugPrompt>True</ShowRiaSvcsOnDebugPrompt> + </SilverlightProjectProperties> + </FlavorProperties> + </VisualStudio> + </ProjectExtensions> +</Project>
\ No newline at end of file diff --git a/files_videoviewer/src/silverlight/SilverlightMediaElement.sln b/files_videoviewer/src/silverlight/SilverlightMediaElement.sln new file mode 100644 index 000000000..b3110c843 --- /dev/null +++ b/files_videoviewer/src/silverlight/SilverlightMediaElement.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightMediaElement", "SilverlightMediaElement.csproj", "{CE832DD6-B659-4F3E-B49B-F297E2AC923A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CE832DD6-B659-4F3E-B49B-F297E2AC923A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE832DD6-B659-4F3E-B49B-F297E2AC923A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE832DD6-B659-4F3E-B49B-F297E2AC923A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE832DD6-B659-4F3E-B49B-F297E2AC923A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal |