PageRenderTime 58ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/media-element/src/flash/htmlelements/VideoElement.as

https://gitlab.com/Gashler/sg
ActionScript | 519 lines | 391 code | 93 blank | 35 comment | 69 complexity | d9a7d7f1a11ec00396ee6cc4f0ac8874 MD5 | raw file
  1. package htmlelements {
  2. import flash.display.Sprite;
  3. import flash.events.*;
  4. import flash.net.NetConnection;
  5. import flash.net.NetStream;
  6. import flash.media.Video;
  7. import flash.media.SoundTransform;
  8. import flash.utils.Timer;
  9. import FlashMediaElement;
  10. import HtmlMediaEvent;
  11. public class VideoElement extends Sprite implements IMediaElement {
  12. private var _currentUrl:String = "";
  13. private var _autoplay:Boolean = true;
  14. private var _preload:String = "";
  15. private var _isPreloading:Boolean = false;
  16. private var _connection:NetConnection;
  17. private var _stream:NetStream;
  18. private var _video:Video;
  19. private var _element:FlashMediaElement;
  20. private var _soundTransform:SoundTransform;
  21. private var _oldVolume:Number = 1;
  22. // event values
  23. private var _duration:Number = 0;
  24. private var _framerate:Number;
  25. private var _isPaused:Boolean = true;
  26. private var _isEnded:Boolean = false;
  27. private var _volume:Number = 1;
  28. private var _isMuted:Boolean = false;
  29. private var _bytesLoaded:Number = 0;
  30. private var _bytesTotal:Number = 0;
  31. private var _bufferedTime:Number = 0;
  32. private var _bufferEmpty:Boolean = false;
  33. private var _bufferingChanged:Boolean = false;
  34. private var _seekOffset:Number = 0;
  35. private var _videoWidth:Number = -1;
  36. private var _videoHeight:Number = -1;
  37. private var _timer:Timer;
  38. private var _isRTMP:Boolean = false;
  39. private var _streamer:String = "";
  40. private var _isConnected:Boolean = false;
  41. private var _playWhenConnected:Boolean = false;
  42. private var _hasStartedPlaying:Boolean = false;
  43. private var _parentReference:Object;
  44. private var _pseudoStreamingEnabled:Boolean = false;
  45. private var _pseudoStreamingStartQueryParam:String = "start";
  46. public function setReference(arg:Object):void {
  47. _parentReference = arg;
  48. }
  49. public function setSize(width:Number, height:Number):void {
  50. _video.width = width;
  51. _video.height = height;
  52. }
  53. public function setPseudoStreaming(enablePseudoStreaming:Boolean):void {
  54. _pseudoStreamingEnabled = enablePseudoStreaming;
  55. }
  56. public function setPseudoStreamingStartParam(pseudoStreamingStartQueryParam:String):void {
  57. _pseudoStreamingStartQueryParam = pseudoStreamingStartQueryParam;
  58. }
  59. public function get video():Video {
  60. return _video;
  61. }
  62. public function get videoHeight():Number {
  63. return _videoHeight;
  64. }
  65. public function get videoWidth():Number {
  66. return _videoWidth;
  67. }
  68. public function duration():Number {
  69. return _duration;
  70. }
  71. public function currentProgress():Number {
  72. if(_stream != null) {
  73. return Math.round(_stream.bytesLoaded/_stream.bytesTotal*100);
  74. } else {
  75. return 0;
  76. }
  77. }
  78. public function currentTime():Number {
  79. var currentTime:Number = 0;
  80. if (_stream != null) {
  81. currentTime = _stream.time;
  82. if (_pseudoStreamingEnabled) {
  83. currentTime += _seekOffset;
  84. }
  85. }
  86. return currentTime;
  87. }
  88. // (1) load()
  89. // calls _connection.connect();
  90. // waits for NetConnection.Connect.Success
  91. // _stream gets created
  92. public function VideoElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number, streamer:String) {
  93. _element = element;
  94. _autoplay = autoplay;
  95. _volume = startVolume;
  96. _preload = preload;
  97. _streamer = streamer;
  98. _video = new Video();
  99. addChild(_video);
  100. _connection = new NetConnection();
  101. _connection.client = { onBWDone: function():void{} };
  102. _connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
  103. _connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
  104. //_connection.connect(null);
  105. _timer = new Timer(timerRate);
  106. _timer.addEventListener("timer", timerHandler);
  107. }
  108. private function timerHandler(e:TimerEvent):void {
  109. _bytesLoaded = _stream.bytesLoaded;
  110. _bytesTotal = _stream.bytesTotal;
  111. if (_hasStartedPlaying && !_isPaused) {
  112. sendEvent(HtmlMediaEvent.TIMEUPDATE);
  113. }
  114. //trace("bytes", _bytesLoaded, _bytesTotal);
  115. if (_bytesLoaded < _bytesTotal) {
  116. sendEvent(HtmlMediaEvent.PROGRESS);
  117. }
  118. }
  119. // internal events
  120. private function netStatusHandler(event:NetStatusEvent):void {
  121. trace("netStatus", event.info.code);
  122. switch (event.info.code) {
  123. case "NetStream.Buffer.Empty":
  124. _bufferEmpty = true;
  125. if (_isEnded)
  126. sendEvent(HtmlMediaEvent.ENDED);
  127. break;
  128. case "NetStream.Buffer.Full":
  129. _bytesLoaded = _stream.bytesLoaded;
  130. _bytesTotal = _stream.bytesTotal;
  131. _bufferEmpty = false;
  132. sendEvent(HtmlMediaEvent.PROGRESS);
  133. break;
  134. case "NetConnection.Connect.Success":
  135. connectStream();
  136. sendEvent(HtmlMediaEvent.LOADEDDATA);
  137. sendEvent(HtmlMediaEvent.CANPLAY);
  138. break;
  139. case "NetStream.Play.StreamNotFound":
  140. trace("Unable to locate video");
  141. break;
  142. // STREAM
  143. case "NetStream.Play.Start":
  144. _isPaused = false;
  145. sendEvent(HtmlMediaEvent.LOADEDDATA);
  146. sendEvent(HtmlMediaEvent.CANPLAY);
  147. if (!_isPreloading) {
  148. sendEvent(HtmlMediaEvent.PLAY);
  149. sendEvent(HtmlMediaEvent.PLAYING);
  150. }
  151. _timer.start();
  152. break;
  153. case "NetStream.Seek.Notify":
  154. sendEvent(HtmlMediaEvent.SEEKED);
  155. break;
  156. case "NetStream.Pause.Notify":
  157. _isPaused = true;
  158. sendEvent(HtmlMediaEvent.PAUSE);
  159. break;
  160. case "NetStream.Play.Stop":
  161. _timer.stop();
  162. _isEnded = true;
  163. _isPaused = true;
  164. sendEvent(HtmlMediaEvent.PAUSE);
  165. if (_bufferEmpty)
  166. sendEvent(HtmlMediaEvent.ENDED);
  167. break;
  168. }
  169. }
  170. private function securityErrorHandler(event:SecurityErrorEvent):void {
  171. trace("securityErrorHandler: " + event);
  172. }
  173. private function asyncErrorHandler(event:AsyncErrorEvent):void {
  174. // ignore AsyncErrorEvent events.
  175. }
  176. private function onMetaDataHandler(info:Object):void {
  177. // Only set the duration when we first load the video
  178. if (_duration == 0) {
  179. _duration = info.duration;
  180. }
  181. _framerate = info.framerate;
  182. _videoWidth = info.width;
  183. _videoHeight = info.height;
  184. // set size?
  185. sendEvent(HtmlMediaEvent.LOADEDMETADATA);
  186. if (_isPreloading) {
  187. _stream.pause();
  188. _isPaused = true;
  189. _isPreloading = false;
  190. sendEvent(HtmlMediaEvent.PROGRESS);
  191. sendEvent(HtmlMediaEvent.TIMEUPDATE);
  192. }
  193. }
  194. // interface members
  195. public function setSrc(url:String):void {
  196. if (_isConnected && _stream) {
  197. // stop and restart
  198. _stream.pause();
  199. }
  200. _duration = 0;
  201. _currentUrl = url;
  202. _isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//) || _streamer != "";
  203. _isConnected = false;
  204. _hasStartedPlaying = false;
  205. }
  206. public function load():void {
  207. // disconnect existing stream and connection
  208. if (_isConnected && _stream) {
  209. _stream.pause();
  210. _stream.close();
  211. _connection.close();
  212. }
  213. _isConnected = false;
  214. _isPreloading = false;
  215. _isEnded = false;
  216. _bufferEmpty = false;
  217. // start new connection
  218. if (_isRTMP) {
  219. var rtmpInfo:Object = parseRTMP(_currentUrl);
  220. if (_streamer != "") {
  221. rtmpInfo.server = _streamer;
  222. rtmpInfo.stream = _currentUrl;
  223. }
  224. _connection.connect(rtmpInfo.server);
  225. } else {
  226. _connection.connect(null);
  227. }
  228. // in a few moments the "NetConnection.Connect.Success" event will fire
  229. // and call createConnection which finishes the "load" sequence
  230. sendEvent(HtmlMediaEvent.LOADSTART);
  231. }
  232. private function connectStream():void {
  233. trace("connectStream");
  234. _stream = new NetStream(_connection);
  235. // explicitly set the sound since it could have come before the connection was made
  236. _soundTransform = new SoundTransform(_volume);
  237. _stream.soundTransform = _soundTransform;
  238. // set the buffer to ensure nice playback
  239. _stream.bufferTime = 1;
  240. _stream.bufferTimeMax = 3;
  241. _stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection
  242. _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  243. var customClient:Object = new Object();
  244. customClient.onMetaData = onMetaDataHandler;
  245. _stream.client = customClient;
  246. _video.attachNetStream(_stream);
  247. // start downloading without playing )based on preload and play() hasn't been called)
  248. // I wish flash had a load() command to make this less awkward
  249. if (_preload != "none" && !_playWhenConnected) {
  250. _isPaused = true;
  251. //stream.bufferTime = 20;
  252. _stream.play(getCurrentUrl(0), 0, 0);
  253. _stream.pause();
  254. _isPreloading = true;
  255. //_stream.pause();
  256. //
  257. //sendEvent(HtmlMediaEvent.PAUSE); // have to send this because the "playing" event gets sent via event handlers
  258. }
  259. _isConnected = true;
  260. if (_playWhenConnected && !_hasStartedPlaying) {
  261. play();
  262. _playWhenConnected = false;
  263. }
  264. }
  265. public function play():void {
  266. if (!_hasStartedPlaying && !_isConnected ) {
  267. if( !_playWhenConnected ) {
  268. _playWhenConnected = true;
  269. load();
  270. }
  271. return;
  272. }
  273. if (_hasStartedPlaying) {
  274. if (_isPaused) {
  275. if (_isEnded) {
  276. setCurrentTime(0);
  277. _isEnded = false;
  278. }
  279. _stream.resume();
  280. _timer.start();
  281. _isPaused = false;
  282. sendEvent(HtmlMediaEvent.PLAY);
  283. sendEvent(HtmlMediaEvent.PLAYING);
  284. }
  285. } else {
  286. if (_isRTMP) {
  287. var rtmpInfo:Object = parseRTMP(_currentUrl);
  288. _stream.play(rtmpInfo.stream);
  289. } else {
  290. _stream.play(getCurrentUrl(0));
  291. }
  292. _timer.start();
  293. _isPaused = false;
  294. _hasStartedPlaying = true;
  295. // don't toss play/playing events here, because we haven't sent a
  296. // canplay / loadeddata event yet. that'll be handled in the next
  297. // event listener
  298. }
  299. }
  300. public function pause():void {
  301. if (_stream == null)
  302. return;
  303. if (_bytesLoaded == _bytesTotal) {
  304. _timer.stop();
  305. }
  306. _stream.pause();
  307. _isPaused = true;
  308. sendEvent(HtmlMediaEvent.PAUSE);
  309. }
  310. public function stop():void {
  311. if (_stream == null)
  312. return;
  313. _timer.stop();
  314. _stream.close();
  315. _isPaused = false;
  316. sendEvent(HtmlMediaEvent.STOP);
  317. }
  318. public function setCurrentTime(pos:Number):void {
  319. if (_stream == null) {
  320. return;
  321. }
  322. // Calculate the position of the buffered video
  323. var bufferPosition:Number = _bytesLoaded / _bytesTotal * _duration;
  324. if (_pseudoStreamingEnabled) {
  325. sendEvent(HtmlMediaEvent.SEEKING);
  326. // Normal seek if it is in buffer and this is the first seek
  327. if (pos < bufferPosition && _seekOffset == 0) {
  328. _stream.seek(pos);
  329. }
  330. else {
  331. // Uses server-side pseudo-streaming to seek
  332. _stream.play(getCurrentUrl(pos));
  333. _seekOffset = pos;
  334. }
  335. }
  336. else {
  337. sendEvent(HtmlMediaEvent.SEEKING);
  338. _stream.seek(pos);
  339. }
  340. if (!_isEnded) {
  341. sendEvent(HtmlMediaEvent.TIMEUPDATE);
  342. }
  343. }
  344. // Seems NetStream supports seek? but before metadata is loaded?
  345. public function seekLimit():Number {
  346. return _duration == 0 ? NaN : _duration;
  347. }
  348. public function setVolume(volume:Number):void {
  349. if (_stream != null) {
  350. _soundTransform = new SoundTransform(volume);
  351. _stream.soundTransform = _soundTransform;
  352. }
  353. _volume = volume;
  354. _isMuted = (_volume == 0);
  355. sendEvent(HtmlMediaEvent.VOLUMECHANGE);
  356. }
  357. public function getVolume():Number {
  358. if(_isMuted) {
  359. return 0;
  360. } else {
  361. return _volume;
  362. }
  363. }
  364. public function setMuted(muted:Boolean):void {
  365. if (_isMuted == muted)
  366. return;
  367. if (muted) {
  368. _oldVolume = (_stream == null) ? _oldVolume : _stream.soundTransform.volume;
  369. setVolume(0);
  370. } else {
  371. setVolume(_oldVolume);
  372. }
  373. _isMuted = muted;
  374. }
  375. private function sendEvent(eventName:String):void {
  376. // calculate this to mimic HTML5
  377. _bufferedTime = _bytesLoaded / _bytesTotal * _duration;
  378. // build JSON
  379. var values:String =
  380. "duration:" + _duration +
  381. ",framerate:" + _framerate +
  382. ",currentTime:" + currentTime() +
  383. ",muted:" + _isMuted +
  384. ",paused:" + _isPaused +
  385. ",ended:" + _isEnded +
  386. ",volume:" + _volume +
  387. ",src:\"" + _currentUrl + "\"" +
  388. ",bytesTotal:" + _bytesTotal +
  389. ",bufferedBytes:" + _bytesLoaded +
  390. ",bufferedTime:" + _bufferedTime +
  391. ",videoWidth:" + _videoWidth +
  392. ",videoHeight:" + _videoHeight +
  393. "";
  394. _element.sendEvent(eventName, values);
  395. }
  396. private function parseRTMP(url:String):Object {
  397. var match:Array = url.match(/(.*)\/((flv|mp4|mp3):.*)/);
  398. var rtmpInfo:Object = {
  399. server: null,
  400. stream: null
  401. };
  402. if (match) {
  403. rtmpInfo.server = match[1];
  404. rtmpInfo.stream = match[2];
  405. }
  406. else {
  407. rtmpInfo.server = url.replace(/\/[^\/]+$/,"/");
  408. rtmpInfo.stream = url.split("/").pop();
  409. }
  410. trace("parseRTMP - server: " + rtmpInfo.server + " stream: " + rtmpInfo.stream);
  411. return rtmpInfo;
  412. }
  413. private function getCurrentUrl(pos:Number):String {
  414. var url:String = _currentUrl;
  415. if (_pseudoStreamingEnabled) {
  416. if (url.indexOf('?') > -1) {
  417. url = url + '&' + _pseudoStreamingStartQueryParam + '=' + pos;
  418. }
  419. else {
  420. url = url + '?' + _pseudoStreamingStartQueryParam + '=' + pos;
  421. }
  422. }
  423. return url;
  424. }
  425. }
  426. }