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