source: trunk/as3/com/jeroenwijering/models/SmoothModel.as @ 355

Revision 355, 6.2 KB checked in by jeroen, 4 years ago (diff)

increased the resolution of smoothmodel position interval

  • Property svn:executable set to *
Line 
1/**
2* Model that smoothly plays back a video segmented in smaller chunks.
3**/
4package com.jeroenwijering.models {
5
6
7import com.jeroenwijering.events.*;
8import com.jeroenwijering.models.AbstractModel;
9import com.jeroenwijering.parsers.SmoothParser;
10import com.jeroenwijering.player.Model;
11
12import flash.display.Sprite;
13import flash.events.*;
14import flash.media.*;
15import flash.net.*;
16import flash.utils.*;
17
18
19public class SmoothModel extends AbstractModel {
20
21
22        /** Currently playing chunk. **/
23        private var chunk:Number;
24        /** Chunk that is up next. **/
25        private var next:Number;
26        /** All available video chunks. **/
27        private var chunks:Array;
28        /** Container that switches the two video objects. **/
29        private var container:Sprite;
30        /** Index metadata of the stream. **/
31        private var index:Object;
32        /** ID for the position interval. **/
33        private var interval:Number;
34        /** Currently active level. **/
35        private var level:Number = 0;
36        /** All available quality levels. **/
37        private var levels:Array;
38        /** Loader that loads the manifest XML file. **/
39        private var loader:URLLoader;
40        /** Soundtransform object. **/
41        private var transform:SoundTransform;
42
43
44        /** Constructor; sets up the connection and display. **/
45        public function SmoothModel(mod:Model):void {
46                super(mod);
47                container = new Sprite();
48                container.graphics.drawRect(0,0,320,240);
49                loader = new URLLoader();
50                loader.addEventListener(Event.COMPLETE, loaderHandler);
51                loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,errorHandler);
52                loader.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
53                transform = new SoundTransform();
54        };
55
56
57        /** Catch playback errors. **/
58        private function errorHandler(evt:ErrorEvent):void {
59                stop();
60                model.sendEvent(ModelEvent.ERROR,{message:evt.text});
61        };
62
63
64        /** Load content. **/
65        override public function load(itm:Object):void {
66                item = itm;
67                level = 0;
68                chunk = 0;
69                position = item['start'];
70                if(model.config['mute']) {
71                         transform.volume = 0;
72                } else {
73                         transform.volume = model.config['volume']/100;
74                }
75                loader.load(new URLRequest(item['file']));
76                model.mediaHandler(container);
77                model.sendEvent(ModelEvent.BUFFER,{percentage:0});
78                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
79        };
80
81
82        /** Load a chunk for playback. **/
83        private function loadChunk(chk:Number):void {
84                //var url:String = item['file'].substr(0,item['file'].length-3)+'mp4';
85                var url:String = 'http://h264.code-shop.com:8080/ccc.mp4';
86                url += '?start='+chunks[chk]['start'];
87                url += '&end='+chunks[chk]['end'];
88                chunks[chk].connection = new NetConnection();
89                chunks[chk].connection.connect(null);
90                chunks[chk].netstream = new NetStream(chunks[chk].connection);
91                chunks[chk].netstream.client = new Object();
92                chunks[chk].netstream.soundTransform = transform;
93                chunks[chk].netstream.play(url);
94                chunks[chk].netstream.pause();
95                chunks[chk].video = new Video(320,240);
96                chunks[chk].video.smoothing = model.config['smoothing'];
97                chunks[chk].video.visible = false;
98                chunks[chk].video.attachNetStream(chunks[chk].netstream);
99                container.addChild(chunks[chk].video);
100                next = chk;
101        };
102
103
104        /** Start playing a chunk. **/
105        private function playChunk(chk:Number=0):void {
106                chunks[chk].netstream.resume();
107                chunks[chk].video.visible = true;
108                chunk = chk;
109        };
110
111
112        /** Remove the current chunk. **/
113        private function killChunk(chk:Number):void {
114                if(chunks[chk] && chunks[chk].netstream) {
115                        chunks[chk].netstream.close();
116                }
117        };
118
119
120        /** Get the metadata, levels and chunks from the manifest. **/
121        private function loaderHandler(evt:Event):void {
122                var xml:XML = XML(evt.target.data);
123                index = SmoothParser.parseIndex(xml);
124                model.sendEvent(ModelEvent.META,index);
125                levels = SmoothParser.parseLevels(xml);
126                chunks = SmoothParser.parseChunks(xml);
127                if(levels.length == 0 || chunks.length == 0) {
128                        errorHandler(new ErrorEvent(ErrorEvent.ERROR,false,false,
129                                "SmoothStreaming manifest contains no quality levels or chunks."))
130                } else {
131                        setLevel();
132                        seek(item['start']);
133                }
134        };
135
136
137        /** Pause playback. **/
138        override public function pause():void {
139                chunks[chunk].netstream.pause();
140                clearInterval(interval);
141                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PAUSED});
142        };
143
144
145        /** Resume playing. **/
146        override public function play():void {
147                chunks[chunk].netstream.resume();
148                interval = setInterval(positionInterval,40);
149                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PLAYING});
150        };
151
152
153        /** Interval for the position progress **/
154        private function positionInterval():void {
155                var chk:Number = chunk;
156                var obj:Object = chunks[chunk];
157                var pos:Number = obj['start']+obj.netstream.time;
158                if(model.config['state'] != ModelStates.PLAYING) {
159                        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PLAYING});
160                }
161                if(pos > obj['end']-0.15) {
162                        setTimeout(killChunk,2000,chk);
163                        playChunk(chk+1);
164                        setTimeout(loadChunk,1000,chk+2);
165                }
166                if(pos < item['duration']) {
167                        pos = Math.round(pos*10)/10;
168                        if(pos != position) {
169                                position = pos;
170                                model.sendEvent(ModelEvent.TIME,{position:pos,duration:item['duration'],chunk:chk});
171                        }
172                } else if (item['duration'] > 0) {
173                        obj.netstream.pause();
174                        clearInterval(interval);
175                        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.COMPLETED});
176                }
177        };
178
179
180        /** Seek to a new position. **/
181        override public function seek(pos:Number):void {
182                position = pos;
183                clearInterval(interval);
184                killChunk(chunk);
185                killChunk(next);
186                for (var i:Number=0; i<chunks.length; i++) {
187                        if(chunks[i]['end'] > pos && chunks[i]['start'] <= pos) {
188                                loadChunk(i);
189                                playChunk(i);
190                                setTimeout(loadChunk,1000,i+1);
191                                break;
192                        }
193                }
194                interval = setInterval(positionInterval,40);
195                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
196        };
197
198
199        /** Set a specific stream level. **/
200        private function setLevel():void {
201                level = 0;
202                model.sendEvent(ModelEvent.META,levels[level]);
203        };
204
205
206        /** Destroy the video. **/
207        override public function stop():void {
208                killChunk(chunk);
209                killChunk(next);
210                clearInterval(interval);
211                position = item['start'];
212                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.IDLE});
213        };
214
215
216        /** Set the volume level. **/
217        override public function volume(vol:Number):void {
218                transform.volume = vol/100;
219                chunks[chunk].netstream.soundTransform = transform;
220        };
221
222
223};
224
225
226}
Note: See TracBrowser for help on using the repository browser.