/**
* Copyright adamh ( http://wonderfl.net/user/adamh )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/9fMg
*/
package {
//START FlashMediaElement.as
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;
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;
_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'])) : "";
_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 = false;
_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;
// 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 = _fullscreenIcon.x - _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 {
var fullscreen;
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
}
//END FlashMediaElement.as
}
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";
}
//START IMediaElement.as
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;
}
//END IMediaElement.as
//START AudioElement.as
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...)
*/
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);
}
}
//END AudioElement.as
//START VideoElement.as
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;
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;
}
}
//END VideoElement.as
//START YouTubeElement.as
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;
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() {
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);
}
}
//END YouTubeElement.as