/sites/all/libraries/mediaelement/src/flash/htmlelements/VideoElement.as
ActionScript | 519 lines | 391 code | 93 blank | 35 comment | 69 complexity | d9a7d7f1a11ec00396ee6cc4f0ac8874 MD5 | raw file
- 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: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):void {
- _bytesLoaded = _stream.bytesLoaded;
- _bytesTotal = _stream.bytesTotal;
- if (_hasStartedPlaying && !_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;
- if (_isEnded)
- sendEvent(HtmlMediaEvent.ENDED);
- break;
- case "NetStream.Buffer.Full":
- _bytesLoaded = _stream.bytesLoaded;
- _bytesTotal = _stream.bytesTotal;
- _bufferEmpty = false;
- sendEvent(HtmlMediaEvent.PROGRESS);
- break;
- case "NetConnection.Connect.Success":
- connectStream();
- sendEvent(HtmlMediaEvent.LOADEDDATA);
- sendEvent(HtmlMediaEvent.CANPLAY);
- 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":
- _timer.stop();
- _isEnded = true;
- _isPaused = true;
- sendEvent(HtmlMediaEvent.PAUSE);
- if (_bufferEmpty)
- sendEvent(HtmlMediaEvent.ENDED);
- 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();
- }
- _duration = 0;
- _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 ) {
- if( !_playWhenConnected ) {
- _playWhenConnected = true;
- load();
- }
- return;
- }
- if (_hasStartedPlaying) {
- if (_isPaused) {
- if (_isEnded) {
- setCurrentTime(0);
- _isEnded = false;
- }
- _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 next
- // event listener
- }
- }
- public function pause():void {
- if (_stream == null)
- return;
- if (_bytesLoaded == _bytesTotal) {
- _timer.stop();
- }
- _stream.pause();
- _isPaused = true;
- sendEvent(HtmlMediaEvent.PAUSE);
- }
- public function stop():void {
- if (_stream == null)
- return;
- _timer.stop();
- _stream.close();
- _isPaused = false;
- 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);
- }
- }
- // Seems NetStream supports seek? but before metadata is loaded?
- public function seekLimit():Number {
- return _duration == 0 ? NaN : _duration;
- }
- 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):void {
- // 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):Object {
- 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;
- }
- }
- }