root/trunk/as3/com/jeroenwijering/models/HTTPModel.as @ 3

Revision 3, 8.0 kB (checked in by jeroen, 18 months ago)

added js initer BUT destroyed controlbar display

  • Property svn:executable set to *
Line 
1/**
2* Wrapper for playback of progressively downloaded video.
3**/
4package com.jeroenwijering.models {
5
6
7import com.jeroenwijering.events.*;
8import com.jeroenwijering.models.ModelInterface;
9import com.jeroenwijering.player.Model;
10import flash.events.*;
11import flash.display.DisplayObject;
12import flash.media.SoundTransform;
13import flash.media.Video;
14import flash.net.*;
15import flash.utils.clearInterval;
16import flash.utils.setInterval;
17
18
19public class HTTPModel implements ModelInterface {
20
21
22        /** reference to the model. **/
23        private var model:Model;
24        /** Video object to be instantiated. **/
25        private var video:Video;
26        /** NetConnection object for setup of the video stream. **/
27        private var connection:NetConnection;
28        /** NetStream instance that handles the stream IO. **/
29        private var stream:NetStream;
30        /** Sound control object. **/
31        private var transform:SoundTransform;
32        /** Interval ID for the time. **/
33        private var timeinterval:Number;
34        /** Interval ID for the loading. **/
35        private var loadinterval:Number;
36        /** Object with keyframe times and positions. **/
37        private var keyframes:Object;
38        /** Offset byteposition to start streaming. **/
39        private var offset:Number;
40        /** Offset timeposition for lighttpd streaming. **/
41        private var timeoffset:Number;
42        /** switch for h264 streaming **/
43        private var h264:Boolean;
44        /** Byteposition to which the file has been loaded. **/
45        private var loaded:Number;
46
47
48        /** Constructor; sets up the connection and display. **/
49        public function HTTPModel(mod:Model) {
50                model = mod;
51                connection = new NetConnection();
52                connection.addEventListener(NetStatusEvent.NET_STATUS,statusHandler);
53                connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR,errorHandler);
54                connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR,errorHandler);
55                connection.connect(null);
56                stream = new NetStream(connection);
57                stream.addEventListener(NetStatusEvent.NET_STATUS,statusHandler);
58                stream.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
59                stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR,errorHandler);
60                stream.bufferTime = model.config['bufferlength'];
61                stream.client = this;
62                video = new Video(320,240);
63                video.attachNetStream(stream);
64                transform = new SoundTransform();
65                stream.soundTransform = transform;
66                model.config['mute'] == true ? volume(0): volume(model.config['volume']);
67                quality(model.config['quality']);
68                offset = timeoffset = 0;
69        };
70
71
72        /** Catch security errors. **/
73        private function errorHandler(evt:ErrorEvent) {
74                model.sendEvent(ModelEvent.ERROR,{message:evt.text});
75        };
76
77
78        /** Return a keyframe byteoffset or timeoffset. **/
79        private function getOffset(pos:Number,tme:Boolean=false):Number {
80                var off = 0;
81                if(keyframes === null) {
82                        errorHandler(new ErrorEvent(ErrorEvent.ERROR,false,false,"This file has no seekpoints metadata."));
83                        return 0;
84                }
85                for (var i=0; i< keyframes.times.length; i++) {
86                        if(keyframes.times[i] <= pos && keyframes.times[i+1] >= pos) {
87                                if(tme == true) {
88                                        off = keyframes.times[i];
89                                } else {
90                                        off = keyframes.filepositions[i];
91                                }
92                                break;
93                        }
94                }
95                return off;
96        };
97
98
99        /** Load content. **/
100        public function load() {
101                stream.close();
102                var url = model.playlist[model.config['item']]['file'];
103                if(model.config["streamscript"] == "lighttpd") {
104                        if(h264) {
105                                url +='?start='+timeoffset;
106                        } else {
107                                url += '?start='+offset;
108                        }
109                } else {
110                        url = model.config["streamscript"]+"?file="+url+'&start='+offset;
111                }
112                url += '&width='+model.config['width'];
113                url += '&client='+encodeURI(model.config['client']);
114                trace(url);
115                stream.play(url);
116                clearInterval(loadinterval);
117                clearInterval(timeinterval);
118                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
119                loadinterval = setInterval(loadHandler,100);
120                timeinterval = setInterval(timeHandler,100);
121        };
122
123
124        /** Interval for the loading progress **/
125        private function loadHandler() {
126                loaded = stream.bytesLoaded;
127                var ttl = stream.bytesTotal;
128                model.sendEvent(ModelEvent.LOADED,{loaded:loaded,total:ttl+offset,offset:offset});
129                if(loaded >= ttl && loaded > 0) {
130                        clearInterval(loadinterval);
131                }
132        };
133
134
135        /** Get textdata from netstream. **/
136        public function onImageData(info:Object) {
137                var dat = new Object();
138                for(var i in info) {
139                        dat[i] = info[i];
140                }
141                model.sendEvent(ModelEvent.META,dat);
142        };
143
144
145        /** Get metadata information from netstream class. **/
146        public function onMetaData(info:Object) {
147                if(h264) { return; }
148                video.width = info.width;
149                video.height = info.height;
150                model.mediaHandler(video);
151                if(info.seekpoints) {
152                        h264 = true;
153                        keyframes = new Object();
154                        keyframes.times = new Array();
155                        keyframes.filepositions = new Array();
156                        for (var j in info.seekpoints) {
157                                keyframes.times.push(Number(info.seekpoints[j]['time']));
158                                keyframes.filepositions.push(Number(info.seekpoints[j]['offset']));
159                        }
160                } else if(info.keyframes) {
161                        keyframes = info.keyframes;
162                }
163                var dat = new Object();
164                for(var i in info) {
165                        dat[i] = info[i];
166                }
167                delete dat.seekpoints;
168                dat.keyframes = '';
169                for(var k=0; k<keyframes.times.length; k++) {
170                        dat['keyframes'] += ','+keyframes.times[k]+':'+keyframes.filepositions[k];
171                }
172                model.sendEvent(ModelEvent.META,dat);
173                if(model.playlist[model.config['item']]['start'] > 0) {
174                        seek(model.playlist[model.config['item']]['start']);
175                }
176        };
177
178
179        /** Get textdata from netstream. **/
180        public function onTextData(info:Object) {
181                var dat = new Object();
182                for(var i in info) {
183                        dat[i] = info[i];
184                }
185                model.sendEvent(ModelEvent.META,dat);
186        };
187
188
189        /** Pause playback. **/
190        public function pause() {
191                clearInterval(timeinterval);
192                stream.pause();
193                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PAUSED});
194        };
195
196
197        /** Resume playing. **/
198        public function play() {
199                stream.resume();
200                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PLAYING});
201                timeinterval = setInterval(timeHandler,100);
202        };
203
204
205        /** Change the smoothing mode. **/
206        public function seek(pos:Number) {
207                clearInterval(timeinterval);
208                var off = getOffset(pos);
209                if(off < offset || off > offset+loaded) {
210                        offset = off;
211                        timeoffset = getOffset(pos,true);
212                        load();
213                } else {
214                        if(h264) {
215                                stream.seek(pos-timeoffset);
216                        } else {
217                                stream.seek(pos)
218                        }
219                        play();
220                }
221        };
222
223
224        /** Change the smoothing mode. **/
225        public function quality(qua:Boolean) {
226                if(qua == true) {
227                        video.smoothing = true;
228                        video.deblocking = 4;
229                } else {
230                        video.smoothing = false;
231                        video.deblocking = 1;
232                }
233        };
234
235
236        /** Receive NetStream status updates. **/
237        private function statusHandler(evt:NetStatusEvent) {
238                if(evt.info.code == "NetStream.Play.Stop") {
239                        if(model.state == ModelStates.COMPLETED) {
240                                stream.close();
241                        } else {
242                                clearInterval(timeinterval);
243                                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.COMPLETED});
244                        }
245                } else if(evt.info.code == "NetStream.Play.StreamNotFound") {
246                        stop();
247                        model.sendEvent(ModelEvent.ERROR,{message:"Video stream not found: " +
248                                model.playlist[model.config['item']]['file']});
249                }
250                model.sendEvent(ModelEvent.META,{info:evt.info.code});
251        };
252
253
254        /** Destroy the HTTP stream. **/
255        public function stop() {
256                clearInterval(loadinterval);
257                clearInterval(timeinterval);
258                stream.close();
259                offset = timeoffset = 0;
260        };
261
262
263        /** Interval for the position progress **/
264        private function timeHandler() {
265                var bfr = Math.round(stream.bufferLength/stream.bufferTime*100);
266                var pos = Math.round(stream.time*10)/10;
267                if (h264) { pos += timeoffset; }
268                var dur = model.playlist[model.config['item']]['duration'];
269                if(bfr < 100 && pos < Math.abs(dur-stream.bufferTime-1)) {
270                        model.sendEvent(ModelEvent.BUFFER,{percentage:bfr});
271                        if(model.state != ModelStates.BUFFERING) {
272                                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
273                        }
274                } else if (model.state == ModelStates.BUFFERING) {
275                        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PLAYING});
276                }
277                if(dur > 0) {
278                        model.sendEvent(ModelEvent.TIME,{position:pos,duration:dur});
279                }
280        };
281
282
283        /** Set the volume level. **/
284        public function volume(vol:Number) {
285                transform.volume = vol/100;
286                stream.soundTransform = transform;
287        };
288
289
290};
291
292
293}
Note: See TracBrowser for help on using the browser.