root/trunk/as2/com/jeroenwijering/players/FLVModel.as @ 1

Revision 1, 9.7 kB (checked in by jeroen, 18 months ago)

initial commit of old repository into public one

  • Property svn:executable set to *
Line 
1/**
2* FLV model class of the players MCV pattern.
3* Handles playback of FLV files, HTTP streams and RTMP streams.
4*
5* @author       Jeroen Wijering
6* @version      1.13
7**/
8
9
10import com.jeroenwijering.players.*;
11
12
13class com.jeroenwijering.players.FLVModel extends AbstractModel {
14
15
16        /** array with extensions used by this model **/
17        private var mediatypes:Array = new Array(
18                "flv","rtmp","mp4","m4v","m4a","mov","3gp","3g2");
19        /** NetConnection object reference **/
20        private var connectObject:NetConnection;
21        /** NetStream object reference **/
22        private var streamObject:NetStream;
23        /** Sound object reference **/
24        private var soundObject:Sound;
25        /** interval ID of the buffer update function **/
26        private var loadedInterval:Number;
27        /** current percentage of the video that's loaded **/
28        private var currentLoaded:Number = 0;
29        /** interval ID of the position update function **/
30        private var positionInterval:Number;
31        /** current state of the video that is playing **/
32        private var currentState:Number;
33        /** Current volume **/
34        private var currentVolume:Number;
35        /** MovieClip with "display" video Object  **/
36        private var videoClip:MovieClip;
37        /** object with keyframe times and positions, saved for PHP streaming **/
38        private var metaKeyframes:Object = new Object();
39        /** Boolean to check whether a stop event is fired **/
40        private var stopFired:Boolean = false;
41        /** Boolean to check whether a flusk event is fired **/
42        private var flushFired:Boolean = false;
43        /** Switch for FLV type currently played **/
44        private var flvType:String;
45        /** check h264 for time offset **/
46        private var isH264:Boolean;
47        /** check h264 for time offset **/
48        private var timeOffset:Number = 0;
49        /** reference to the captions object for parsing captionate data **/
50        public var capView:Object;
51        /** buffer iterator (prevents buffericon showing on slow PC's) **/
52        public var bufferCount:Number = 0;
53
54
55
56        /** Constructor **/
57        function FLVModel(vws:Array,ctr:AbstractController,cfg:Object,
58                fed:Object,fcl:MovieClip) {
59                super(vws,ctr,cfg,fed);
60                connectObject = new NetConnection();
61                videoClip = fcl;
62                if(config["smoothing"] == "false") {
63                        videoClip.display.smoothing = false;
64                        videoClip.display.deblocking = 1;
65                } else {
66                        videoClip.display.smoothing = true;
67                        videoClip.display.deblocking = 3;
68                }
69                videoClip.createEmptyMovieClip("snd",videoClip.getNextHighestDepth());
70                soundObject = new Sound(videoClip.snd);
71        };
72
73
74        /** Check which FLV type we use **/
75        private function setItem(idx:Number) {
76                super.setItem(idx);
77                if(isActive == true) {
78                        if(config["streamscript"] != undefined) {
79                                flvType = "HTTP";
80                        } else if(feeder.feed[currentItem]["type"] == "rtmp") {
81                                flvType = "RTMP";
82                        } else {
83                                flvType = "FLV";
84                        }
85                }
86        };
87
88
89        /** Start a specific video **/
90        private function setStart(pos:Number) {
91                stopFired = false;
92                flushFired = false;
93                if (pos != undefined) { currentPosition = pos; }
94                if(pos < 1) {
95                        pos = 0;
96                } else if (pos > feeder.feed[currentItem]["duration"] - 1) {
97                        pos = feeder.feed[currentItem]["duration"] - 1;
98                }
99                if (flvType=="RTMP" && feeder.feed[currentItem]["id"] != currentURL) {
100                        connectObject.connect(feeder.feed[currentItem]["file"]);
101                        currentURL = feeder.feed[currentItem]["id"];
102                        setStreamObject(connectObject);
103                        streamObject.play(currentURL);
104                } else if(flvType != "RTMP" &&
105                        feeder.feed[currentItem]["file"] != currentURL) {
106                        connectObject.connect(null);
107                        currentURL = feeder.feed[currentItem]["file"];
108                        if(flvType == "HTTP" ) {
109                                setStreamObject(connectObject);
110                                if(config["streamscript"] == "lighttpd") {
111                                        streamObject.play(currentURL);
112                                } else {
113                                        streamObject.play(config["streamscript"] +
114                                        "?file=" + currentURL);
115                                }
116                        } else {
117                                setStreamObject(connectObject);
118                                streamObject.play(currentURL);
119                        }
120                } else {
121                        if(flvType == "HTTP" && pos != undefined) {
122                                playKeyframe(currentPosition);
123                        } else if (flvType != "HTTP" && pos != undefined) {
124                                streamObject.seek(currentPosition);
125                                streamObject.pause(false);
126                        } else if(flvType == "RTMP" && currentPosition > 0 &&
127                                feeder.feed[currentItem]["duration"] == 0) {
128                                connectObject.connect(feeder.feed[currentItem]["file"]);
129                                setStreamObject(connectObject);
130                                streamObject.play(currentURL);
131                        } else {
132                                streamObject.pause(false);
133                        }
134                }
135                videoClip._visible = true;
136                videoClip._parent.thumb._visible = false;
137                clearInterval(positionInterval);
138                positionInterval = setInterval(this,"updatePosition",100);
139                clearInterval(loadedInterval);
140                loadedInterval = setInterval(this,"updateLoaded",100);
141        };
142
143
144        /** Read and broadcast the amount of the flv that's currently loaded **/
145        private function updateLoaded() {
146                var pct:Number = Math.round(streamObject.bufferLength/
147                        streamObject.bufferTime*100);
148                if(flvType == "FLV") {
149                        pct = Math.round(streamObject.bytesLoaded/
150                                streamObject.bytesTotal*100);
151                }
152                if(isNaN(pct)) {
153                        currentLoaded = 0;
154                        sendUpdate("load",0);
155                } else if (pct > 95) {
156                        clearInterval(loadedInterval);
157                        currentLoaded = 100;
158                        sendUpdate("load",100);
159                } else if (pct != currentLoaded) {
160                        currentLoaded= pct;
161                        sendUpdate("load",currentLoaded);
162                }
163        };
164
165
166        /** Read and broadcast the current position of the song **/
167        private function updatePosition() {
168                var pos = streamObject.time + timeOffset;
169                if(pos == currentPosition && currentState != 1 && stopFired != true) {
170                        if(bufferCount == 5) {
171                                currentState = 1;
172                                sendUpdate("state",1);
173                                bufferCount = 0;
174                        } else {
175                                bufferCount++;
176                        }
177                } else if (pos != currentPosition && currentState != 2) {
178                        bufferCount = 0;
179                        currentState = 2;
180                        sendUpdate("state",2);
181                } else {
182                        bufferCount = 0;
183                }
184                if (pos != currentPosition) {
185                        currentPosition = pos;
186                        sendUpdate("time",currentPosition,
187                                Math.max(feeder.feed[currentItem]["duration"]-currentPosition,0));
188                } else if (stopFired == true ||
189                        (flushFired == true && flvType != "RTMP" && bufferCount == 5)) {
190                        currentState = 3;
191                        videoClip._visible = false;
192                        videoClip._parent.thumb._visible = true;
193                        sendUpdate("state",3);
194                        sendCompleteEvent();
195                        stopFired = false;
196                        flushFired = false;
197                }
198        };
199
200
201        /** Pause the video that's currently playing. **/
202        private function setPause(pos:Number) {
203                if(pos < 1) { pos = 0; }
204                clearInterval(positionInterval);
205                if(pos != undefined) {
206                        currentPosition = pos;
207                        sendUpdate("time",currentPosition,
208                                Math.abs(feeder.feed[currentItem]["duration"]-currentPosition));
209                        streamObject.seek(currentPosition);
210                }
211                streamObject.pause(true);
212                currentState = 0;
213                sendUpdate("state",0);
214        };
215
216
217        /** Stop video and clear data. **/
218        private function setStop(pos:Number) {
219                clearInterval(loadedInterval);
220                clearInterval(positionInterval);
221                videoClip._visible = false;
222                delete currentURL;
223                delete currentLoaded;
224                delete currentPosition;
225                delete metaKeyframes;
226                currentLoaded = 0;
227                stopFired = false;
228                timeOffset = 0;
229                streamObject.close();
230                delete streamObject;
231                videoClip.display.clear();
232        };
233
234
235        /** Set volume of the sound object. **/
236        private function setVolume(vol:Number) {
237                super.setVolume(vol);
238                currentVolume = vol;
239                soundObject.setVolume(vol);
240        };
241
242
243        /** Connect a new stream object to video/audio/callbacks **/
244        private function setStreamObject(cnt:NetConnection) {
245                _root.tf.text = 'metadata!';
246                var ref = this;
247                currentLoaded = 0;
248                sendUpdate("load",0);
249                streamObject = new NetStream(cnt);
250                streamObject.setBufferTime(config["bufferlength"]);
251                streamObject.onMetaData = function(obj) {
252                        for (var i in obj) {
253                                trace(i+': '+obj[i]);
254                        }
255                        if(obj.duration > 1) {
256                                ref.feeder.feed[ref.currentItem]["duration"] = obj.duration;
257                        }
258                        if(obj.width > 10) {
259                                ref.sendUpdate("size",obj.width,obj.height);
260                        }
261                        if(obj.seekpoints != undefined) {
262                                ref.isH264 = true;
263                                ref.metaKeyframes = new Object();
264                                ref.metaKeyframes.times = new Array();
265                                ref.metaKeyframes.filepositions = new Array();
266                                for (var j in obj.seekpoints) {
267                                        ref.metaKeyframes.times.unshift(
268                                                Number(obj.seekpoints[j]['time']));
269                                        ref.metaKeyframes.filepositions.unshift(
270                                                Number(obj.seekpoints[j]['time']));
271                                }
272                        } else {
273                                ref.metaKeyframes = obj.keyframes;
274                        }
275                        if(ref.feeder.feed[ref.currentItem]['start'] > 0) {
276                                if(ref.flvType == "HTTP") {
277                                        ref.playKeyframe(ref.feeder.feed[ref.currentItem]['start']);
278                                } else if (ref.flvType == "RTMP") {
279                                        ref.setStart(ref.feeder.feed[ref.currentItem]['start']);
280                                }
281                        }
282                        delete obj;
283                        delete this.onMetaData;
284                };
285                streamObject.onStatus = function(object) {
286                        trace("status: "+object.code);
287                        if(object.code == "NetStream.Play.Stop" && ref.flvType!='RTMP') {
288                                ref.stopFired = true;
289                        } else if (object.code == "NetStream.Play.StreamNotFound") {
290                                ref.currentState = 3;
291                                ref.videoClip._visible = false;
292                                ref.sendUpdate("state",3);
293                                ref.sendCompleteEvent();
294                                ref.stopFired = false;
295                                ref.flushFired = false;
296                        } else if (object.code == "NetStream.Buffer.Flush") {
297                                ref.flushFired = true;
298                        }
299                };
300                streamObject.onPlayStatus = function(object) {
301                        if( object.code == "NetStream.Play.Complete" ||
302                                object.code == "NetStream.Play.Stop") {
303                                ref.stopFired = true;
304                        }
305                };
306                streamObject.onCaption = function(cap:Array) {
307                        ref.capView.onCaptionate(cap);
308                };
309                videoClip.display.attachVideo(streamObject);
310                videoClip.snd.attachAudio(streamObject);
311        };
312
313
314        /** Play from keyframe position from metadata **/
315        private function playKeyframe(pos:Number) {
316                for (var i=0; i< metaKeyframes.times.length; i++) {
317                        if((metaKeyframes.times[i] <= pos) &&
318                                (metaKeyframes.times[i+1] >= pos)) {
319                                if(config["streamscript"] == "lighttpd") {
320                                        streamObject.play(currentURL+"?start="+
321                                                metaKeyframes.filepositions[i]);
322                                        if(isH264 == true) {
323                                                timeOffset = metaKeyframes.filepositions[i];
324                                        }
325                                } else {
326                                        streamObject.play(config["streamscript"]+"?file="+
327                                                currentURL+"&pos="+metaKeyframes.filepositions[i]);
328                                }
329                                break;
330                        }
331                }
332        };
333
334
335}
Note: See TracBrowser for help on using the browser.