PageRenderTime 66ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/mediaplayers/source/temple/mediaplayers/video/players/VideoPlayer.as

http://templelibrary.googlecode.com/
ActionScript | 1541 lines | 1028 code | 181 blank | 332 comment | 178 complexity | ad418bc827658dd62bebe637d083ba6a MD5 | raw file
  1. /*
  2. * Temple Library for ActionScript 3.0
  3. * Copyright Š MediaMonks B.V.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. All advertising materials mentioning features or use of this software
  14. * must display the following acknowledgement:
  15. * This product includes software developed by MediaMonks B.V.
  16. * 4. Neither the name of MediaMonks B.V. nor the
  17. * names of its contributors may be used to endorse or promote products
  18. * derived from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY MEDIAMONKS B.V. ''AS IS'' AND ANY
  21. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  22. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  23. * DISCLAIMED. IN NO EVENT SHALL MEDIAMONKS B.V. BE LIABLE FOR ANY
  24. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  27. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. *
  32. * Note: This license does not apply to 3rd party classes inside the Temple
  33. * repository with their own license!
  34. */
  35. package temple.mediaplayers.video.players
  36. {
  37. import temple.common.enum.Align;
  38. import flash.display.Bitmap;
  39. import flash.display.BitmapData;
  40. import flash.events.AsyncErrorEvent;
  41. import flash.events.Event;
  42. import flash.events.IOErrorEvent;
  43. import flash.events.NetStatusEvent;
  44. import flash.events.SecurityErrorEvent;
  45. import flash.geom.Rectangle;
  46. import flash.media.SoundTransform;
  47. import flash.media.Video;
  48. import flash.net.ObjectEncoding;
  49. import flash.text.TextField;
  50. import flash.text.TextFieldAutoSize;
  51. import temple.common.enum.ScaleMode;
  52. import temple.common.events.SoundEvent;
  53. import temple.common.events.StatusEvent;
  54. import temple.common.interfaces.IHasBackground;
  55. import temple.core.debug.addToDebugManager;
  56. import temple.core.display.CoreSprite;
  57. import temple.core.errors.TempleError;
  58. import temple.core.errors.throwError;
  59. import temple.mediaplayers.players.PlayerEvent;
  60. import temple.mediaplayers.players.PlayerStatus;
  61. import temple.mediaplayers.video.cuepoints.CuePointEvent;
  62. import temple.mediaplayers.video.cuepoints.VideoCuePoint;
  63. import temple.mediaplayers.video.metadata.VideoMetaData;
  64. import temple.mediaplayers.video.metadata.VideoMetaDataEvent;
  65. import temple.mediaplayers.video.net.NetStatusEventInfoCodes;
  66. import temple.mediaplayers.video.net.VideoNetConnection;
  67. import temple.mediaplayers.video.net.VideoNetStream;
  68. import temple.utils.FrameDelay;
  69. import temple.utils.TimeUtils;
  70. /**
  71. * Dispatched when the status is changed
  72. * @eventType temple.status.StatusEvent.STATUS_CHANGE
  73. */
  74. [Event(name = "StatusEvent.statusChange", type = "temple.common.events.StatusEvent")]
  75. /**
  76. * @eventType temple.media.video.players.VideoPlayerEvent.BUFFER_EMPTY
  77. */
  78. [Event(name = "VideoPlayerEvent.bufferEmpty", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  79. /**
  80. * @eventType temple.media.video.players.VideoPlayerEvent.BUFFER_FLUSH
  81. */
  82. [Event(name = "VideoPlayerEvent.bufferFlush", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  83. /**
  84. * @eventType temple.media.video.players.VideoPlayerEvent.MOVIE_NOTFOUND
  85. */
  86. [Event(name = "VideoPlayerEvent.movieNotFound", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  87. /**
  88. * @eventType temple.media.video.players.VideoPlayerEvent.SECURITY_ERROR
  89. */
  90. [Event(name = "VideoPlayerEvent.securityError", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  91. /**
  92. * @eventType temple.media.video.players.VideoPlayerEvent.SEEK_INVALID
  93. */
  94. [Event(name = "VideoPlayerEvent.seekInvalid", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  95. /**
  96. * @eventType temple.media.video.players.VideoPlayerEvent.MOVIE_LOADED
  97. */
  98. [Event(name = "VideoPlayerEvent.movieLoaded", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  99. /**
  100. * @eventType temple.media.video.players.VideoPlayerEvent.SEEK_NOTIFY
  101. */
  102. [Event(name = "VideoPlayerEvent.seekNotify", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  103. /**
  104. * @eventType temple.media.video.players.VideoPlayerEvent.LOAD_READY
  105. */
  106. [Event(name = "VideoPlayerEvent.loadReady", type = "temple.mediaplayers.video.players.VideoPlayerEvent")]
  107. /**
  108. * @eventType temple.media.sound.SoundEvent.VOLUME_CHANGE
  109. */
  110. [Event(name = "SoundEvent.volumeChange", type = "temple.common.events.SoundEvent")]
  111. /**
  112. * @eventType flash.events.NetStatusEvent.NET_STATUS
  113. */
  114. [Event(name = "netStatus", type = "flash.events.NetStatusEvent")]
  115. /**
  116. * @eventType temple.media.video.metadata.VideoMetaDataEvent.METADATA
  117. */
  118. [Event(name = "VideoMetaDataEvent.metadata", type = "temple.mediaplayers.video.metadata.VideoMetaDataEvent")]
  119. /**
  120. * @eventType temple.media.video.cuepoints.CuePointEvent.CUEPOINT
  121. */
  122. [Event(name = "CuePointEvent.cuepoint", type = "temple.mediaplayers.video.cuepoints.CuePointEvent")]
  123. /**
  124. * Class for playing video. The VideoPlayer can handle progressive download video files, like flv or f4v
  125. * and streaming video, like RTMP or RTMPT.
  126. *
  127. * @example
  128. * <listing version="3.0">
  129. * // create videoplayer
  130. * var video:VideoPlayer = new VideoPlayer(324, 182);
  131. * // add videoplayer to stage or displaylist
  132. * addChild(video);
  133. * // position videoplayer
  134. * video.x = 20;
  135. * video.y = 20;
  136. * // start video
  137. * video.playMovie(url);
  138. * </listing>
  139. *
  140. * @includeExample VideoPlayerExample.as
  141. *
  142. * @author Thijs Broerse
  143. */
  144. public class VideoPlayer extends CoreSprite implements IVideoPlayer, IHasBackground
  145. {
  146. /** @private */
  147. protected var _netStream:VideoNetStream;
  148. /** @private */
  149. private var _metaData:VideoMetaData;
  150. // if pausing when status is between connected<>playing, the video is paused but the NetStream.Play.Start is still broadcasted (so the UI is updated)
  151. protected var _delayedPause:Boolean;
  152. private var _netConnection:VideoNetConnection;
  153. private var _cuePoint:VideoCuePoint;
  154. private var _video:Video;
  155. private var _videoPath:String;
  156. private var _status:String;
  157. private var _netConnectionCommand:String;
  158. private var _volume:Number = 1;
  159. private var _debug:Boolean;
  160. private var _isLoaded:Boolean;
  161. private var _txtDebug:TextField;
  162. private var _bytesLoaded:Number;
  163. private var _bytesTotal:Number;
  164. private var _isClosed:Boolean;
  165. private var _width:Number;
  166. private var _height:Number;
  167. private var _scaleMode:String = ScaleMode.EXACT_FIT;
  168. private var _upscaleEnabled:Boolean = true;
  169. private var _align:String;
  170. private var _playAfterLoaded:Boolean;
  171. private var _autoRewind:Boolean;
  172. private var _bufferTime:Number;
  173. private var _screenShot:BitmapData;
  174. private var _rtmpConnection:String;
  175. private var _background:Boolean;
  176. private var _backgroundColor:uint = 0;
  177. private var _backgroundAlpha:Number = 1;
  178. /**
  179. * Create a new video player
  180. * @param width The width of the video
  181. * @param height The height of the video
  182. * @param smoothing (optional) set video to smooting when scaled, default
  183. * @param scaleMode (optional) indicates how the player should scale the video, default: 'exactFit'
  184. * @param debug (optional) indicates if debug info should be logged
  185. */
  186. public function VideoPlayer(width:Number = NaN, height:Number = NaN, smoothing:Boolean = false, scaleMode:String = ScaleMode.EXACT_FIT, debug:Boolean = false)
  187. {
  188. this.toStringProps.push('videoPath', 'status');
  189. if (isNaN(width) && super.width > 0)
  190. {
  191. this._width = super.width;
  192. }
  193. else
  194. {
  195. this._width = width;
  196. }
  197. if (isNaN(height) && super.height > 0)
  198. {
  199. this._height = super.height;
  200. }
  201. else
  202. {
  203. this._height = height;
  204. }
  205. if (isNaN(this._width) || isNaN(this._height)) throwError(new TempleError(this, "Video dimensions are not set, please fill in width and height"));
  206. this._isLoaded = false;
  207. this._isClosed = true;
  208. this._netConnection = new VideoNetConnection();
  209. this._netConnection.addEventListener(NetStatusEvent.NET_STATUS, this.handleNetStatusEvent);
  210. this._netConnection.objectEncoding = ObjectEncoding.AMF0;
  211. this._netConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.handleSecurityError);
  212. this._netConnection.addEventListener(IOErrorEvent.IO_ERROR, this.handleIOError);
  213. this._netConnection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this.handleNetConnectionAsyncError);
  214. // create a bitmap for screenshot
  215. // in this way you can always make a screenshot of the video, even when the NetStream is closed. More about this bug on: http://bugs.adobe.com/jira/browse/FP-1048
  216. this._screenShot = new BitmapData(this._width, this._height, true, 0x00000000);
  217. this.addChild(new Bitmap(this._screenShot));
  218. // create actual video
  219. this._video = new Video(this._width, this._height);
  220. this._video.smoothing = smoothing;
  221. this.addChild(this._video);
  222. this.scrollRect = new Rectangle(0, 0, this._width, this._height);
  223. this.debug = debug;
  224. addToDebugManager(this);
  225. this.scaleMode = scaleMode;
  226. this.addEventListener(Event.ENTER_FRAME, this.handleEnterFrame);
  227. // We create the netStream later, depending on the NetConnection.connect (Streaming or not)
  228. }
  229. /**
  230. * Plays the video on a URL
  231. * This video player can handle local files, web files (http) and RTMP Streaming
  232. *
  233. * When using RTMP streaming pass url as:
  234. * rtmp:[//host][:port]/[appname]/[video filename]
  235. */
  236. public function playUrl(url:String):void
  237. {
  238. if (url == null)
  239. {
  240. this.logError("playUrl: url can not be null");
  241. return;
  242. }
  243. if (this._debug) this.logDebug("playUrl: " + url);
  244. this._video.visible = true;
  245. if (this._scaleMode != ScaleMode.EXACT_FIT)
  246. {
  247. if (this._status != PlayerStatus.LOADING)
  248. {
  249. this._status = PlayerStatus.LOADING;
  250. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  251. // first hide player, so we can't see him playing, show it after playing and seek to 0 and start play again
  252. this._video.visible = false;
  253. this._playAfterLoaded = true;
  254. }
  255. }
  256. else
  257. {
  258. this.setVideoSize();
  259. }
  260. this._isLoaded = false;
  261. this._delayedPause = false;
  262. this._videoPath = url;
  263. // Check if this is RTMP streaming
  264. if (this.isRTMPStream(this._videoPath))
  265. {
  266. // If netStream is allready created and the net connection command is the same, we can directly play the video. Otherwise connect first
  267. if (this._netStream && this._netConnectionCommand == this.rtmpConnection)
  268. {
  269. if (this._netConnection.connected)
  270. {
  271. this.addChild(this._video);
  272. if (this.debug) this.addChild(this._txtDebug);
  273. if (this._status == PlayerStatus.PAUSED)
  274. {
  275. this._isClosed = false;
  276. this._netStream.resume();
  277. }
  278. else
  279. {
  280. this._isClosed = false;
  281. if (this._debug) this.logDebug("playUrl: play '" + this._videoPath + "'");
  282. this._netStream.play(this.rtmpVideoFile);
  283. }
  284. }
  285. }
  286. else
  287. {
  288. this._netConnectionCommand = this.rtmpConnection;
  289. if (this._debug) this.logDebug("playUrl: Connect to '" + this._netConnectionCommand + "'");
  290. this._netConnection.connect(this._netConnectionCommand);
  291. }
  292. }
  293. else
  294. {
  295. // Check if we have a netstream with no netconnection command
  296. if (this._netStream == null || this._netConnectionCommand != null)
  297. {
  298. this._netConnectionCommand = null;
  299. if (this._debug) this.logDebug("playUrl: Connect to '" + this._netConnectionCommand + "'");
  300. this._netConnection.connect(this._netConnectionCommand);
  301. this.createNetStream();
  302. }
  303. this.addChild(this._video);
  304. if (this._debug)
  305. {
  306. this.logDebug("playUrl: play '" + this._videoPath + "'");
  307. this.addChild(this._txtDebug);
  308. }
  309. this._netStream.play(this._videoPath);
  310. this._isClosed = false;
  311. }
  312. }
  313. /**
  314. * @inheritDoc
  315. *
  316. * Loads a movie, but does not play it. Stops movie on first frame
  317. */
  318. public function loadUrl(url:String):void
  319. {
  320. if (this._debug) this.logDebug("loadUrl: " + url);
  321. if (this._videoPath) this.clear();
  322. this._status = PlayerStatus.LOADING;
  323. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  324. this._playAfterLoaded = false;
  325. // first hide player, so we can't see him playing, show it after playing and seek to 0.
  326. this._video.visible = false;
  327. if (this._netStream)
  328. {
  329. try
  330. {
  331. this._netStream.soundTransform = new SoundTransform(0);
  332. }
  333. catch (error:Error)
  334. {
  335. this.logError(error.message);
  336. }
  337. }
  338. this.playUrl(url);
  339. this._video.visible = false;
  340. }
  341. /**
  342. * @inheritDoc
  343. */
  344. public function play():void
  345. {
  346. if (this._debug) this.logDebug("play: ");
  347. this._delayedPause = false;
  348. if (!this._netStream)
  349. {
  350. this.logError("play: NetStream is not set yet");
  351. }
  352. else
  353. {
  354. this.addChild(this._video);
  355. if (this.debug) this.addChild(this._txtDebug);
  356. if (this.isRTMPStream(this._videoPath))
  357. {
  358. if (this._debug) this.logDebug("play: '" + this.rtmpVideoFile + "'");
  359. this._netStream.play(this.rtmpVideoFile);
  360. }
  361. else
  362. {
  363. if (this._debug) this.logDebug("play: '" + this._videoPath + "'");
  364. this._netStream.play(this._videoPath);
  365. }
  366. this._isClosed = false;
  367. }
  368. }
  369. /**
  370. * @inheritDoc
  371. */
  372. public function pause():void
  373. {
  374. if (this._debug) this.logDebug("pause: ");
  375. this._delayedPause = true;
  376. if (!this._netStream)
  377. {
  378. this.logError("pause: NetStream is not set yet");
  379. }
  380. else
  381. {
  382. this._netStream.pause();
  383. this._status = PlayerStatus.PAUSED;
  384. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  385. }
  386. }
  387. /**
  388. * @inheritDoc
  389. */
  390. public function resume():void
  391. {
  392. if (this._debug) this.logDebug("resume: current status is " + this._status);
  393. this._delayedPause = false;
  394. if (!this._netStream)
  395. {
  396. this.logError("resume: NetStream is not set yet");
  397. }
  398. else if (this._status == PlayerStatus.LOADING)
  399. {
  400. this._playAfterLoaded = true;
  401. }
  402. else
  403. {
  404. this._netStream.resume();
  405. this._status = PlayerStatus.PLAYING;
  406. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  407. }
  408. }
  409. /**
  410. * @inheritDoc
  411. */
  412. public function get paused():Boolean
  413. {
  414. return this._status == PlayerStatus.PAUSED;
  415. }
  416. /**
  417. * @inheritDoc
  418. */
  419. public function stop():void
  420. {
  421. if (this._debug) this.logDebug("stop: ");
  422. this._bytesLoaded = this.bytesLoaded;
  423. this._bytesTotal = this.bytesTotal;
  424. this._isClosed = true;
  425. if (this._netStream)
  426. {
  427. // try catch draw to prevent Security Error
  428. try
  429. {
  430. this._screenShot.draw(this);
  431. }
  432. catch (error:Error)
  433. {
  434. if (this.debug) this.logError(error.message);
  435. }
  436. this._netStream.close();
  437. }
  438. if (this._video.parent == this)
  439. {
  440. this.removeChild(this._video);
  441. }
  442. if (this._status != PlayerStatus.STOPPED)
  443. {
  444. this._status = PlayerStatus.STOPPED;
  445. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  446. }
  447. }
  448. /**
  449. * @inheritDoc
  450. */
  451. public function seek(seconds:Number = 0):void
  452. {
  453. if (this._debug) this.logDebug("seek: " + seconds);
  454. if (this._netStream && (this._metaData || seconds == 0))
  455. {
  456. if (seconds == 0 || seconds >= 0 && seconds < this.duration)
  457. {
  458. this._netStream.seek(seconds);
  459. }
  460. else
  461. {
  462. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.SEEK_INVALID));
  463. }
  464. }
  465. else
  466. {
  467. this.logError("seek: MetaData is not available");
  468. }
  469. }
  470. /**
  471. * @inheritDoc
  472. */
  473. override public function get width():Number
  474. {
  475. return this._width;
  476. }
  477. /**
  478. * @inheritDoc
  479. */
  480. override public function set width(value:Number):void
  481. {
  482. if (this._width != value)
  483. {
  484. this._width = value;
  485. this.setVideoSize();
  486. var rect:Rectangle = this.scrollRect;
  487. rect.width = this._width;
  488. this.scrollRect = rect;
  489. }
  490. }
  491. /**
  492. * Returns the width of the current video
  493. */
  494. public function get videoWidth():Number
  495. {
  496. return this._metaData ? this._metaData.width : this._video.videoWidth;
  497. }
  498. /**
  499. * @inheritDoc
  500. */
  501. override public function get height():Number
  502. {
  503. return this._height;
  504. }
  505. /**
  506. * @inheritDoc
  507. */
  508. override public function set height(value:Number):void
  509. {
  510. if (this._height != value)
  511. {
  512. this._height = value;
  513. this.setVideoSize();
  514. var rect:Rectangle = this.scrollRect;
  515. rect.height = this._height;
  516. this.scrollRect = rect;
  517. }
  518. }
  519. /**
  520. * Returns the height of the current video
  521. */
  522. public function get videoHeight():Number
  523. {
  524. return this._metaData ? this._metaData.height : this._video.videoHeight;
  525. }
  526. /**
  527. * @inheritDoc
  528. */
  529. public function get bytesLoaded():uint
  530. {
  531. if (this._isClosed == true) return this._bytesLoaded;
  532. return this._netStream.bytesLoaded;
  533. }
  534. /**
  535. * @inheritDoc
  536. */
  537. public function get bytesTotal():uint
  538. {
  539. if (this._isClosed == true) return this._bytesTotal;
  540. return this._netStream.bytesTotal;
  541. }
  542. /**
  543. * @inheritDoc
  544. */
  545. public function get metaData():VideoMetaData
  546. {
  547. return this._metaData;
  548. }
  549. /**
  550. * Returns most recent cuepoint
  551. */
  552. public function get currentCuePoint():VideoCuePoint
  553. {
  554. return this._cuePoint;
  555. }
  556. /**
  557. * @inheritDoc
  558. */
  559. public function get volume():Number
  560. {
  561. return this._volume;
  562. }
  563. /**
  564. * @inheritDoc
  565. */
  566. [Inspectable(name="Volume", type="Number", defaultValue="1")]
  567. public function set volume(value:Number):void
  568. {
  569. if (this._debug) this.logDebug("volume: " + value);
  570. if (this._volume != value)
  571. {
  572. this._volume = value;
  573. if (this._netStream)
  574. {
  575. try
  576. {
  577. this._netStream.soundTransform = new SoundTransform(this._volume);
  578. }
  579. catch (error:Error)
  580. {
  581. this.logError(error.message);
  582. }
  583. }
  584. this.dispatchEvent(new SoundEvent(SoundEvent.VOLUME_CHANGE));
  585. }
  586. }
  587. /**
  588. * @inheritDoc
  589. */
  590. public function get status():String
  591. {
  592. return this._status;
  593. }
  594. /**
  595. * @inheritDoc
  596. */
  597. public function get currentPlayTime():Number
  598. {
  599. if (this._netStream == null || this._status == PlayerStatus.LOADING) return 0;
  600. return this._netStream.time;
  601. }
  602. /**
  603. * @inheritDoc
  604. */
  605. public function get duration():Number
  606. {
  607. return this._metaData ? this.metaData.duration : 0;
  608. }
  609. /**
  610. * @inheritDoc
  611. */
  612. public function get currentPlayFactor():Number
  613. {
  614. if (!this.metaData || isNaN(this.duration)) return 0;
  615. return this.currentPlayTime / this.duration;
  616. }
  617. /**
  618. * @inheritDoc
  619. */
  620. public function get url():String
  621. {
  622. return this.videoPath;
  623. }
  624. /**
  625. * @inheritDoc
  626. */
  627. public function get videoPath():String
  628. {
  629. return this._videoPath;
  630. }
  631. /**
  632. * @private
  633. */
  634. [Inspectable(name="VideoPath", type="String")]
  635. public function set videoPath(value:String):void
  636. {
  637. if (value != null && value != '') this.playUrl(value);
  638. }
  639. /**
  640. * Checks if the video buffer is full or the buffer equals the length of the video
  641. */
  642. public function isBufferFull():Boolean
  643. {
  644. if (this._metaData)
  645. {
  646. return Math.round(this._netStream.bufferLength) == Math.round(this.duration) || Math.round(this._netStream.bufferLength) == Math.round(this._netStream.bufferTime);
  647. }
  648. else
  649. {
  650. return Math.round(this._netStream.bufferLength) == Math.round(this._netStream.bufferTime);
  651. }
  652. }
  653. /**
  654. * Return true is the video is loaded
  655. */
  656. public function get isLoaded():Boolean
  657. {
  658. return this._isLoaded;
  659. }
  660. /**
  661. * Returns true if the video is closed
  662. */
  663. public function get isClosed():Boolean
  664. {
  665. return this._isClosed;
  666. }
  667. /**
  668. * Get or set the scale mode of the Video
  669. *
  670. * Possible values:
  671. * ScaleMode.EXACT_FIT Specifies that the entire video be visible in the specified area without trying to preserve the original aspect ratio.
  672. * ScaleMode.NO_BORDER Specifies that the entire video fill the specified area, without distortion but possibly with some cropping, while maintaining the original aspect ratio of the video.
  673. * ScaleMode.NO_SCALE Specifies that the size of the video be fixed, so that it remains unchanged even as the size of the player changes.
  674. * ScaleMode.SHOW_ALL Specifies that the entire video be visible in the specified area without distortion while maintaining the original aspect ratio of the video.
  675. */
  676. public function get scaleMode():String
  677. {
  678. return this._scaleMode;
  679. }
  680. /**
  681. * @private
  682. */
  683. [Inspectable(name="scaleMode", type="List", defaultValue="exactFit", enumeration="exactFit,noBorder,noScale,showAll")]
  684. public function set scaleMode(value:String):void
  685. {
  686. if (this._debug) this.logDebug("scaleMode: " + value);
  687. switch (value)
  688. {
  689. case ScaleMode.EXACT_FIT:
  690. case ScaleMode.NO_BORDER:
  691. case ScaleMode.NO_SCALE:
  692. case ScaleMode.SHOW_ALL:
  693. this._scaleMode = value;
  694. this.setVideoSize();
  695. break;
  696. default:
  697. throwError(new TempleError(this, "Invalid value for scaleMode: '" + value + "'"));
  698. break;
  699. }
  700. }
  701. /**
  702. * When you set the scaleMode to a property other than NO_SCALE, and clipping mode is enabled, every image is scaled.
  703. * When you set upscaleEnabled to false, images that are smaller than the clippingRect are not scaled.
  704. * @default true
  705. */
  706. public function get upscaleEnabled():Boolean
  707. {
  708. return this._upscaleEnabled;
  709. }
  710. /**
  711. * @private
  712. */
  713. public function set upscaleEnabled(value:Boolean):void
  714. {
  715. this._upscaleEnabled = value;
  716. this.setVideoSize();
  717. }
  718. /**
  719. *
  720. */
  721. public function get align():String
  722. {
  723. return this._align;
  724. }
  725. /**
  726. * @private
  727. */
  728. public function set align(value:String):void
  729. {
  730. switch (value)
  731. {
  732. case Align.LEFT:
  733. case Align.CENTER:
  734. case Align.RIGHT:
  735. case Align.TOP:
  736. case Align.MIDDLE:
  737. case Align.BOTTOM:
  738. case Align.TOP_LEFT:
  739. case Align.TOP_RIGHT:
  740. case Align.BOTTOM_LEFT:
  741. case Align.BOTTOM_RIGHT:
  742. case Align.NONE:
  743. case null:
  744. this._align = value;
  745. this.setVideoSize();
  746. break;
  747. default:
  748. throwError(new ArgumentError("Invalid value for align: '" + value + "'"));
  749. break;
  750. }
  751. }
  752. /**
  753. * @inheritDoc
  754. */
  755. public function clear():void
  756. {
  757. if (this._debug) this.logDebug("clear: ");
  758. if (this._video)
  759. {
  760. // due to a known bug, clear doens't work. So we just make a copy of the video
  761. var video:Video = new Video();
  762. video.x = this._video.x;
  763. video.y = this._video.y;
  764. video.width = this._video.width;
  765. video.height = this._video.height;
  766. video.visible = this._video.visible;
  767. video.smoothing = this._video.smoothing;
  768. this._video.attachNetStream(null);
  769. video.attachNetStream(this._netStream);
  770. this._video.clear();
  771. if (this._video.parent == this)
  772. {
  773. this.removeChild(this._video);
  774. }
  775. this._video = video;
  776. this.addChild(this._video);
  777. if (this.debug) this.addChild(this._txtDebug);
  778. }
  779. if (this._screenShot) this._screenShot.dispose();
  780. }
  781. /**
  782. * @inheritDoc
  783. */
  784. public function get smoothing():Boolean
  785. {
  786. return this._video.smoothing;
  787. }
  788. /**
  789. * @inheritDoc
  790. */
  791. [Inspectable(name="Smoothing", type="Boolean", defaultValue="false")]
  792. public function set smoothing(value:Boolean):void
  793. {
  794. this._video.smoothing = value;
  795. }
  796. /**
  797. * @inheritDoc
  798. */
  799. public function get autoRewind():Boolean
  800. {
  801. return this._autoRewind;
  802. }
  803. /**
  804. * @inheritDoc
  805. */
  806. public function set autoRewind(value:Boolean):void
  807. {
  808. this._autoRewind = value;
  809. }
  810. /**
  811. * @inheritDoc
  812. */
  813. public function get bufferLength():Number
  814. {
  815. return this._netStream ? this._netStream.bufferLength : 0;
  816. }
  817. /**
  818. * @inheritDoc
  819. */
  820. public function get bufferTime():Number
  821. {
  822. return this._bufferTime;
  823. }
  824. /**
  825. * @inheritDoc
  826. */
  827. public function set bufferTime(value:Number):void
  828. {
  829. this._bufferTime = value;
  830. if (this._netStream) this._netStream.bufferTime = value;
  831. }
  832. /**
  833. * Return the domain + the application name
  834. * (Substring of begin till 2nd "/" after "rtmp://"
  835. */
  836. public function get rtmpConnection():String
  837. {
  838. if (this._rtmpConnection)
  839. {
  840. return this._rtmpConnection;
  841. }
  842. if (this._videoPath)
  843. {
  844. return this._videoPath.substring(0, this._videoPath.lastIndexOf("/"));
  845. }
  846. return null;
  847. }
  848. /**
  849. * @inheritDoc
  850. */
  851. public function set rtmpConnection(value:String):void
  852. {
  853. this._rtmpConnection = value;
  854. }
  855. /**
  856. * Return the url of the file of an RMTP url
  857. * (Substring after 2nd "/" after "rtmp://"
  858. */
  859. public function get rtmpVideoFile():String
  860. {
  861. if (this._rtmpConnection)
  862. {
  863. return this._videoPath.indexOf(this._rtmpConnection) == 0 ? this._videoPath.substr(this._rtmpConnection.length) : this._videoPath;
  864. }
  865. if (this._videoPath)
  866. {
  867. this._videoPath = this._videoPath.substring(this._videoPath.lastIndexOf("/") + 1);
  868. if (this._videoPath.substr(-4) == '.mp3')
  869. {
  870. this._videoPath = 'mp3:' + this._videoPath.substr(0,this._videoPath.length-4);
  871. }
  872. else if (this._videoPath.substr(-4) == '.mp4' || this._videoPath.substr(-4) == '.mov' || this._videoPath.substr(-4) == '.aac' || this._videoPath.substr(-4) == '.m4a')
  873. {
  874. this._videoPath = 'mp4:' + this._videoPath.substr(0, this._videoPath.length-4);
  875. }
  876. else if (this._videoPath.substr(-4) == '.flv')
  877. {
  878. this._videoPath = this._videoPath.substr(0, this._videoPath.length-4);
  879. }
  880. return this._videoPath;
  881. }
  882. return null;
  883. }
  884. /**
  885. * Returns a reference to the Video object of the VideoPlayer.
  886. */
  887. public function get video():Video
  888. {
  889. return this._video;
  890. }
  891. /**
  892. * A Boolean which indicates if background filling is enabled.
  893. * If set to true the background of the VideoPlayer will be filled which the color and alpha set by backgroundColor and backgroundAlpha
  894. */
  895. public function get background():Boolean
  896. {
  897. return this._background;
  898. }
  899. /**
  900. * @private
  901. */
  902. [Inspectable(name="Background", type="Boolean", defaultValue="false")]
  903. public function set background(value:Boolean):void
  904. {
  905. this._background = value;
  906. this.setBackground();
  907. }
  908. /**
  909. * The color of the background of the VideoPlayer, if background is enabled.
  910. */
  911. public function get backgroundColor():uint
  912. {
  913. return this._backgroundColor;
  914. }
  915. /**
  916. * @private
  917. */
  918. [Inspectable(name="Background Color", type="Color", defaultValue="#000000")]
  919. public function set backgroundColor(value:uint):void
  920. {
  921. this._backgroundColor = value;
  922. this.setBackground();
  923. }
  924. /**
  925. * The Number (between 0 and 1) which indicted the alpha of the background of the VideoPlayer, if background is enabled.
  926. */
  927. public function get backgroundAlpha():Number
  928. {
  929. return this._backgroundAlpha;
  930. }
  931. /**
  932. * @private
  933. */
  934. [Inspectable(name="Background Alpha", type="Number", defaultValue="1")]
  935. public function set backgroundAlpha(value:Number):void
  936. {
  937. this._backgroundAlpha = Math.min(Math.max(value, 0), 1);
  938. this.setBackground();
  939. }
  940. /**
  941. * @inheritDoc
  942. */
  943. public function get debug():Boolean
  944. {
  945. return this._debug;
  946. }
  947. /**
  948. * @inheritDoc
  949. */
  950. [Inspectable(name="Debug", type="Boolean", defaultValue="false")]
  951. public function set debug(value:Boolean):void
  952. {
  953. this._debug = value;
  954. if (this._debug)
  955. {
  956. this.removeEventListener(Event.ENTER_FRAME, this.handleEnterFrame);
  957. this.addEventListener(Event.ENTER_FRAME, this.handleEnterFrame);
  958. this.createDebugInfo();
  959. }
  960. }
  961. /**
  962. * @private
  963. *
  964. * Flash Player dispatches NetStatusEvent objects when NetStream reports its status.
  965. */
  966. protected function handleNetStatusEvent(event:NetStatusEvent):void
  967. {
  968. if (this._debug)
  969. {
  970. if (event.info.level == "error")
  971. {
  972. this.logError("handleNetStatusEvent: '" + event.info.code + "' " + event.info.description + ", status=" + this._status);
  973. }
  974. else
  975. {
  976. this.logDebug("handleNetStatusEvent: '" + event.info.code + "' " + event.info.description + ", status=" + this._status);
  977. }
  978. }
  979. switch (event.info.code)
  980. {
  981. //NetStream events
  982. case NetStatusEventInfoCodes.NETSTREAM_BUFFER_EMPTY:
  983. {
  984. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.BUFFER_EMPTY));
  985. break;
  986. }
  987. case NetStatusEventInfoCodes.NETSTREAM_BUFFER_FULL:
  988. {
  989. if (this._status == PlayerStatus.LOADING)
  990. {
  991. this.onLoadReady();
  992. }
  993. else
  994. {
  995. this.dispatchEvent(new VideoPlayerEvent(PlayerEvent.PLAY_STARTED));
  996. }
  997. break;
  998. }
  999. case NetStatusEventInfoCodes.NETSTREAM_PLAY_START:
  1000. {
  1001. if (this._status != PlayerStatus.LOADING)
  1002. {
  1003. if (!this._delayedPause)
  1004. {
  1005. this._status = PlayerStatus.PLAYING;
  1006. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  1007. }
  1008. }
  1009. else
  1010. {
  1011. new FrameDelay(this.onLoadReady, 30);
  1012. }
  1013. break;
  1014. }
  1015. case NetStatusEventInfoCodes.NETSTREAM_PLAY_STOP:
  1016. {
  1017. if (this._status == PlayerStatus.PLAYING)
  1018. {
  1019. this._status = PlayerStatus.STOPPED;
  1020. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  1021. if (this.currentPlayFactor > 0.99)
  1022. {
  1023. if (this._autoRewind)
  1024. {
  1025. this.seek(0);
  1026. this.pause();
  1027. }
  1028. this.dispatchEvent(new PlayerEvent(PlayerEvent.COMPLETE));
  1029. }
  1030. }
  1031. break;
  1032. }
  1033. case NetStatusEventInfoCodes.NETSTREAM_PLAY_STREAM_NOT_FOUND:
  1034. {
  1035. this.logError("handleNetStatusEvent: '" + event.info.code + "' - '" + this._videoPath + "'");
  1036. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.MOVIE_NOTFOUND));
  1037. break;
  1038. }
  1039. case NetStatusEventInfoCodes.NETSTREAM_SEEK_INVALID_TIME:
  1040. {
  1041. this.logError("handleNetStatusEvent: try to seek to invalid time '" + event.info.code + "'");
  1042. break;
  1043. }
  1044. case NetStatusEventInfoCodes.NETSTREAM_BUFFER_FLUSH:
  1045. {
  1046. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.BUFFER_FLUSH));
  1047. break;
  1048. }
  1049. case NetStatusEventInfoCodes.NETSTREAM_SEEK_NOTIFY:
  1050. {
  1051. this.dispatchEvent(new PlayerEvent(PlayerEvent.SEEK_NOTIFY));
  1052. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.SEEK_NOTIFY));
  1053. break;
  1054. }
  1055. case NetStatusEventInfoCodes.NETSTREAM_PLAY_RESET:
  1056. case NetStatusEventInfoCodes.NETSTREAM_UNPAUSE_NOTIFY:
  1057. case NetStatusEventInfoCodes.NETSTREAM_PAUSE_NOTIFY:
  1058. {
  1059. // do nothing
  1060. break;
  1061. }
  1062. //NetConnection events
  1063. case NetStatusEventInfoCodes.NETCONNECTION_CONNECT_SUCCESS:
  1064. {
  1065. if (this._netConnectionCommand != null)
  1066. {
  1067. this.createNetStream();
  1068. if (this.debug) this.logDebug("handleNetStatusEvent: play \"" + this.rtmpVideoFile + "\"");
  1069. this._netStream.play(this.rtmpVideoFile);
  1070. }
  1071. break;
  1072. }
  1073. case NetStatusEventInfoCodes.NETCONNECTION_CONNECT_CLOSED:
  1074. {
  1075. // do nothing
  1076. break;
  1077. }
  1078. case NetStatusEventInfoCodes.NETCONNECTION_CONNECT_REJECTED:
  1079. {
  1080. this.logError("handleNetStatusEvent: Error can't connect '" + event.info.code + "'");
  1081. break;
  1082. }
  1083. default:
  1084. {
  1085. this.logError("handleNetStatusEvent: unhandled NetStatusEvent '" + event.info.code + "'");
  1086. break;
  1087. }
  1088. }
  1089. this.dispatchEvent(event.clone());
  1090. }
  1091. /**
  1092. * Flash Player dispatches an AsyncErrorEvent when an exception is thrown from native asynchronous code
  1093. */
  1094. private function handleAsyncError(event:AsyncErrorEvent):void
  1095. {
  1096. this.logError("handleAsyncError: " + event.text);
  1097. }
  1098. /**
  1099. * Flash Player dispatches SecurityErrorEvent objects to report the occurrence of a security error
  1100. */
  1101. private function handleSecurityError(event:SecurityErrorEvent):void
  1102. {
  1103. this.logError("handleSecurityError: " + event.text);
  1104. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.SECURITY_ERROR));
  1105. }
  1106. /**
  1107. * Handler for metadata & cuepoints events from the NetStream object.
  1108. */
  1109. private function handleMetaDataEvent(event:VideoMetaDataEvent):void
  1110. {
  1111. if (this._debug) this.logDebug("handleMetaDataEvent: " + event.metadata);
  1112. this._metaData = event.metadata;
  1113. new FrameDelay(this.setVideoSize);
  1114. // max buffertime to duration
  1115. if (this._netStream.bufferTime > this.duration) this._netStream.bufferTime = this.duration;
  1116. this.dispatchEvent(event.clone());
  1117. }
  1118. /**
  1119. * Handler for metadata & cuepoints events from the NetStream object.
  1120. */
  1121. private function handleCuePointEvent(event:CuePointEvent):void
  1122. {
  1123. if (this._debug) this.logDebug("handleCuePointEvent: " + event.cuepoint);
  1124. // store cuepoint
  1125. this._cuePoint = event.cuepoint;
  1126. this.dispatchEvent(event.clone());
  1127. }
  1128. private function handleNetConnectionAsyncError(event:AsyncErrorEvent):void
  1129. {
  1130. this.logError("handleNetConnectionAsyncError: '" + event.text + "'");
  1131. }
  1132. private function handleIOError(event:IOErrorEvent):void
  1133. {
  1134. this.logError("handleIOError: '" + event.text + "'");
  1135. }
  1136. private function onLoadReady():void
  1137. {
  1138. if (this._status == PlayerStatus.LOADING)
  1139. {
  1140. if (this._debug) this.logDebug("onLoadReady: Load Ready!");
  1141. this.setVideoSize();
  1142. this._video.visible = true;
  1143. var volume:Number = this._volume;
  1144. this._volume = 0;
  1145. this.volume = volume;
  1146. if (this._playAfterLoaded)
  1147. {
  1148. this._status = PlayerStatus.PLAYING;
  1149. this.dispatchEvent(new StatusEvent(StatusEvent.STATUS_CHANGE, this._status));
  1150. }
  1151. else
  1152. {
  1153. this.pause();
  1154. this.seek(0);
  1155. }
  1156. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.LOAD_READY));
  1157. }
  1158. }
  1159. private function isRTMPStream(url:String):Boolean
  1160. {
  1161. if (url.substr(0, 7) == "rtmp://" || url.substr(0, 8) == "rtmpt://")
  1162. {
  1163. return true;
  1164. }
  1165. return false;
  1166. }
  1167. private function createNetStream():void
  1168. {
  1169. if (this._netStream != null)
  1170. {
  1171. this._netStream.destruct();
  1172. }
  1173. this._netStream = new VideoNetStream(this._netConnection);
  1174. this._netStream.checkPolicyFile = true;
  1175. this._netStream.soundTransform = new SoundTransform(this._status == PlayerStatus.LOADING ? 0 : this._volume);
  1176. this._netStream.addEventListener(VideoMetaDataEvent.METADATA, this.handleMetaDataEvent);
  1177. this._netStream.addEventListener(CuePointEvent.CUEPOINT, this.handleCuePointEvent);
  1178. this._netStream.addEventListener(NetStatusEvent.NET_STATUS, this.handleNetStatusEvent);
  1179. this._netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this.handleAsyncError);
  1180. this._netStream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.handleSecurityError);
  1181. this._netStream.bufferTime = this._bufferTime;
  1182. this._video.attachNetStream(this._netStream);
  1183. if (this.debug) this.logDebug("createNetStream: ");
  1184. this.addChild(this._video);
  1185. if (this.debug) this.addChild(this._txtDebug);
  1186. }
  1187. private function createDebugInfo():void
  1188. {
  1189. this._txtDebug = this.addChild(this._txtDebug || new TextField()) as TextField;
  1190. this._txtDebug.background = true;
  1191. this._txtDebug.alpha = .75;
  1192. this._txtDebug.border = true;
  1193. this._txtDebug.multiline = true;
  1194. this._txtDebug.width = this._video.width;
  1195. this._txtDebug.autoSize = TextFieldAutoSize.LEFT;
  1196. }
  1197. private function handleEnterFrame(event:Event):void
  1198. {
  1199. // if loaded, dispatch event
  1200. if (this.bytesLoaded > 10 && this.bytesLoaded == this.bytesTotal && this._isLoaded == false)
  1201. {
  1202. this._isLoaded = true;
  1203. this.dispatchEvent(new VideoPlayerEvent(VideoPlayerEvent.MOVIE_LOADED));
  1204. if (!this._debug) this.removeEventListener(Event.ENTER_FRAME, this.handleEnterFrame);
  1205. }
  1206. if (this._debug)
  1207. {
  1208. this._txtDebug.text = "";
  1209. this._txtDebug.appendText("url: " + this.videoPath + "\n");
  1210. if (this.videoPath && !this.isRTMPStream(this.videoPath)) this._txtDebug.appendText((this.isLoaded ? "loaded" : "loading") + ': ' + int(this.bytesLoaded / 1024) + ' / ' + int(this.bytesTotal / 1024) + " KB - " + uint(100 * this.bytesLoaded / this.bytesTotal) + "%\n");
  1211. this._txtDebug.appendText(this.status + ": " + TimeUtils.secondsToString(this.currentPlayTime) + " / " + TimeUtils.formatTime(this.duration * 1000) + "\n");
  1212. this._txtDebug.appendText(this.scaleMode + ": " + this.videoWidth + "x" + this.videoHeight);
  1213. if (!this._video.visible) this._txtDebug.appendText(" (hidden)");
  1214. }
  1215. }
  1216. private function setVideoSize():void
  1217. {
  1218. var videoWidth:Number = this.videoWidth;
  1219. var videoHeight:Number = this.videoHeight;
  1220. if (this.debug) this.logDebug("setVideoSize: " + this._scaleMode + " " + videoWidth + "*" + videoHeight);
  1221. switch (this._scaleMode)
  1222. {
  1223. case ScaleMode.EXACT_FIT:
  1224. {
  1225. // do nothing
  1226. this._video.width = this._width;
  1227. this._video.height = this._height;
  1228. break;
  1229. }
  1230. case ScaleMode.NO_BORDER:
  1231. {
  1232. if (this._width / videoWidth > this._height / videoHeight)
  1233. {
  1234. this._video.height = (this._width / videoWidth) * videoHeight;
  1235. this._video.width = this._width;
  1236. }
  1237. else
  1238. {
  1239. this._video.width = (this._height / videoHeight) * videoWidth;
  1240. this._video.height = this._height;
  1241. }
  1242. break;
  1243. }
  1244. case ScaleMode.NO_SCALE:
  1245. {
  1246. this._video.width = videoWidth;
  1247. this._video.height = videoHeight;
  1248. break;
  1249. }
  1250. case ScaleMode.SHOW_ALL:
  1251. {
  1252. if (this._width / videoWidth < this._height / videoHeight)
  1253. {
  1254. this._video.height = (this._width / videoWidth) * videoHeight;
  1255. this._video.width = this._width;
  1256. }
  1257. else
  1258. {
  1259. this._video.width = (this._height / videoHeight) * videoWidth;
  1260. this._video.height = this._height;
  1261. }
  1262. break;
  1263. }
  1264. }
  1265. if (!this._upscaleEnabled)
  1266. {
  1267. if (this._video.width > videoWidth)
  1268. {
  1269. this._video.width = videoWidth;
  1270. }
  1271. if (this._video.height > videoHeight)
  1272. {
  1273. this._video.height = videoHeight;
  1274. }
  1275. }
  1276. this.setAlign();
  1277. this.setBackground();
  1278. }
  1279. private function setAlign():void
  1280. {
  1281. // Horizontal
  1282. switch (this._align)
  1283. {
  1284. case Align.LEFT:
  1285. case Align.TOP_LEFT:
  1286. case Align.BOTTOM_LEFT:
  1287. this._video.x = 0;
  1288. break;
  1289. case Align.RIGHT:
  1290. case Align.TOP_RIGHT:
  1291. case Align.BOTTOM_RIGHT:
  1292. this._video.x = -1 * (this._video.width - this._width);
  1293. break;
  1294. default:
  1295. this._video.x = - 0.5 * (this._video.width - this._width);
  1296. break;
  1297. }
  1298. // Vertical
  1299. switch (this._align)
  1300. {
  1301. case Align.TOP:
  1302. case Align.TOP_LEFT:
  1303. case Align.TOP_RIGHT:
  1304. this._video.y = 0;
  1305. break;
  1306. case Align.BOTTOM:
  1307. case Align.BOTTOM_LEFT:
  1308. case Align.BOTTOM_RIGHT:
  1309. this._video.y = -1 * (this._video.height - this._height);
  1310. break;
  1311. default:
  1312. this._video.y = - 0.5 * (this._video.height - this._height);
  1313. break;
  1314. }
  1315. }
  1316. private function setBackground():void
  1317. {
  1318. this.graphics.clear();
  1319. if (this._background)
  1320. {
  1321. this.graphics.beginFill(this._backgroundColor, this._backgroundAlpha);
  1322. this.graphics.drawRect(0, 0, this._width, this._height);
  1323. this.graphics.endFill();
  1324. }
  1325. }
  1326. /**
  1327. * Removes all listeners of the video player
  1328. */
  1329. override public function destruct():void
  1330. {
  1331. this.removeAllStrongEventListenersForType(StatusEvent.STATUS_CHANGE);
  1332. this.stop();
  1333. this.removeEventListener(Event.ENTER_FRAME, this.handleEnterFrame);
  1334. if (this._netStream)
  1335. {
  1336. this._netStream.destruct();
  1337. this._netStream = null;
  1338. }
  1339. if (this._netConnection)
  1340. {
  1341. this._netConnection.destruct();
  1342. this._netConnection = null;
  1343. }
  1344. this._metaData = null;
  1345. if (this._video.parent && this._video.parent == this)
  1346. {
  1347. this.removeChild(this._video);
  1348. this._video = null;
  1349. }
  1350. if (this._screenShot)
  1351. {
  1352. this._screenShot.dispose();
  1353. this._screenShot = null;
  1354. }
  1355. this._txtDebug = null;
  1356. this._cuePoint = null;
  1357. super.destruct();
  1358. }
  1359. }
  1360. }