PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/html5/src/FLVPlayer.as

http://flvplayer.googlecode.com/
ActionScript | 414 lines | 230 code | 55 blank | 129 comment | 31 complexity | a009ef8f529705ba84ffc1cc74b2234f MD5 | raw file
  1. package
  2. {
  3. import flash.display.Sprite;
  4. import flash.display.StageScaleMode;
  5. import flash.display.StageAlign;
  6. import flash.external.ExternalInterface;
  7. import flash.utils.Timer;
  8. import flash.events.Event;
  9. import flash.events.NetStatusEvent;
  10. import flash.events.TimerEvent;
  11. import flash.media.Video;
  12. import flash.media.SoundTransform;
  13. import flash.net.NetConnection;
  14. import flash.net.NetStream;
  15. import flash.system.Security;
  16. /**
  17. * The FLV player
  18. */
  19. [SWF(width="200", height="200", backgroundColor="#000000", frameRate="48")]
  20. [Frame(factoryClass="Preload")]
  21. public class FLVPlayer extends Sprite
  22. {
  23. /**
  24. * The javascript listener
  25. */
  26. protected var _javascriptListener:String = "";
  27. /**
  28. * The net connection
  29. */
  30. protected var _connection:NetConnection;
  31. /**
  32. * The net stream
  33. */
  34. protected var _stream:NetStream;
  35. /**
  36. * The video object
  37. */
  38. protected var _video:Video;
  39. /**
  40. * The video URL
  41. */
  42. protected var _videoURL:String = "";
  43. /**
  44. * Indicates the video is playing for the first time
  45. */
  46. protected var _firstPlay:Boolean = true;
  47. /**
  48. * The current time
  49. */
  50. protected var _currentTime:Number = 0;
  51. /**
  52. * The current volume
  53. */
  54. protected var _currentVolume:Number = 1;
  55. /**
  56. * Indicates the player is ready
  57. */
  58. protected var _isReady:Boolean = false;
  59. /**
  60. * The meta data of the video
  61. */
  62. protected var _metaData:Object;
  63. /**
  64. * Indicates the loading data is started
  65. */
  66. protected var _loadStarted:Boolean = false;
  67. /**
  68. * Indicates the loading data is finished
  69. */
  70. protected var _loaded:Boolean = false;
  71. /**
  72. * Constructor
  73. */
  74. public function FLVPlayer()
  75. {
  76. super();
  77. Security.allowDomain("*");
  78. this.addEventListener(Event.ADDED_TO_STAGE, this._initialize);
  79. }
  80. protected function _initialize(event:Event):void
  81. {
  82. // Initialize the stage
  83. this.stage.scaleMode = StageScaleMode.NO_SCALE;
  84. this.stage.align = StageAlign.TOP_LEFT;
  85. // Flash parameters
  86. var parameters:Object = this.root.loaderInfo.parameters;
  87. this._javascriptListener = parameters.listener;
  88. this._videoURL = parameters.src;
  89. // Initialize external interface
  90. if (ExternalInterface.available) {
  91. ExternalInterface.addCallback("flashPlay", this._play);
  92. ExternalInterface.addCallback("flashPause", this._pause);
  93. ExternalInterface.addCallback("flashSeek", this._seek);
  94. ExternalInterface.addCallback("flashVolume", this._volume);
  95. if (this._checkJavascriptReady()) {
  96. this._ready();
  97. } else {
  98. var timer:Timer = new Timer(500);
  99. timer.addEventListener(TimerEvent.TIMER, this._timerHandler);
  100. timer.start();
  101. }
  102. }
  103. this.addEventListener(Event.ENTER_FRAME, this._enterFrameHandler);
  104. }
  105. /**
  106. * Check if the Javascript is ready
  107. *
  108. * return true if the Javascript is ready, false otherwise
  109. */
  110. protected function _checkJavascriptReady():Boolean
  111. {
  112. var isReady:Boolean = ExternalInterface.call(this._javascriptListener+".isReady");
  113. this._isReady = isReady;
  114. return isReady;
  115. }
  116. /**
  117. * Timer handler
  118. *
  119. * @param event The event
  120. */
  121. protected function _timerHandler(event:TimerEvent):void
  122. {
  123. if (this._checkJavascriptReady()) {
  124. this._ready();
  125. }
  126. }
  127. /**
  128. * The javascript is ready
  129. */
  130. protected function _ready():void
  131. {
  132. this._connection = new NetConnection();
  133. this._connection.addEventListener(NetStatusEvent.NET_STATUS, this._netStatusHandler);
  134. this._connection.connect(null);
  135. this._stream = new NetStream(this._connection);
  136. this._stream.addEventListener(NetStatusEvent.NET_STATUS, this._netStatusHandler);
  137. this._stream.client = new Object();
  138. this._stream.client.onMetaData = this._metaDataHandler;
  139. this._video = new Video();
  140. this._video.attachNetStream(this._stream);
  141. this.addChild(this._video);
  142. /*
  143. this._video.width = this.stage.stageWidth;
  144. this._video.height = this.stage.stageHeight;
  145. this._video.width = 320;
  146. this._video.height = 240;
  147. */
  148. }
  149. /**
  150. * Play the video
  151. */
  152. protected function _play():void
  153. {
  154. if (this._firstPlay) {
  155. this._stream.play(this._videoURL);
  156. this._firstPlay = false;
  157. } else {
  158. this._stream.resume();
  159. }
  160. var jsEvent:Object = new Object();
  161. jsEvent.type = "play";
  162. this._dispatchEventToJavascript(jsEvent);
  163. }
  164. /**
  165. * Pause
  166. */
  167. protected function _pause():void
  168. {
  169. this._stream.pause();
  170. // Dispatch timeupdate event
  171. jsEvent = new Object();
  172. jsEvent.type = "timeupdate";
  173. this._dispatchEventToJavascript(jsEvent);
  174. // Dispatch pause event
  175. var jsEvent:Object = new Object();
  176. jsEvent.type = "pause";
  177. this._dispatchEventToJavascript(jsEvent);
  178. }
  179. /**
  180. * Seek
  181. */
  182. protected function _seek(offset:Number):void
  183. {
  184. this._stream.seek(offset);
  185. var jsEvent:Object = new Object();
  186. jsEvent.type = "seeking";
  187. this._dispatchEventToJavascript(jsEvent);
  188. }
  189. /**
  190. * Volume
  191. */
  192. protected function _volume(value:Number):void
  193. {
  194. var transform:SoundTransform = this._stream.soundTransform;
  195. transform.volume = value;
  196. this._stream.soundTransform = transform;
  197. }
  198. /**
  199. * "metaData" event handler
  200. *
  201. * @param info The info object
  202. */
  203. protected function _metaDataHandler(info:Object):void
  204. {
  205. this._metaData = info;
  206. // duration
  207. this._callJavascript("setDuration", info.duration);
  208. var jsEvent:Object = new Object();
  209. jsEvent.type = "durationchange";
  210. this._dispatchEventToJavascript(jsEvent);
  211. // width
  212. this._callJavascript("setVideoWidth", info.width);
  213. // height
  214. this._callJavascript("setVideoHeight", info.height);
  215. // framerate
  216. //this._callJavascript("setPlaybackRate", info.framerate);
  217. //jsEvent = new Object();
  218. //jsEvent.type = "ratechange";
  219. //this._dispatchEventToJavascript(jsEvent);
  220. // The metadata is loaded
  221. jsEvent = new Object();
  222. jsEvent.type = "loadedmetadata";
  223. this._dispatchEventToJavascript(jsEvent);
  224. }
  225. /**
  226. *The enter frame event handler
  227. *
  228. * @param event The event
  229. */
  230. protected function _enterFrameHandler(event:Event):void
  231. {
  232. // video size
  233. // Sometimes, the sprite is not already added to the stage (Firefox 3.1, MacOSX)
  234. // So, I wait until the stage exists and I set the video size
  235. if (this.stage && (this._video.width != this.stage.stageWidth || this._video.height != this.stage.stageHeight)) {
  236. this._video.width = this.stage.stageWidth;
  237. this._video.height = this.stage.stageHeight;
  238. }
  239. // The javascript player is ready
  240. if (this._isReady) {
  241. var jsEvent:Object;
  242. // event "loadstart"
  243. if (!this._loadStarted && this._stream.bytesLoaded > 0) {
  244. this._loadStarted = true;
  245. jsEvent = new Object();
  246. jsEvent.type = "loadstart";
  247. this._dispatchEventToJavascript(jsEvent);
  248. }
  249. // event "progress"
  250. if (this._loadStarted && !this._loaded) {
  251. jsEvent = new Object();
  252. jsEvent.type = "progress";
  253. this._dispatchEventToJavascript(jsEvent);
  254. }
  255. // event "load"
  256. if (!this._loaded && this._loadStarted && this._stream.bytesLoaded >= this._stream.bytesTotal) {
  257. this._loaded = true;
  258. jsEvent = new Object();
  259. jsEvent.type = "load";
  260. this._dispatchEventToJavascript(jsEvent);
  261. }
  262. // Time check
  263. var jsCurrentTime:Number = this._callJavascript("getCurrentTime");
  264. var currentTimeChanged:Boolean = false;
  265. if (this._currentTime == jsCurrentTime) {
  266. //if (this._stream.time != this._currentTime) {
  267. // currentTimeChanged = true;
  268. //}
  269. this._currentTime = this._stream.time;
  270. } else {
  271. this._currentTime = jsCurrentTime;
  272. this._seek(this._currentTime);
  273. currentTimeChanged = true;
  274. }
  275. this._callJavascript("setCurrentTime", this._currentTime);
  276. // If a new time is set, dispatch the event
  277. if (currentTimeChanged) {
  278. jsEvent = new Object();
  279. jsEvent.type = "timeupdate";
  280. this._dispatchEventToJavascript(jsEvent);
  281. }
  282. // Volume check
  283. var jsVolume:Number = this._callJavascript("getVolume");
  284. var volumeChanged:Boolean = false;
  285. if (this._currentVolume != jsVolume) {
  286. this._volume(jsVolume);
  287. this._currentVolume = jsVolume;
  288. volumeChanged = true;
  289. }
  290. this._callJavascript("setVolume", this._currentVolume);
  291. // If a new volume is set, dispatch the event
  292. if (volumeChanged) {
  293. jsEvent = new Object();
  294. jsEvent.type = "volumechange";
  295. this._dispatchEventToJavascript(jsEvent);
  296. }
  297. }
  298. }
  299. /**
  300. * The net status event handler
  301. *
  302. * @param event The event
  303. */
  304. protected function _netStatusHandler(event:NetStatusEvent):void
  305. {
  306. var jsEvent:Object = new Object();
  307. switch (event.info.code) {
  308. default:
  309. jsEvent.type = "unknown";
  310. break;
  311. case "NetStream.Play.StreamNotFound":
  312. jsEvent.type = "error";
  313. jsEvent.code = "no_source";
  314. break;
  315. case "NetStream.Play.Start":
  316. jsEvent.type = "playing";
  317. break;
  318. case "NetStream.Play.Stop":
  319. jsEvent.type = "ended";
  320. break;
  321. case "NetStream.Pause.Notify":
  322. jsEvent.type = "pause";
  323. break;
  324. case "NetStream.Seek.Notify":
  325. jsEvent.type = "seeked";
  326. break;
  327. }
  328. if (this._loadStarted || jsEvent.type == "error") {
  329. this._dispatchEventToJavascript(jsEvent);
  330. }
  331. //ExternalInterface.call("console.log", event.info.code);
  332. }
  333. /**
  334. * Dispatch an event to javascript
  335. *
  336. * @param event The event
  337. */
  338. protected function _dispatchEventToJavascript(event:Object):void
  339. {
  340. ExternalInterface.call(this._javascriptListener + ".dispatchEvent", event);
  341. }
  342. /**
  343. * Call a javascript method
  344. *
  345. * @param methodName The javascript method name
  346. * @param parameters The parameters
  347. * @return The method result
  348. */
  349. protected function _callJavascript(methodName:String, ...parameters):*
  350. {
  351. var jsParameters:Array = new Array();
  352. jsParameters.push(this._javascriptListener + "." + methodName);
  353. for each (var parameter:* in parameters) {
  354. jsParameters.push(parameter);
  355. }
  356. return ExternalInterface.call.apply(ExternalInterface, jsParameters);
  357. }
  358. }
  359. }