Mercurial > hg > env-test-daniele
diff johndyer-mediaelement-13fa20a/src/flash/htmlelements/VideoElement.as @ 0:032bc65ebafc
added core components
author | George Fazekas <gyorgy.fazekas@eecs.qmul.ac.uk> |
---|---|
date | Wed, 06 Mar 2013 15:45:48 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/johndyer-mediaelement-13fa20a/src/flash/htmlelements/VideoElement.as Wed Mar 06 15:45:48 2013 +0000 @@ -0,0 +1,384 @@ +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 _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 _videoWidth:Number = -1; + private var _videoHeight:Number = -1; + + private var _timer:Timer; + + private var _isRTMP:Boolean = false; + private var _isConnected:Boolean = false; + private var _playWhenConnected:Boolean = false; + private var _hasStartedPlaying:Boolean = false; + + 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 currentTime():Number { + if (_stream != null) { + return _stream.time; + } else { + return 0; + } + } + + // (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) + { + _element = element; + _autoplay = autoplay; + _volume = startVolume; + _preload = preload; + + _video = new Video(); + addChild(_video); + + _connection = new NetConnection(); + _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; + + 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); + 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 { + _duration = info.duration; + _framerate = info.framerate; + _videoWidth = info.width; + _videoHeight = info.height; + + // set size? + + sendEvent(HtmlMediaEvent.LOADEDMETADATA); + } + + + + + // 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)?\:\/\//); + _isConnected = false; + _hasStartedPlaying = false; + } + + public function load():void { + // disconnect existing stream and connection + if (_isConnected && _stream) { + _stream.pause(); + _stream.close(); + _connection.close(); + } + _isConnected = false; + + // start new connection + if (_isRTMP) { + _connection.connect(_currentUrl.replace(/\/[^\/]+$/,"/")); + } 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; + + _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) { + _stream.play(_currentUrl, 0, 0); + + _stream.pause(); + _isPaused = true; + 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) { + _stream.play(_currentUrl.split("/").pop()); + } else { + _stream.play(_currentUrl); + } + _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; + _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; + + sendEvent(HtmlMediaEvent.SEEKING); + _stream.seek(pos); + 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 setMuted(muted:Boolean):void { + + if (_isMuted == muted) + return; + + if (muted) { + _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:" + (_stream != null ? _stream.time : 0) + + ",muted:" + _isMuted + + ",paused:" + _isPaused + + ",ended:" + _isEnded + + ",volume:" + _volume + + ",src:\"" + _currentUrl + "\"" + + ",bytesTotal:" + _bytesTotal + + ",bufferedBytes:" + _bytesLoaded + + ",bufferedTime:" + _bufferedTime + + ",videoWidth:" + _videoWidth + + ",videoHeight:" + _videoHeight + + ""; + + _element.sendEvent(eventName, values); + } + } +} \ No newline at end of file