|
1 package bab.player |
|
2 { |
|
3 |
|
4 import fl.video.MetadataEvent; |
|
5 import fl.video.SoundEvent; |
|
6 import fl.video.VideoEvent; |
|
7 import fl.video.VideoScaleMode; |
|
8 import fl.video.VideoState; |
|
9 |
|
10 import flash.display.Graphics; |
|
11 import flash.display.Loader; |
|
12 import flash.display.MovieClip; |
|
13 import flash.display.Sprite; |
|
14 import flash.events.Event; |
|
15 import flash.events.IOErrorEvent; |
|
16 import flash.events.MouseEvent; |
|
17 import flash.events.TimerEvent; |
|
18 import flash.net.URLRequest; |
|
19 import flash.text.StyleSheet; |
|
20 import flash.text.TextField; |
|
21 import flash.text.TextFormat; |
|
22 import flash.text.TextFormatAlign; |
|
23 import flash.utils.Timer; |
|
24 |
|
25 import fl.controls.ProgressBar; |
|
26 |
|
27 import bab.player.events.EditEvent; |
|
28 |
|
29 public class FlvPlayer extends Sprite |
|
30 { |
|
31 private var wMin:Number = 550; |
|
32 private var hMin:Number = 400; |
|
33 public var flvPB:FLVPlaybackLDT; |
|
34 private var widthFlv:uint; |
|
35 private var heightFlv:uint; |
|
36 private var uic:Sprite; |
|
37 private var loading:TextField; |
|
38 private var tcLabel:TextField; |
|
39 private var metas:Array = new Array(); |
|
40 private var curRatio:Number; |
|
41 private var savePlay:Boolean = false; |
|
42 |
|
43 public var editSkin:EditSkin; |
|
44 //private var babAr:Array; |
|
45 private var curInst:int = -1; |
|
46 private var babRunning:Boolean = false; |
|
47 private var babRunningTimer:Timer; |
|
48 public var babSkin:MovieClip; |
|
49 private var babRatio:Number = 1.25; |
|
50 private var editList:Array; |
|
51 private var mediaList:Array; |
|
52 private var instanceToPlay:uint = 0; |
|
53 |
|
54 private var imageLayer:MovieClip; |
|
55 private var pictAr:Array; |
|
56 private var nbPictLoaded:uint; |
|
57 private var mcContainer:Sprite; |
|
58 private var bgMcCtn:Sprite; |
|
59 private var textLayer:TextField; |
|
60 private var styles:StyleSheet; |
|
61 private var tf:TextFormat; |
|
62 private var pb:ProgressBar; |
|
63 |
|
64 private var caption:FLVPlaybackCaptioningLDT; |
|
65 |
|
66 private var fullScreenOn:Boolean = false; |
|
67 |
|
68 public var writeTC:Boolean = true; |
|
69 |
|
70 private var YTPlayer:ExternalPlayer; |
|
71 |
|
72 private var currentTcBab:Number; |
|
73 private var debugText:TextField; |
|
74 |
|
75 public function FlvPlayer(wInit:Number=550, hInit:Number=400, urlSkin:String="", debug:TextField=null) |
|
76 { |
|
77 super(); |
|
78 |
|
79 wMin = wInit; |
|
80 hMin = hInit; |
|
81 debugText = debug; |
|
82 |
|
83 // Container for text layer, image layer and flvPB |
|
84 uic = new Sprite(); |
|
85 addChild(uic); |
|
86 |
|
87 // Background container |
|
88 mcContainer = new Sprite(); |
|
89 mcContainer.visible = false; |
|
90 uic.addChild(mcContainer); |
|
91 bgMcCtn = new Sprite(); |
|
92 bgMcCtn.graphics.beginFill(0x770000); |
|
93 bgMcCtn.graphics.drawRect(0,0,wMin,hMin); |
|
94 bgMcCtn.graphics.endFill(); |
|
95 mcContainer.addChild(bgMcCtn); |
|
96 // Text layer |
|
97 textLayer = new TextField(); |
|
98 textLayer.width = wMin; |
|
99 tf = new TextFormat("Verdana",12,0xFFFFFF); |
|
100 tf.align = TextFormatAlign.CENTER; |
|
101 /*styles = new StyleSheet(); |
|
102 var body:Object = new Object(); |
|
103 body.fontFamily = "Verdana"; |
|
104 body.fontSize = 12; |
|
105 body.color = "#FFFFFF"; |
|
106 body.align = "center"; |
|
107 styles.setStyle("body", body); |
|
108 textLayer.styleSheet = styles;*/ |
|
109 textLayer.wordWrap = true; |
|
110 textLayer.visible = false; |
|
111 mcContainer.addChild(textLayer); |
|
112 |
|
113 // Flv playback component |
|
114 flvPB = new FLVPlaybackLDT(); |
|
115 uic.addChild(flvPB); |
|
116 flvPB.autoPlay = false; |
|
117 flvPB.fullScreenTakeOver = false; |
|
118 flvPB.scaleMode = VideoScaleMode.MAINTAIN_ASPECT_RATIO; |
|
119 //flvPB.skin = urlSkin + "SkinUnderPlaySeekMuteVol.swf"; // urlSkin finishes with a "/" |
|
120 //flvPB.skinBackgroundColor = 0xCCCCCC; |
|
121 flvPB.addEventListener(MetadataEvent.METADATA_RECEIVED, onMDReceived); |
|
122 flvPB.addEventListener(VideoEvent.PLAYHEAD_UPDATE, onPlayheadUpdate); |
|
123 flvPB.addEventListener(VideoEvent.READY, onReady); |
|
124 flvPB.addEventListener(VideoEvent.SEEKED, onSeeked); |
|
125 flvPB.addEventListener(VideoEvent.STATE_CHANGE, onStateChange); |
|
126 |
|
127 caption = new FLVPlaybackCaptioningLDT(); |
|
128 uic.addChild(caption); |
|
129 |
|
130 var loader:Loader = new Loader(); |
|
131 loader.contentLoaderInfo.addEventListener(Event.COMPLETE, placeBabSkin); |
|
132 loader.load(new URLRequest(urlSkin)); |
|
133 uic.addChild(loader); |
|
134 |
|
135 imageLayer = new MovieClip(); |
|
136 this.addChild(imageLayer); |
|
137 |
|
138 tcLabel = new TextField(); |
|
139 tcLabel.text = "[00:00:00]"; |
|
140 tcLabel.textColor = 0xFFFFFF; |
|
141 tcLabel.x = 120; |
|
142 this.addChild(tcLabel); |
|
143 |
|
144 loading = new TextField(); |
|
145 loading.text = "Loading..."; |
|
146 loading.textColor = 0x0000FF; |
|
147 loading.visible = false; |
|
148 loading.mouseEnabled = false; |
|
149 //loading.styleSheet.setStyle("horizontalCenter",0); |
|
150 this.addChild(loading); |
|
151 |
|
152 pb = new ProgressBar(); |
|
153 pb.visible = false; |
|
154 addChild(pb); |
|
155 |
|
156 } |
|
157 |
|
158 |
|
159 |
|
160 // |
|
161 // On creation complete |
|
162 // |
|
163 private function placeBabSkin(e:Event):void { |
|
164 babSkin = e.target.content; |
|
165 //trace("babSkin 2 = " + babSkin.play_mc + ", " + babSkin.pause_mc + ", " + babSkin.back_mc + ", " + babSkin.forward_mc + ", " + babSkin.volumeBarHandle_mc + ", " + babSkin.volumeBar_mc); |
|
166 babSkin.y = heightFlv; |
|
167 babSkin.getChildAt(0).width = widthFlv; |
|
168 babSkin.visible = false; |
|
169 editSkin = new EditSkin(this); |
|
170 editSkin.addEventListener(EditEvent.EDIT_PLAYPAUSE, onEditPlayPause); |
|
171 editSkin.addEventListener(EditEvent.EDIT_BACK, onEditBack); |
|
172 editSkin.addEventListener(EditEvent.EDIT_FORWARD, onEditForward); |
|
173 editSkin.addEventListener(EditEvent.EDIT_SOUNDUPDATE, onEditVolumeUpdate); |
|
174 // usefull to notice edit skin has been loaded. |
|
175 dispatchEvent(new Event(EditEvent.EDIT_CHANGEINSTRUCTION)); |
|
176 } |
|
177 |
|
178 |
|
179 |
|
180 // |
|
181 // load media function |
|
182 // |
|
183 public function loadMedia(path:String, live:Boolean=false, paramPlay:Boolean=false, firstST:String="", extrasAr:Array=null):void{ |
|
184 //trace("loadMedia " + path); |
|
185 stopBab(); |
|
186 // First, we check if the url to load is a Youtube url |
|
187 if(path.search("youtube.com")>-1 || path.search("dailymotion.com")>-1){ |
|
188 pause(); |
|
189 // A valid youtube url is like : http://www.youtube.com/watch?v=PgEu923nxSE or http://www.youtube.com/v/PgEu923nxSE |
|
190 if(YTPlayer==null){ |
|
191 YTPlayer = new ExternalPlayer(uic, path); |
|
192 YTPlayer.addEventListener(VideoEvent.PLAYHEAD_UPDATE, onPlayheadUpdate); |
|
193 YTPlayer.addEventListener(VideoEvent.READY, initSizes); |
|
194 } |
|
195 else YTPlayer.loadVideo(path); |
|
196 curRatio = ExternalPlayer.EXTERNALPLAYER_RATIO; |
|
197 //initSizes(); |
|
198 YTPlayer.visible = true; |
|
199 flvPB.visible = false; |
|
200 } |
|
201 else{ |
|
202 if(YTPlayer!=null) YTPlayer.visible = false; |
|
203 flvPB.visible = true; |
|
204 // We check if the media is already loaded |
|
205 var nbMedias:uint = metas.length; |
|
206 var vp:Number = getVp(path); |
|
207 var vol:Number = flvPB.volume; |
|
208 // We stop the current reading if possible |
|
209 if(nbMedias>0 && allowFlvPB()) { flvPB.stop(); } |
|
210 // We load the new content or play the already loaded content |
|
211 if(isNaN(vp)){ |
|
212 vp = metas.length; |
|
213 // We activate the good video player index |
|
214 flvPB.activeVideoPlayerIndex = flvPB.visibleVideoPlayerIndex = vp; |
|
215 flvPB.smoothing = true; |
|
216 //trace("je load " + vp + ", " + path); |
|
217 metas.push({path:path, w:3, h:1, ratio:3}); |
|
218 curRatio = metas[vp].ratio; |
|
219 savePlay = paramPlay; |
|
220 if(live==true){ |
|
221 savePlay = true; |
|
222 flvPB.play(path, NaN, true); |
|
223 } |
|
224 else flvPB.load(path); // Then the window will be resized on metadata received |
|
225 //trace("LoadMedia flvPB.volume : " + flvPB.volume); |
|
226 // sets the volume to 0 (to avoid a bug) then sets it back to its previous level |
|
227 flvPB.volume = 0; |
|
228 flvPB.volume = vol; |
|
229 } |
|
230 else{ |
|
231 // We activate the good video player index |
|
232 flvPB.activeVideoPlayerIndex = flvPB.visibleVideoPlayerIndex = vp; |
|
233 flvPB.smoothing = true; |
|
234 //trace("vp = " + flvPB.activeVideoPlayerIndex + ", " + flvPB.isLive); |
|
235 //trace("je play " + vp + ", " + path); |
|
236 if(allowFlvPB()){ savePlay==false ? flvPB.pause() : flvPB.play(); } |
|
237 // sets the volume to 0 (to avoid a bug) then sets it back to its previous level |
|
238 flvPB.volume = 0; |
|
239 flvPB.volume = vol; |
|
240 // We have to resize the window |
|
241 curRatio = metas[vp].ratio; |
|
242 initSizes(); |
|
243 } |
|
244 // If a subtitle path is indicated we display it |
|
245 var ext:String = firstST.toLowerCase().substr(firstST.length-3); |
|
246 if(ext=="xml"){ |
|
247 caption.source = firstST; |
|
248 } |
|
249 else if(ext=="srt"){ |
|
250 caption.loadSrt(firstST); |
|
251 } |
|
252 // We set the caption/subtitles module to the good videoPlayerIndex index |
|
253 caption.videoPlayerIndex = vp; |
|
254 } |
|
255 } |
|
256 private function getVp(path:String):Number{ |
|
257 |
|
258 // We check if the media is already loaded |
|
259 var i:uint = 0; |
|
260 var nbMedias:uint = metas.length; |
|
261 var vp:Number = NaN; |
|
262 while(i<nbMedias && isNaN(vp)){ |
|
263 if(metas[i].path==path){ |
|
264 vp = i; |
|
265 } |
|
266 i++; |
|
267 } |
|
268 return vp; |
|
269 |
|
270 } |
|
271 |
|
272 // |
|
273 // Function allowing to go to the wanted timecode. TC is in milliseconds, paramPlay enable to play or pause the video |
|
274 // |
|
275 public function goTo(tc:Number=0, paramPlay:Boolean=true):void{ |
|
276 |
|
277 //trace("goto " + paramPlay + ", flvPB.isLive = " + flvPB.isLive); |
|
278 if((flvPB.isLive==false && allowFlvPB()) && metas.length>0 && (YTPlayer==null || !YTPlayer.visible)){ |
|
279 // It appears that we have some problems when the video is streamed : |
|
280 // if we ask seek while the video is being played, the server plays the video from the beginning, |
|
281 // so we have to pause it first. |
|
282 if((metas[flvPB.visibleVideoPlayerIndex].path.substr(0,4).toLowerCase()=="rtmp") && paramPlay){ |
|
283 if(allowFlvPB()) flvPB.pause(); |
|
284 } |
|
285 if(allowFlvPB()) flvPB.seek(tc/1000); |
|
286 savePlay = paramPlay; |
|
287 } |
|
288 else if(YTPlayer!=null){ |
|
289 if(YTPlayer.visible){ |
|
290 YTPlayer.goTo(tc/1000, paramPlay); |
|
291 } |
|
292 } |
|
293 |
|
294 } |
|
295 |
|
296 // |
|
297 // Function enabling to know the flvPB is playing (or pause) |
|
298 // |
|
299 public function isPlaying():Boolean{ return flvPB.playing; } |
|
300 |
|
301 // |
|
302 // Function enabling to switch play-pause and pause-play |
|
303 // |
|
304 public function playPause():void{ |
|
305 //trace(this.name + " playPause " + babRunning + ", flvPB.playing = " + flvPB.playing); |
|
306 if(babRunning==false){ |
|
307 if(flvPB.playing==true){ |
|
308 if(allowFlvPB()) flvPB.pause(); |
|
309 savePlay = false; |
|
310 } |
|
311 else{ |
|
312 if(allowFlvPB()) flvPB.play(); |
|
313 savePlay = true; |
|
314 } |
|
315 } |
|
316 else onEditPlayPause(); |
|
317 } |
|
318 public function play():void{ |
|
319 if(allowFlvPB()) flvPB.play(); |
|
320 savePlay = true; |
|
321 } |
|
322 public function pause():void{ |
|
323 if(allowFlvPB()) flvPB.pause(); |
|
324 savePlay = false; |
|
325 } |
|
326 public function stop():void{ |
|
327 if(metas.length>0 && allowFlvPB()){ flvPB.stop(); } |
|
328 savePlay = false; |
|
329 if(babRunning==true){ |
|
330 if(babRunningTimer!=null){ if(babRunningTimer.running==true){ babRunningTimer.stop(); } } |
|
331 babRunning = false; |
|
332 } |
|
333 } |
|
334 |
|
335 // |
|
336 // Manage video events |
|
337 // |
|
338 private function onMDReceived(e:MetadataEvent):void{ |
|
339 /*var o:Object; |
|
340 trace("MD"); |
|
341 for(o in e.info){ |
|
342 trace(o + " : " + e.info[o.toString()]); |
|
343 }*/ |
|
344 if(e.info["duration"]!=null){ |
|
345 //(this.parentApplication as LignesDeTempsFlex).debug.text += "\nw = " + e.info["width"] + "\nh = " + e.info["height"] + "\ndur = " + e.info["duration"]; |
|
346 } |
|
347 var w:uint = Math.max(3, uint(e.info["width"])); |
|
348 var h:uint = Math.max(1, uint(e.info["height"])); |
|
349 metas[e.vp].w = w; |
|
350 metas[e.vp].h = h; |
|
351 metas[e.vp].ratio = w/h; |
|
352 if(e.vp==flvPB.activeVideoPlayerIndex){ |
|
353 // If we load the content for a bout à bout (edit), we force the ratio at the bab Ratio |
|
354 curRatio = (babRunning==true) ? babRatio : metas[e.vp].ratio; |
|
355 initSizes(); |
|
356 } |
|
357 |
|
358 } |
|
359 private function getInfoID3(e:Event):void{ |
|
360 var o:Object; |
|
361 trace("getInfoID3"); |
|
362 for(o in e){ |
|
363 trace(o + " : " + e[o.toString()]); |
|
364 } |
|
365 } |
|
366 private function onStateChange(e:VideoEvent=null):void { |
|
367 // If the user is not allowed to read the whole media, we hide the SeekBarHit |
|
368 //if(Config.readFullLength==false) flvPB.hideSeekBarHit(); |
|
369 // We display an alert message if there is a connection error |
|
370 dispatchEvent(new VideoEvent(VideoEvent.STATE_CHANGE, false, false, e.state)); |
|
371 if(e.state==VideoState.CONNECTION_ERROR){ |
|
372 //Alert.show("The player can not find the video file :\n" + metas[e.vp].path, "No video file"); |
|
373 } |
|
374 } |
|
375 private function allowFlvPB():Boolean{ |
|
376 return (flvPB.state!=VideoState.CONNECTION_ERROR && flvPB.state!=VideoState.DISCONNECTED); |
|
377 } |
|
378 private function onReady(e:VideoEvent=null):void { |
|
379 //trace("onReady savePlay = " + savePlay); |
|
380 // We have to do that to force pause on load |
|
381 if(allowFlvPB()){ savePlay==false ? flvPB.pause() : flvPB.play(); } |
|
382 } |
|
383 private function onSeeked(e:VideoEvent):void { |
|
384 //trace(name + " onSeeked savePlay = " + savePlay); |
|
385 loading.visible = false; |
|
386 // We have to do that to force pause on load |
|
387 if(allowFlvPB()){ savePlay==false ? flvPB.pause() : flvPB.play(); } |
|
388 } |
|
389 public function onPlayheadUpdate(e:VideoEvent):void { |
|
390 //trace("onPU " + e.state + ", " + e.playheadTime + ", " + babRunning);//editList[curInst].tOut + ", " + |
|
391 if(e.state=="seeking"){ loading.visible = true; } |
|
392 if(babRunning==false && writeTC==true){ |
|
393 tcLabel.text = "[" + convertTC(e.playheadTime*1000, false) + "]"; |
|
394 this.dispatchEvent(e); |
|
395 } |
|
396 else if(babRunning==true){ |
|
397 if(e.playheadTime>=editList[curInst].tOut && e.state=="playing"){ |
|
398 playBabInst(curInst+1); |
|
399 } |
|
400 //var tcBab:Number; |
|
401 if(mediaList[editList[curInst].m].type=="v"){ |
|
402 //trace(editList[curInst].eIn + ", " + e.playheadTime + ", " + editList[curInst].tIn + ", diff = " + (editList[curInst].tIn - e.playheadTime)); |
|
403 // If the current playheadTime is inferior to editList[curInst].tIn more than 2 seconds, we reseek to the tIn |
|
404 if((editList[curInst].tIn - e.playheadTime)>3){ |
|
405 if(allowFlvPB()) flvPB.seek(editList[curInst].tIn); |
|
406 } |
|
407 else{ |
|
408 // We apply max : because of the playhead's approximation, e.playheadTime can be inferior to tIn |
|
409 currentTcBab = Math.max(editList[curInst].eIn*1000,(editList[curInst].eIn + e.playheadTime - editList[curInst].tIn)*1000); |
|
410 //currentTcBab = tcBab; |
|
411 tcLabel.text = "[" + convertTC(currentTcBab, false) + "]"; |
|
412 this.dispatchEvent(new EditEvent(EditEvent.EDIT_UPDATETC, currentTcBab)); |
|
413 } |
|
414 } |
|
415 else if(mediaList[editList[curInst].m].type=="p" || mediaList[editList[curInst].m].type=="t"){ |
|
416 currentTcBab = (editList[curInst].eIn)*1000; |
|
417 tcLabel.text = "[" + convertTC(currentTcBab, false) + "]"; |
|
418 this.dispatchEvent(new EditEvent(EditEvent.EDIT_UPDATETC, currentTcBab)); |
|
419 } |
|
420 } |
|
421 } |
|
422 |
|
423 // |
|
424 // Set the good sizes function of the ratio |
|
425 // |
|
426 public function initSizes(e:VideoEvent=null):void{ |
|
427 // We set hMin and wMin for the video to take the maximum of space. wMax = 415, hMax = 310 |
|
428 /*if((Math.round(424/curRatio)+24+37)>310){ |
|
429 hMin = 310; |
|
430 wMin = (310-24-37)*curRatio; |
|
431 } |
|
432 else{ |
|
433 wMin = 415; |
|
434 hMin = Math.round(wMin/curRatio) + 24 + 37; |
|
435 } |
|
436 if(width<wMin) {} |
|
437 else{ |
|
438 height = Math.round(width/curRatio) + 24 + 37; |
|
439 }*/ |
|
440 } |
|
441 |
|
442 |
|
443 // |
|
444 // Function enabling to take or let control of the timecode label |
|
445 // |
|
446 public function set manageEventTimer(b:Boolean):void{ |
|
447 writeTC = b; |
|
448 } |
|
449 public function set tcText(s:String):void{ |
|
450 tcLabel.text = s; |
|
451 } |
|
452 |
|
453 |
|
454 private function onResize():void{ |
|
455 setSize(wMin, hMin - 37); |
|
456 } |
|
457 public function setSize(w:uint, h:uint):void{ |
|
458 //trace("setSize " + w + ", " + h); |
|
459 if(h<1000){ // avoids resize problems if metadatas were not good |
|
460 //mcContainer.width = imageLayer.width = widthFlv = w; |
|
461 //mcContainer.height = imageLayer.height = heightFlv = h; |
|
462 imageLayer.width = widthFlv = w; |
|
463 imageLayer.height = heightFlv = h; |
|
464 loading.y = heightFlv - 16; |
|
465 tcLabel.y = heightFlv; |
|
466 //if(metas.length==1 && metas[0]["path"].search("mp3:")>-1){ |
|
467 flvPB.setSize(widthFlv,heightFlv); |
|
468 flvPB.scaleMode = VideoScaleMode.MAINTAIN_ASPECT_RATIO; |
|
469 if(babSkin!=null){ |
|
470 babSkin.y = heightFlv - 3; |
|
471 babSkin.getChildAt(0).width = widthFlv; |
|
472 } |
|
473 var nbChilds:uint = imageLayer.numChildren; |
|
474 for(var i:uint=0;i<nbChilds;i++){ |
|
475 imageLayer.getChildren()[i].width = widthFlv; |
|
476 imageLayer.getChildren()[i].height = heightFlv; |
|
477 } |
|
478 if(YTPlayer!=null) YTPlayer.setSize(widthFlv,heightFlv); |
|
479 } |
|
480 |
|
481 } |
|
482 |
|
483 // |
|
484 // BOUT A BOUT (EDIT) FUNCTIONS |
|
485 // |
|
486 public function getEditList(editListPar:Array, mediaListPar:Array):void{ |
|
487 //if(Global.flv2==name) trace("flv getEditList " + editListPar.length + ", " + mediaListPar.length); |
|
488 if(mediaListPar.length>0 && editListPar.length>0){ |
|
489 instanceToPlay = 0; |
|
490 curInst = -1; |
|
491 // We don't display the different layers |
|
492 textLayer.visible = false; |
|
493 mcContainer.visible = false; |
|
494 imageLayer.visible = false; |
|
495 flvPB.visible = false; |
|
496 // We search for every media |
|
497 var i:uint; |
|
498 editList = editListPar; |
|
499 mediaList = mediaListPar; |
|
500 var nbMedias:uint = mediaList.length; |
|
501 var nbLoaded:uint = metas.length; |
|
502 var canStart:Boolean = true; |
|
503 var a:Array = new Array(); |
|
504 for(i=0;i<nbMedias;i++){ |
|
505 // We check if the videos are not already loaded |
|
506 if(mediaList[i].type=="v"){ |
|
507 var found:Boolean = false; |
|
508 var j:uint = 0; |
|
509 while(j<nbLoaded && found==false){ |
|
510 if(metas[j].path==mediaList[i].content){ found = true; } |
|
511 j++; |
|
512 } |
|
513 // If the path was not found, we load the media |
|
514 if(nbLoaded==0 || found==false){ |
|
515 loadMedia(mediaList[i].content); |
|
516 } |
|
517 } |
|
518 // We load every picture before the bout a bout starts |
|
519 else if(mediaList[i].type=="p"){ |
|
520 canStart = false; |
|
521 // We add the Global.projPath to the pict url when its path is relative (= "_resources/...") |
|
522 //a.push( ((mediaList[i].content.substr(0,9)=="_resource") ? Global.projPath : "") + mediaList[i].content); |
|
523 a.push(mediaList[i].content); |
|
524 } |
|
525 } |
|
526 if(canStart==true) startBab(); |
|
527 else{ |
|
528 // We delete doubloons |
|
529 a.sort(Array.CASEINSENSITIVE); |
|
530 for(i=0;i<a.length;i++){ |
|
531 if(a[i]==a[i+1] || a[i]==""){ |
|
532 a.splice(i,1); |
|
533 i--; // We do i-- because we spliced an index so we have to redo the test at "i" position |
|
534 } |
|
535 } |
|
536 loadPicts(a); |
|
537 } |
|
538 |
|
539 } |
|
540 |
|
541 } |
|
542 // |
|
543 // Image load management |
|
544 // |
|
545 private function loadPicts(a:Array):void{ |
|
546 |
|
547 var i:uint; |
|
548 // We delete the old pictures |
|
549 pictAr = []; |
|
550 var nbChilds:uint = imageLayer.getChildren().length; |
|
551 for(i=0;i<nbChilds;i++){ |
|
552 imageLayer.removeChildAt(0); |
|
553 } |
|
554 // We add the new ones |
|
555 var nbPict:uint = a.length; |
|
556 nbPictLoaded = 0; |
|
557 if(nbPict>0){ |
|
558 // We prepare pictAr |
|
559 for(i=0;i<nbPict;i++){ |
|
560 pictAr.push({src:a[i], img:null}); |
|
561 } |
|
562 loadPict(a[0]); |
|
563 } |
|
564 else startBab(); |
|
565 |
|
566 } |
|
567 private function loadPict(src:String):void{ |
|
568 |
|
569 var nbPict:uint = pictAr.length; |
|
570 var i:uint = 0; |
|
571 var found:Boolean = false; |
|
572 while(i<nbPict && found==false){ |
|
573 if(pictAr[i].src==src && pictAr[i].img!=null){ found = true; } |
|
574 i++; |
|
575 } |
|
576 if(found==false){ |
|
577 var img:Image = new Image(); |
|
578 img.width = widthFlv; |
|
579 img.height = widthFlv / babRatio; |
|
580 //img.setStyle("horizontalAlign","center"); |
|
581 //img.setStyle("verticalAlign","center"); |
|
582 //img.maintainAspectRatio = true; |
|
583 img.y = 0; |
|
584 img.addEventListener(Event.INIT, imgComplete); |
|
585 img.addEventListener(IOErrorEvent.IO_ERROR, imgError); |
|
586 pb.visible = true; |
|
587 //pb.label = "Loading picture " + (nbPictLoaded+1) + " %3%%"; |
|
588 pb.source = img; |
|
589 // trace("load img :\n" + src); |
|
590 // (this.parentApplication as LignesDeTempsFlex).debug.text += "\nload img :\n" + src; |
|
591 img.source = src; |
|
592 img.visible = false; |
|
593 imageLayer.addChild(img); |
|
594 } |
|
595 else{ |
|
596 nbPictLoaded++; |
|
597 if(nbPictLoaded==nbPict) startBab(); |
|
598 } |
|
599 //(this.parentApplication as LignesDeTempsFlex).debug.text += "\nload img" + src |
|
600 |
|
601 } |
|
602 private function imgError(e:IOErrorEvent):void { |
|
603 // We don't display the progress bar anymore |
|
604 pb.visible = false; |
|
605 // We update pictAr |
|
606 var img:Image = e.target as Image; |
|
607 var src:String = img.source as String; |
|
608 // trace("imgError :\n" + src); |
|
609 // (this.parentApplication as LignesDeTempsFlex).debug.text += "\nimgError" + src; |
|
610 loadNextPict(src, img); |
|
611 |
|
612 } |
|
613 private function imgComplete(e:Event):void { |
|
614 // We don't display the progress bar anymore |
|
615 pb.visible = false; |
|
616 // We update pictAr |
|
617 var img:Image = e.target as Image; |
|
618 var src:String = img.source as String; |
|
619 // trace("imgComplete :\n" + src); |
|
620 // (this.parentApplication as LignesDeTempsFlex).debug.text += "\nimgComplete" + src; |
|
621 loadNextPict(src, img); |
|
622 } |
|
623 private function loadNextPict(src:String, img:Image):void{ |
|
624 var nbPict:uint = pictAr.length; |
|
625 var i:uint = 0; |
|
626 var found:Boolean = false; |
|
627 while(i<nbPict && found==false){ |
|
628 if(pictAr[i].src==src){ |
|
629 found = true; |
|
630 pictAr[i].img = img; |
|
631 } |
|
632 i++; |
|
633 } |
|
634 nbPictLoaded++; |
|
635 if(nbPictLoaded==nbPict){ |
|
636 // Because of the time needed when we load picture, BaB can start before all pictures are loaded |
|
637 // So we curInst we recall set curInst at -1 in order to call startBab at the correct time. |
|
638 curInst = -1; |
|
639 startBab(); |
|
640 } |
|
641 else loadPict(pictAr[nbPictLoaded].src); |
|
642 } |
|
643 private function displayPict(src:String):void{ |
|
644 |
|
645 var nbPict:uint = pictAr.length; |
|
646 for(var i:uint=0;i<nbPict;i++){ |
|
647 if(pictAr[i].src==src && pictAr[i].img!=null){ |
|
648 // trace("img vis : " + pictAr[i].src + " : " + pictAr[i].img); |
|
649 // (this.parentApplication as LignesDeTempsFlex).debug.text += "\nimg vis : " + pictAr[i].src + " : " + pictAr[i].img; |
|
650 pictAr[i].img.visible = true; |
|
651 } |
|
652 else if(pictAr[i].img!=null){ pictAr[i].img.visible = false; } |
|
653 } |
|
654 |
|
655 } |
|
656 // |
|
657 // Bab timer management |
|
658 // |
|
659 private function completeTimer(e:TimerEvent):void { |
|
660 //trace("completeTimer"); |
|
661 babRunningTimer.stop(); |
|
662 babRunningTimer.removeEventListener(TimerEvent.TIMER, onRunningTimer); |
|
663 babRunningTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,completeTimer); |
|
664 playBabInst(curInst+1); |
|
665 } |
|
666 private function onRunningTimer(e:TimerEvent):void { |
|
667 //trace("onRunningTimer " + babRunningTimer.currentCount + " sur " + babRunningTimer.repeatCount); |
|
668 currentTcBab = editList[curInst].eOut*1000 - (babRunningTimer.repeatCount-babRunningTimer.currentCount)*250; |
|
669 tcLabel.text = "[" + convertTC(currentTcBab, false) + "]"; |
|
670 //(this.parentApplication as LignesDeTempsFlex).debug.text += "[" + convertTC(tcBab, false) + "]"; |
|
671 dispatchEvent(new EditEvent(EditEvent.EDIT_UPDATETC, currentTcBab)); |
|
672 } |
|
673 private function onEditPlayPause(e:EditEvent=null):void{ |
|
674 //trace(this.name + " onEditPlayPause " + mediaList[editList[curInst].m].type); |
|
675 if(babRunning==true){ |
|
676 var tcBab:Number; |
|
677 if(mediaList[editList[curInst].m].type=="v"){ |
|
678 //flvPB.playing==true ? (flvPB.pause();trace("je pause");) : (flvPB.play();trace("je play");); |
|
679 if(flvPB.playing==true){ |
|
680 if(allowFlvPB()) flvPB.pause(); |
|
681 editSkin.isPlaying = false; |
|
682 }else{ |
|
683 savePlay = true; |
|
684 if(allowFlvPB()) flvPB.play(); |
|
685 editSkin.isPlaying = true; |
|
686 } |
|
687 } |
|
688 else if(mediaList[editList[curInst].m].type=="p" || mediaList[editList[curInst].m].type=="t"){ |
|
689 if(babRunningTimer!=null){ |
|
690 if(babRunningTimer.running==true){ |
|
691 babRunningTimer.stop(); |
|
692 editSkin.isPlaying = false; |
|
693 //trace("after stop " + babRunningTimer.currentCount + " sur " + babRunningTimer.repeatCount); |
|
694 } |
|
695 else{ |
|
696 var newNb:uint = babRunningTimer.repeatCount - babRunningTimer.currentCount; |
|
697 babRunningTimer = new Timer(250, newNb); |
|
698 //trace("je reprends " + babRunningTimer.currentCount + " sur " + newNb); |
|
699 babRunningTimer.addEventListener(TimerEvent.TIMER, onRunningTimer); |
|
700 babRunningTimer.addEventListener(TimerEvent.TIMER_COMPLETE, completeTimer); |
|
701 babRunningTimer.start(); |
|
702 editSkin.isPlaying = true; |
|
703 } |
|
704 } |
|
705 } |
|
706 } |
|
707 } |
|
708 // |
|
709 // Edit events functions |
|
710 // |
|
711 public function onEditBack(e:EditEvent=null):void{ |
|
712 //trace("onEditBack"); |
|
713 playBabInst(curInst-1); |
|
714 } |
|
715 public function onEditForward(e:EditEvent=null):void{ |
|
716 //trace("onEditForward"); |
|
717 playBabInst(curInst+1); |
|
718 } |
|
719 private function onEditVolumeUpdate(e:EditEvent=null):void{ |
|
720 //trace("onEditVolumeUpdate " + e.volume); |
|
721 flvPB.volume = e.volume; |
|
722 } |
|
723 |
|
724 // |
|
725 // Edit play functions |
|
726 // |
|
727 public function startBab():void{ |
|
728 trace("startBab flvPB = " + flvPB); |
|
729 try{ |
|
730 flvPB.showHideSkin(false); |
|
731 } |
|
732 catch(e:*){ trace("flvPB.showHideSkin error"); } |
|
733 curRatio = babRatio; |
|
734 //hMin = Math.round(wMin/babRatio) + 24 + 37; |
|
735 //height = Math.round(width/babRatio) + 24 + 37; |
|
736 onResize(); |
|
737 tcLabel.text = "[" + convertTC(0, false) + "]"; |
|
738 if(babSkin) { babSkin.visible = true; } |
|
739 playBabInst(instanceToPlay, false); |
|
740 onResize(); |
|
741 |
|
742 } |
|
743 public function stopBab():void{ |
|
744 //trace("stopBab"); |
|
745 textLayer.visible = false; |
|
746 mcContainer.visible = false; |
|
747 imageLayer.visible = false; |
|
748 babRunning = false; |
|
749 if(babSkin!=null){ babSkin.visible = false; } |
|
750 flvPB.visible = true; |
|
751 flvPB.showHideSkin(true); |
|
752 if(babRunningTimer!=null){ |
|
753 if(babRunningTimer.running==true){ |
|
754 babRunningTimer.stop(); |
|
755 } |
|
756 } |
|
757 curInst = -1; |
|
758 } |
|
759 |
|
760 public function playBabInst(i:uint, paramPlay:Boolean=true):void{ |
|
761 //if(Global.flv2==name) trace(name + " playBabInst change je passe a " + i + ", curInst = " + curInst + ", paramPlay = " + paramPlay); |
|
762 if(editList!=null){if(i<editList.length){ |
|
763 // We update the edit player skin |
|
764 editSkin.isPlaying = paramPlay; |
|
765 if(curInst!=i || paramPlay==true){ |
|
766 babRunning = true; |
|
767 instanceToPlay = curInst = i; |
|
768 if(babRunningTimer!=null){ if(babRunningTimer.running==true){ babRunningTimer.stop(); } } |
|
769 if(mediaList[editList[curInst].m].type=="v"){ |
|
770 // Video case |
|
771 textLayer.visible = false; |
|
772 mcContainer.visible = true; |
|
773 drawBgCtn(0x000000); // We draw a black background |
|
774 imageLayer.visible = false; |
|
775 savePlay = paramPlay || mediaList[editList[curInst].m].content.substr(0,4).toLowerCase()=="rtmp"; |
|
776 var vp:Number = getVp(mediaList[editList[curInst].m].content); |
|
777 //if(Global.flv2==name) trace(name + " vp = " + vp); |
|
778 if(flvPB.activeVideoPlayerIndex!=vp){ |
|
779 if(allowFlvPB()) flvPB.pause(); |
|
780 flvPB.activeVideoPlayerIndex = flvPB.visibleVideoPlayerIndex = vp; |
|
781 flvPB.smoothing = true; |
|
782 } |
|
783 if(allowFlvPB()){ |
|
784 // If the video is NOT streamed and savePlay==true, we play it. |
|
785 if(savePlay==true && mediaList[editList[curInst].m].content.substr(0,4).toLowerCase()!="rtmp") flvPB.play(); |
|
786 // If the video IS streamed and the player is playing, we have to pause it for the seek to work. |
|
787 if(!flvPB.paused && mediaList[editList[curInst].m].content.substr(0,4).toLowerCase()=="rtmp") flvPB.pause(); |
|
788 flvPB.seek(editList[curInst].tIn); |
|
789 } |
|
790 flvPB.visible = true; |
|
791 // sets the volume to 0 (to avoid a bug) then sets it back to its previous level |
|
792 var vol:Number = flvPB.volume; |
|
793 flvPB.volume = 0; |
|
794 flvPB.volume = vol; |
|
795 } |
|
796 else if(mediaList[editList[curInst].m].type=="p"){ |
|
797 // Picture case |
|
798 textLayer.visible = false; |
|
799 mcContainer.visible = true; |
|
800 drawBgCtn(mediaList[editList[curInst].m].color); |
|
801 imageLayer.visible = true; |
|
802 flvPB.visible = false; |
|
803 if(metas.length>0 && allowFlvPB()){ flvPB.pause(); } |
|
804 //displayPict( ((mediaList[editList[curInst].m].content.substr(0,9)=="_resource") ? Global.projPath : "") + mediaList[editList[curInst].m].content); |
|
805 displayPict(mediaList[editList[curInst].m].content); |
|
806 imageLayer.y = 0; |
|
807 babRunningTimer = new Timer(250, editList[i].tOut*4); |
|
808 //trace("je lance un timer sur " + (babAr[i].tOut*4)); |
|
809 babRunningTimer.addEventListener(TimerEvent.TIMER, onRunningTimer); |
|
810 babRunningTimer.addEventListener(TimerEvent.TIMER_COMPLETE, completeTimer); |
|
811 babRunningTimer.start(); |
|
812 if(paramPlay==false){ onEditPlayPause(); } |
|
813 } |
|
814 else if(mediaList[editList[curInst].m].type=="t"){ |
|
815 // Text case |
|
816 textLayer.visible = true; |
|
817 mcContainer.visible = true; |
|
818 drawBgCtn(mediaList[editList[curInst].m].color); |
|
819 imageLayer.visible = false; |
|
820 flvPB.visible = false; |
|
821 if(metas.length>0 && allowFlvPB()){ flvPB.pause(); } |
|
822 textLayer.htmlText = mediaList[editList[curInst].m].content; |
|
823 // If the color is clear the text will be black, if the color is dark the text will be white. |
|
824 tf.color = (RGB2L(mediaList[editList[curInst].m].color)>(255*3/2)) ? 0x000000 : 0xFFFFFF; |
|
825 textLayer.setTextFormat(tf); |
|
826 textLayer.height = Math.floor(textLayer.textHeight) + 10; |
|
827 textLayer.y = ((hMin-37-37)/2) - (textLayer.textHeight/2); |
|
828 if(babRunningTimer!=null){ |
|
829 if(babRunningTimer.running==true){ |
|
830 babRunningTimer.stop(); |
|
831 } |
|
832 } |
|
833 babRunningTimer = new Timer(250, editList[i].tOut*4); |
|
834 //trace("je lance un timer sur " + (babAr[i].tOut*4)); |
|
835 babRunningTimer.addEventListener(TimerEvent.TIMER, onRunningTimer); |
|
836 babRunningTimer.addEventListener(TimerEvent.TIMER_COMPLETE, completeTimer); |
|
837 babRunningTimer.start(); |
|
838 if(paramPlay==false){ onEditPlayPause(); } |
|
839 } |
|
840 //if(Global.flv2==name) trace(name + " playBabInst textLayer = " + textLayer.visible + ", mcContainer = " + mcContainer.visible + ", imageLayer = " + imageLayer.visible + ", flvPB = " + flvPB.visible); |
|
841 //trace("4* tcBab = " + (editList[curInst].eIn*1000)); |
|
842 currentTcBab = editList[curInst].eIn * 1000; |
|
843 dispatchEvent(new EditEvent(EditEvent.EDIT_UPDATETC, currentTcBab)); |
|
844 tcLabel.text = "[" + convertTC(currentTcBab, false) + "]"; |
|
845 } |
|
846 // Else we run the current segment from the beginning |
|
847 else if(curInst==i){ |
|
848 babRunning = true; |
|
849 if(babRunningTimer!=null){ if(babRunningTimer.running==true){ babRunningTimer.stop(); } } |
|
850 //if(Global.flv2==name) trace(name + " 2 type m = " + mediaList[editList[curInst].m].type); |
|
851 //trace("m " + mediaList[editList[curInst].m].type + ", c = " + mediaList[editList[curInst].m].content + ", col = " + mediaList[editList[curInst].m].color); |
|
852 if(mediaList[editList[curInst].m].type=="v"){ |
|
853 savePlay = paramPlay; |
|
854 //if(Global.flv2==name) trace(name + " 2 vp = " + vp); |
|
855 if(allowFlvPB()){ |
|
856 // If the video is NOT streamed and savePlay==true, we play it. |
|
857 if(savePlay==true && mediaList[editList[curInst].m].content.substr(0,4).toLowerCase()!="rtmp") flvPB.play(); |
|
858 // If the video IS streamed and the player is playing, we have to pause it for the seek to work. |
|
859 if(!flvPB.paused && mediaList[editList[curInst].m].content.substr(0,4).toLowerCase()=="rtmp") flvPB.pause(); |
|
860 flvPB.seek(editList[curInst].tIn); |
|
861 } |
|
862 } |
|
863 else if(mediaList[editList[curInst].m].type=="p"){ |
|
864 babRunningTimer = new Timer(250, editList[i].tOut*4); |
|
865 //trace("je lance un timer sur " + (editList[i].tOut*4)); |
|
866 babRunningTimer.addEventListener(TimerEvent.TIMER, onRunningTimer); |
|
867 babRunningTimer.addEventListener(TimerEvent.TIMER_COMPLETE, completeTimer); |
|
868 babRunningTimer.start(); |
|
869 if(paramPlay==false){ onEditPlayPause(); } |
|
870 } |
|
871 else if(mediaList[editList[curInst].m].type=="t"){ |
|
872 if(babRunningTimer!=null){ |
|
873 if(babRunningTimer.running==true){ |
|
874 babRunningTimer.stop(); |
|
875 } |
|
876 } |
|
877 babRunningTimer = new Timer(250, editList[i].tOut*4); |
|
878 //trace("je lance un timer sur " + (babAr[i].tOut*4)); |
|
879 babRunningTimer.addEventListener(TimerEvent.TIMER, onRunningTimer); |
|
880 babRunningTimer.addEventListener(TimerEvent.TIMER_COMPLETE, completeTimer); |
|
881 babRunningTimer.start(); |
|
882 if(paramPlay==false){ onEditPlayPause(); } |
|
883 } |
|
884 //if(Global.flv2==name) trace(name + " playBabInst 2 textLayer = " + textLayer.visible + ", mcContainer = " + mcContainer.visible + ", imageLayer = " + imageLayer.visible + ", flvPB = " + flvPB.visible); |
|
885 currentTcBab = editList[curInst].eIn * 1000; |
|
886 dispatchEvent(new EditEvent(EditEvent.EDIT_UPDATETC, currentTcBab)); |
|
887 tcLabel.text = "[" + convertTC(currentTcBab, false) + "]"; |
|
888 } |
|
889 } |
|
890 else{ |
|
891 if(metas.length>0 && allowFlvPB()){ flvPB.pause(); } |
|
892 babRunning = false; |
|
893 }} |
|
894 //if(Global.flv2==name) trace(name + " playBabInst 2 textLayer = " + textLayer.visible + ", mcContainer = " + mcContainer.visible + ", imageLayer = " + imageLayer.visible + ", flvPB = " + flvPB.visible); |
|
895 |
|
896 } |
|
897 private function drawBgCtn(col:uint):void{ |
|
898 |
|
899 var g:Graphics = bgMcCtn.graphics; |
|
900 g.clear(); |
|
901 g.beginFill(col); |
|
902 g.drawRect(0,0,wMin,hMin-39); |
|
903 g.endFill(); |
|
904 } |
|
905 |
|
906 // |
|
907 // Empties the edit arrays |
|
908 // |
|
909 public function empty():void{ |
|
910 |
|
911 editList = []; |
|
912 mediaList = []; |
|
913 babRunning = false; |
|
914 curInst = -1; |
|
915 |
|
916 } |
|
917 |
|
918 // |
|
919 // Get luminance from RGB. Luminance is the sum between the 3 values from 0 to 255 of red, green and blue. |
|
920 // |
|
921 private function RGB2L(c:uint):uint{ |
|
922 |
|
923 var r:uint = (c >> 16) & 0xFF; |
|
924 var g:uint = (c >> 8) & 0xFF; |
|
925 var b:uint = c & 0xFF; |
|
926 var l:uint = r + g + b; |
|
927 return l; |
|
928 |
|
929 } |
|
930 |
|
931 public function get volume():Number{ return flvPB.volume;} |
|
932 |
|
933 private function convertTC(monTC:Number, tenth:Boolean=true) : String { |
|
934 |
|
935 // We do this 2 divisions to keep only 1 number after "." |
|
936 monTC = Math.floor(monTC/100); |
|
937 monTC = (tenth==true) ? monTC/10 : Math.floor(monTC/10); |
|
938 var MaHeu:Number = Math.floor(monTC/3600); |
|
939 var MaMin:Number = Math.floor(monTC/60)-(60*MaHeu); |
|
940 var MaSec:Number = ((monTC*10)%600) / 10; // We have to do that because there is an incomprehensible probleme with %60 |
|
941 |
|
942 var MonTime:String = ((MaHeu<10)?"0":"") + MaHeu + ":" + ((MaMin<10)?"0":"") + MaMin + ":" + ((MaSec<10)?"0":"") + MaSec; |
|
943 return MonTime; |
|
944 |
|
945 } |
|
946 |
|
947 |
|
948 // |
|
949 // External Interface functions |
|
950 // |
|
951 public function playVideo(e:*=null):Boolean{ |
|
952 if(metas.length>0 && allowFlvPB()){ |
|
953 flvPB.play(); |
|
954 editSkin.isPlaying = true; |
|
955 } |
|
956 debugOutput("playVideo e = " + e); |
|
957 return true; |
|
958 } |
|
959 public function pauseVideo(e:*=null):Boolean{ |
|
960 if(metas.length>0 && allowFlvPB()){ |
|
961 flvPB.pause(); |
|
962 editSkin.isPlaying = false; |
|
963 } |
|
964 debugOutput("pauseVideo e = " + e); |
|
965 return true; |
|
966 } |
|
967 public function getCurrentTime(e:*=null):Number{ |
|
968 // We send in seconds |
|
969 var tc:Number = Math.floor(currentTcBab) / 1000; |
|
970 debugOutput("getCurrentTime e = " + tc); |
|
971 return tc; |
|
972 } |
|
973 public function seekTo(e:*=null):Boolean{ |
|
974 debugOutput("seekTo e = " + e); |
|
975 return true; |
|
976 } |
|
977 public function isMuted(e:*=null):Boolean{ |
|
978 var b:Boolean = (flvPB.volume==0); |
|
979 debugOutput("isMuted e = " + b); |
|
980 return b; |
|
981 } |
|
982 public function mute(e:*=null):Boolean{ |
|
983 debugOutput("mute e = " + e); |
|
984 flvPB.volume = 0; |
|
985 flvPB.volume = 0; |
|
986 return true; |
|
987 } |
|
988 public function unMute(e:*=null):Boolean{ |
|
989 debugOutput("unMute e = " + e); |
|
990 flvPB.volume = 0; |
|
991 flvPB.volume = 1; |
|
992 return true; |
|
993 } |
|
994 public function getVolume(e:*=null):Number{ |
|
995 debugOutput("getVolume e = " + volume); |
|
996 return volume; |
|
997 } |
|
998 public function setVolume(e:*=null):Boolean{ |
|
999 flvPB.volume = 0; |
|
1000 flvPB.volume = e; |
|
1001 debugOutput("setVolume e = " + e); |
|
1002 return true; |
|
1003 } |
|
1004 private function debugOutput(s:String):void{ |
|
1005 if(debugText) debugText.text = "bab " + s; |
|
1006 } |
|
1007 |
|
1008 } |
|
1009 } |