分段播放的flash播放器

效果:

视频分段好处显而易见,就是节省流量,因为看视频很多时候都不会看完,还有很多时候是跳着看的。还有的时候也许用户暂停视频出去买东西了。。。

本文不讨论flash rtmp直播流,例子用的是普通的http流,视频7分钟一段,播放至当前视频的90%时开始加载下一段。

原理很简单,就是伪视频流和对播放时间的判断,还有一些小的细节。

关于视频伪流技术(pseudo streaming)可以参考flowplayer的这篇介绍http://flash.flowplayer.org/plugins/streaming/pseudostreaming.html,简单说就是这个东西可以让用户不用等视频缓冲到后面就可以点击后面没缓冲的位置播放,这点很实用。

1.安装服务器视频模块,让服务器支持客户端发出的对视频相应帧的请求。我的是apache httpd

LoadModule flvx_module modules/mod_flvx.so
LoadModule h264_streaming_module modules/mod_h264_streaming.so

nginx也是在编译的时候添加nginx对这两个视频格式模块的支持参数。

2.这样客户端就是可以用有start参数的链接让服务器传输从相应帧开始的视频。

对于mp4,解析出

time 0
offset 217027
time 2.333
offset 361576
time 11.733
offset 1010319

。。。。

请求格式start= _frameInfo[frame].time

flv,f4v由于格式内没有对相应帧的索引,所以必须用flvtool或yamdi添加,添加后解析出

filepositions  5388,36263,65370,93925,。。。。。。

times  0.065,0.545,1.025,1.505,1.985,。。。。。。。。

请求格式start= _frameInfo.filepositions[frame])

as

main.as

  1 package 
  2 {
  3     import flash.display.*;
  4     import ui.*;
  5     import flash.events.*;
  6     import core.*;
  7     import flash.geom.*;
  8 
  9     public class Youtube_player extends MovieClip
 10     {
 11         private var W:int = 360;
 12         private var H:int = 266;
 13         private var fullscreen:Boolean = true;
 14         private var video:String;
 15         private var thumbnail:String;
 16         private var playing:Boolean = false;
 17         private var load_relate:Boolean = false;
 18         private var autoplay:Boolean = true;
 19         private var cur_vl:VideoLoader;//当前videoloader
 20         private var loader_arr:Array;
 21         private var loading:Boolean = false;//是否在加载缓冲
 22         private var fs:Boolean = false;
 23         private var _nav_bar;
 24         private var videoHeight:int;
 25         private var videoWidth:int;
 26         private var video_index:int = 0;
 27         private var duration:int = 1232;//总时长
 28         private var part_duration:int = 420;//每段长度
 29         private var cur_total_time:int = 0;
 30         private var v:VideoLoader;//视频操作的封装类
 31         private var cur_i:int;//当前视频index
 32         private var isPlay:Boolean;
 33 
 34         var arr=['http://localhost/twitter/videos/1.mp4?'+new Date().getTime(),'http://localhost/twitter/videos/3.mp4?'+new Date().getTime(),'http://localhost/twitter/videos/4.mp4?'+new Date().getTime()];
 35         //var arr=['http://localhost/twitter/videos/2.flv?'+new Date().getTime(),'http://localhost/twitter/videos/3.flv?'+new Date().getTime(),'http://localhost/twitter/videos/4.flv?'+new Date().getTime()];
 36 
 37         public function Youtube_player()
 38         {
 39             _load_config(this.loaderInfo);
 40             _init();
 41             _init_ui(W,H);
 42             _init_events();
 43         }
 44         function resizeEvent(e:Event):void
 45         {
 46             _init_ui(stage.stageWidth, stage.stageHeight);
 47             size_screen(W,H);//重绘ui
 48         }
 49         private function add_video_listener(i:int)
 50         {
 51             var vl:VideoLoader = loader_arr[i] as VideoLoader;
 52             var vl1:VideoLoader = null;
 53             if (i<arr.length-1)
 54             {
 55                 vl1 = loader_arr[i + 1] as VideoLoader;
 56             }
 57             vl.volume(0);
 58             if (! vl.hasEventListener("playProgress"))
 59             {
 60                 vl.addEventListener("playProgress",function(){
 61                     if(vl.status=="NetStream.Seek.Notify")
 62                     buffering.visible = true;
 63                     else
 64                     buffering.visible = false;
 65                     var vl1_buffer_progress=0;
 66                     var a=vl.isFlv?cur_total_time+vl.videoTime:cur_total_time+vl.videoTime+vl.start;
 67                     if(vl.videoTime>1){
 68                         nav.progress_line.x=a/duration*nav.bar.width;
 69                         nav.notify.text=formatTime(a)+" / "+formatTime(duration);
 70                     }
 71                     if(vl1!=null&&!isNaN(vl1.bufferProgress)&&vl1.bufferProgress!=0){
 72                         vl1_buffer_progress=vl1.bufferProgress*vl1.totalTime;
 73                     }
 74                     var vl_buffer_progress=0;
 75                     if(!isNaN(vl.bufferProgress)){
 76                         vl_buffer_progress=vl.isFlv?vl.bufferProgress*(vl.totalTime-vl.start):vl.bufferProgress*vl.totalTime;
 77                     }
 78                     if(!isNaN(vl_buffer_progress)&&!isNaN(vl1_buffer_progress)){
 79                         if(i==arr.length-1||vl_buffer_progress!=0&&vl.isPlay){
 80                             nav.progressBar.width=(vl.start+vl1_buffer_progress+cur_total_time+vl_buffer_progress)/duration*nav.bar.width;
 81                         }
 82                     }
 83                     var prop=vl.isMp4?(loader_arr[cur_i].start+loader_arr[cur_i].videoTime)/(loader_arr[cur_i].totalTime+loader_arr[cur_i].start):vl.playProgress;
 84                     if(!loading&&prop>0.9&&prop<1){//播放到90%加载下一段
 85                     if(vl1!=null){
 86                         if(vl.isMp4){
 87                             vl1.metaData_loaded=false;
 88                             vl1.start=0;
 89                         }
 90                         vl1.load();
 91                         screen.setChildIndex(vl1.content,0);
 92                         vl1.pauseVideo();
 93                         loading=true;
 94                     }
 95                 }
 96                 });
 97             }
 98             if (! vl.hasEventListener("videoComplete"))
 99             {
100                 vl.addEventListener("videoComplete",function(){
101                     if(vl1!=null){
102                         screen.setChildIndex(vl1.content,screen.numChildren -1);
103                         if(!vl1.isPlay)
104                         vl1.pauseVideo();
105                         cur_i=i+1;
106                         cur_total_time=vl.isFlv?cur_total_time+vl.totalTime:cur_total_time+vl.totalTime+vl.start;
107                         loading=false;
108                     }
109                     i++;
110                     if(i<arr.length)
111                     add_video_listener(i);
112                     else{
113                         nav.progressBar.visible=false;
114                         nav.playingBar.visible=false;
115                         new Recommend(stage,W,H);
116                     }
117                     });
118                }
119             }
120             private function _init()
121             {
122             v = new VideoLoader(arr[0],{name:"myVideo0",container:screen,width:360,height:240});
123             for (var i=1,len=arr.length; i<len; i++)
124             {
125                 new VideoLoader(arr[i],{name:"myVideo" + i,container:screen,width:360,height:240});
126             }
127             loader_arr = VideoLoader.getLoader();
128             v.load();
129             cur_i = 0;
130             add_video_listener(0);//添加对每段视频的监听
131             v.addEventListener("videoStart",function(){
132                 size_screen(W,H);
133                 });
134             _nav_bar = new Nav_bar(nav,top_nav,overlay);
135             new Screen_size(stage,screen,top_nav.screen_size.size1,top_nav.screen_size.size2,top_nav.screen_size.size3);
136         }
137         private function progressBarEvent(e:MouseEvent):void//点击进度条
138         {
139             var point:Number = stage.mouseX;
140             var seekpoint:int = (point / nav.bar.width) * duration;
141             var index=Math.floor(seekpoint/part_duration);
142             var load_video:VideoLoader = loader_arr[index] as VideoLoader;
143             var load_video_buffer = loader_arr[index].bufferProgress * loader_arr[index].totalTime;
144             var seek_time = load_video.isFlv ? seekpoint % part_duration:seekpoint % part_duration - load_video.start;
145             if (isNaN(load_video_buffer)||(seekpoint%part_duration<load_video.start||seekpoint%part_duration>load_video.start+load_video_buffer))
146             {
147                 if (cur_i!=index)
148                 {
149                     add_video_listener(index);
150                     load_video.load(seekpoint % part_duration);
151                     cur_total_time = cur_total_time + part_duration * (index - cur_i);
152                     if (cur_i<loader_arr.length-1)
153                     {
154                         if (Math.abs(cur_i-index)>1)
155                         {
156                             loader_arr[cur_i + 1].netStream.close();
157                         }
158                     }
159                     loader_arr[cur_i].netStream.close();
160                     screen.setChildIndex(loader_arr[index].content,screen.numChildren -1);
161                 }
162                 else
163                 {
164                     load_video.load(seekpoint % part_duration);
165                     screen.setChildIndex(load_video.content,screen.numChildren -1);
166                 }
167             }
168             else
169             {
170                 if (cur_i==index)
171                 {
172                     load_video.seekVideo(seek_time);
173                 }
174                 else
175                 {
176                     add_video_listener(index);
177                     loader_arr[index].pauseVideo();
178                     loader_arr[index].seekVideo(seek_time);
179                     loader_arr[cur_i].netStream.close();
180                     cur_total_time = cur_total_time + part_duration * (index - cur_i);
181                     screen.setChildIndex(loader_arr[index].content,screen.numChildren -1);
182                     loading = false;
183                 }
184             }
185             cur_i = index;
186         }
187         private function _init_ui(W,H)
188         {
189             stage.scaleMode = StageScaleMode.NO_SCALE;
190             stage.align = StageAlign.TOP_LEFT;
191             new Button(nav.playButton);
192             new Button(nav.pauseButton);
193             new Button(nav.fullscreen);
194             new Button(nav.volumn_btn);
195             new Button(nav.mute);
196             this.W = W;
197             this.H = H;
198             background.x = screen.x = overlay.x = 0;
199             background.y = screen.y = overlay.y = 0;
200             background.width = overlay.width = W;
201             background.height = overlay.height = H;
202             overlay.alpha = 0;
203             buffering.x = (W - buffering.width) * .5;
204             buffering.y = (H - buffering.height) * .5;
205             nav.y = H - 26;
206             top_nav.width = nav.bar.width = W;
207             top_nav.time.x = W - 70;
208             nav.pauseButton.y = nav.playButton.y;
209             nav.progressBar.x = nav.playingBar.x = 0;
210             nav.progressBar.y = nav.playingBar.y = nav.bar.y - 10;
211             nav.seeker_time.visible = false;
212             nav.seeker_time.y = nav.progressBar.y - 20;
213             nav.seeker_time.x = 0;
214             if (fullscreen)
215             {
216                 nav.fullscreen.x = nav.bar.width - nav.fullscreen.width - 20;
217             }
218             else
219             {
220                 nav.fullscreen.visible = false;
221             }
222             nav.playingBar.width = nav.bar.width;
223             nav.notify.x = nav.volumeBar.x + nav.volumeBar.width + 10;
224             nav.progressBar.width = W;
225             if (autoplay)
226             {
227                 nav.playButton.visible = false;
228             }
229             else
230             {
231                 nav.pauseButton.visible = false;
232             }
233             nav.volumn_btn.x = nav.volumeBar.x + 36;
234             nav.y = overlay.height - 26;
235             nav.progress_line.x = top_nav.y = -30;
236             nav.seeker_time.y = nav.progressBar.y - 20;
237             nav.seeker_time.x = 0;
238             nav.hover_line.y = nav.progress_line.y = nav.progressBar.y;
239             nav.setChildIndex(nav.progress_line,nav.numChildren-1);
240             nav.setChildIndex(nav.hover_line,nav.numChildren-1);
241             nav.hover_line.visible = false;
242             nav.hover_line.buttonMode = true;
243             nav.progress_line.buttonMode = true;
244             nav.progressBar.buttonMode = true;
245             nav.playingBar.buttonMode = true;
246         }
247         private function _init_events()
248         {
249             stage.addEventListener(Event.RESIZE, resizeEvent);
250             stage.addEventListener(Event.FULLSCREEN, resizeEvent);
251             stage.addEventListener(MouseEvent.MOUSE_MOVE,_nav_bar.nav_show);
252             nav.fullscreen.addEventListener(MouseEvent.CLICK, fullscreenEvent);
253             nav.progressBar.addEventListener(MouseEvent.MOUSE_OVER, seeker_time_show);
254             nav.playingBar.addEventListener(MouseEvent.MOUSE_OVER, seeker_time_show);
255             nav.progressBar.addEventListener(MouseEvent.MOUSE_MOVE, seeker_time_show);
256             nav.playingBar.addEventListener(MouseEvent.MOUSE_MOVE, seeker_time_show);
257             nav.progressBar.addEventListener(MouseEvent.MOUSE_OUT, seeker_time_hide);
258             nav.playingBar.addEventListener(MouseEvent.MOUSE_OUT, seeker_time_hide);
259             nav.playingBar.addEventListener(MouseEvent.CLICK, progressBarEvent);
260             nav.progressBar.addEventListener(MouseEvent.CLICK, progressBarEvent);
261             nav.playButton.addEventListener(MouseEvent.CLICK, playOrpauseEvent);
262             nav.pauseButton.addEventListener(MouseEvent.CLICK, playOrpauseEvent);
263             nav.volumeBar.addEventListener(MouseEvent.CLICK, volume_bar_click);
264             nav.mute.addEventListener(MouseEvent.CLICK, volumeEvent);
265             nav.volumn_btn.addEventListener(MouseEvent.MOUSE_DOWN, volumn_btn_mouse_down);
266             stage.addEventListener(MouseEvent.MOUSE_UP, volumn_btn_mouse_up);
267             top_nav.screen_size.size3.addEventListener(MouseEvent.CLICK,size3_handler);
268         }
269         private function size3_handler(e:MouseEvent):void
270         {
271             var proportion:Number = W / H;
272             var videoproportion:Number = loader_arr[cur_i].content.width / loader_arr[cur_i].content.height;
273             if (videoproportion >= proportion)
274             {
275                 screen.width = W;
276                 screen.height = W / videoproportion;
277             }
278             else
279             {
280                 screen.width = H * videoproportion;
281                 screen.height = H;
282             }
283             screen.x = (stage.stageWidth -screen.width) *0.5;
284             screen.y = (stage.stageHeight - screen.height) *0.5;
285         }
286         private function setVolume(newVolume:Number):void
287         {
288             loader_arr[cur_i].volume(newVolume);
289             nav.mute.gotoAndStop((newVolume > 0) ? 1 : 2);
290         }
291         private function volumeEvent(event:MouseEvent):void
292         {
293             setVolume(loader_arr[cur_i].mute());
294         }
295         private function volume_bar_click(event:MouseEvent):void
296         {
297             var volume = event.localX / 140;
298             nav.mute.gotoAndStop((volume > 0) ? 1 : 2);
299             loader_arr[cur_i].volume(new Number((volume.toFixed(2))));
300             nav.volumn_btn.x = nav.volumeBar.x + event.localX;
301             event.stopPropagation();
302         }
303         private function volumn_btn_mouse_down(e:Event)
304         {
305             var rect:Rectangle = new Rectangle(nav.volumeBar.x,nav.volumn_btn.y);
306             rect.width = nav.volumeBar.width - nav.volumn_btn.width;
307             rect.height = 0;
308             e.target.startDrag(false,rect);
309             nav.volumn_btn.addEventListener(MouseEvent.MOUSE_MOVE, volumn_btn_mouse_move);
310             e.stopPropagation();
311         }
312         private function volumn_btn_mouse_move(event:MouseEvent):void
313         {
314             var volume=(nav.volumn_btn.x-nav.volumeBar.x)/(140-nav.volumn_btn.width);
315             nav.mute.gotoAndStop((volume > 0) ? 1 : 2);
316             loader_arr[cur_i].volume(new Number((volume.toFixed(2))));
317             event.stopPropagation();
318         }
319         private function volumn_btn_mouse_up(event:MouseEvent):void
320         {
321             nav.volumn_btn.stopDrag();
322             nav.volumn_btn.removeEventListener(MouseEvent.MOUSE_MOVE, volumn_btn_mouse_move);
323             event.stopPropagation();
324         }
325         private function playOrpauseEvent(event:MouseEvent):void
326         {
327             isPlay = loader_arr[cur_i].pauseVideo();
328             nav.playButton.visible = isPlay;
329             nav.pauseButton.visible = ! isPlay;
330         }
331         private function _load_config(li:LoaderInfo)
332         {
333             video = this.loaderInfo.parameters.video;
334             thumbnail = this.loaderInfo.parameters.thumbnail;
335             autoplay = this.loaderInfo.parameters.autoplay == 1;
336             load_relate = this.loaderInfo.parameters.load_relate;
337             W=this.loaderInfo.parameters.width;
338             H=this.loaderInfo.parameters.height;
339         }
340         private function size_screen(W:int,H:int):void
341         {
342             top_nav.time.x = W - 70;
343             top_nav.screen_size.size2.gotoAndStop(1);
344             top_nav.screen_size.size3.gotoAndStop(1);
345             top_nav.screen_size.size1.gotoAndStop(1);
346             top_nav.screen_size.size2.graphics.clear();
347             top_nav.screen_size.size3.graphics.clear();
348             top_nav.screen_size.size1.graphics.clear();
349             if (fs)
350             {
351                 top_nav.visible = true;
352                 var proportion:Number = W / H;
353                 var videoproportion:Number = loader_arr[cur_i].content.width / loader_arr[cur_i].content.height;
354                 if (videoproportion >= proportion)
355                 {//<= (H / W)
356                     screen.width = W;
357                     screen.height = W / videoproportion;
358                 }
359                 else
360                 {
361                     screen.width = H * videoproportion;
362                     screen.height = H;
363                 }
364                 top_nav.screen_size.size3.gotoAndStop(2);
365             }
366             else
367             {
368                 top_nav.visible = false;
369                 screen.width = loader_arr[cur_i].content.width;
370                 screen.height = loader_arr[cur_i].content.height;
371             }
372             screen.x = (stage.stageWidth -screen.width) *0.5;
373             screen.y = (stage.stageHeight - screen.height) *0.5;
374         }
375         public function fullscreenEvent(e:Event):void
376         {
377             if (stage.displayState == StageDisplayState.FULL_SCREEN)
378             {
379                 fs = false;
380                 stage.displayState = StageDisplayState.NORMAL;
381             }
382             else
383             {
384                 fs = true;
385                 stage.displayState = StageDisplayState.FULL_SCREEN;
386             }
387         }
388         private function seeker_time_show(e:MouseEvent):void
389         {
390             var target_x = stage.mouseX;
391             nav.hover_line.x = target_x;
392             if (15<target_x&&target_x<W-15)
393             {
394                 nav.hover_line.visible = true;
395                 nav.seeker_time.visible = true;
396                 nav.seeker_time.x = target_x;
397                 nav.seeker_time.mouseon_time.text = formatTime(stage.mouseX / W * duration);
398             }
399         }
400         private function seeker_time_hide(e:MouseEvent):void
401         {
402             nav.hover_line.visible = false;
403             nav.seeker_time.visible = false;
404         }
405         private function formatTime(time:Number):String
406         {
407             if (time > 0)
408             {
409                 var integer:String = String((time / 60) >> 0);
410                 var decimal:String = String((time % 60) >> 0);
411                 return ((integer.length < 2) ? "0" + integer : integer) + ":" + ((decimal.length < 2) ? "0" + decimal : decimal);
412             }
413             else
414             {
415                 return String("00:00");
416             }
417         }
418     }
419 }

VideoLoader.as

  1 package core
  2 {
  3     import flash.display.*;
  4     import flash.net.*;
  5     import flash.media.*;
  6     import flash.events.*;
  7     import flash.utils.*;
  8 
  9     public class VideoLoader extends Shape
 10     {
 11         private var nc:NetConnection;
 12         private var _ns:NetStream;
 13         private var st:SoundTransform;
 14         private var _url:String;
 15         private var vars:Object;
 16         private var v:Video;
 17         private var _status:String;
 18         private var togglepause:Boolean = false;
 19         private var _duration:int;
 20         private static var _loader = [];
 21         private var _frameInfo:Object;
 22         private var _start:Number = 0;
 23         private var _metaData_loaded:Boolean = false;
 24         private var _volcache:Number = 0;
 25         private var _isMp4:Boolean = false;
 26         private var _isFlv:Boolean = false;
 27 
 28         public function VideoLoader(url:String,vars:Object=null)
 29         {
 30             nc = new NetConnection  ;
 31             nc.connect(null);
 32             _ns = new NetStream(nc);
 33             _ns.addEventListener(NetStatusEvent.NET_STATUS,nsEvent);
 34             _ns.client = {onMetaData:this._metaDataHandler};
 35             _ns.bufferTime = 1;
 36             st = new SoundTransform  ;
 37             v = new Video  ;
 38             v.attachNetStream(_ns);
 39             getVideoType(url);
 40             this._url = url;
 41             this.vars = vars;
 42             _loader.push(this);
 43             v.smoothing = true;
 44             vars.container.addChildAt(v,0);
 45         }
 46         private function nsEvent(e:NetStatusEvent):void
 47         {
 48             if ((_status != e.info.code))
 49             {
 50                 switch (e.info.code)
 51                 {
 52                     case "NetConnection.Connect.Success" :
 53                         break;
 54                     case "NetStream.Play.Stop" :
 55                         stopVideo();
 56                         break;
 57                     case "NetStream.Play.Start" :
 58                         break;
 59                 }
 60                 _status = e.info.code;
 61                 _render();
 62             }
 63         }
 64         public function mute():Number
 65         {
 66             if (_volcache)
 67             {
 68                 st.volume = _volcache;
 69                 _ns.soundTransform = st;
 70                 _volcache = 0;
 71             }
 72             else
 73             {
 74                 _volcache = st.volume;
 75                 st.volume = 0;
 76                 _ns.soundTransform = st;
 77             }
 78             return st.volume;
 79         }
 80         public function load(start:Number=0):void
 81         {
 82             //trace(_metaData_loaded);
 83             _start = start;
 84             if (nc.connected)
 85             {
 86                 if (_metaData_loaded)
 87                 {
 88                     var frame:Number = _isFlv ? get_nearest_keyframe(_start,_frameInfo.times):get_nearest_seekpoint(_start,_frameInfo);
 89                     if (_isFlv)
 90                     {
 91                         _ns.play(((_url + "&start=") + _frameInfo.filepositions[frame]));
 92                     }
 93                     else
 94                     {
 95                         _ns.play(((_url + "&start=") + _frameInfo[frame].time));
 96                     }
 97                 }
 98                 else
 99                 {
100                     _ns.play(_url);
101                 }
102             }
103             else
104             {
105                 _ns.play(_url);
106             }
107         }
108         private function _metaDataHandler(i:Object):void
109         {
110 //            for (var j=0,len=i['seekpoints'].length; j<len; j++)
111 //            {
112 //            var h = i['seekpoints'][j];
113 //            for (var k in h)
114 //            {
115 //            trace(k+"  "+h[k]);
116 //            }
117 //            }
118 //            for (var j in i['keyframes'])
119 //            {
120 //                trace(((j + "  ") + i['keyframes'][j]));
121 //            }
122             _duration = i.duration;
123             _frameInfo = _isFlv ? i['keyframes']:i['seekpoints'];
124             if (typeof vars.width == 'undefined')
125             {
126                 v.width = i.width;
127             }
128             if (typeof vars.height == 'undefined')
129             {
130                 v.height = i.height;
131             }
132             if ((_start != 0&&!_metaData_loaded))
133             {
134                 _ns.close();
135                 var frame:Number = _isFlv ? get_nearest_keyframe(_start,_frameInfo.times):get_nearest_seekpoint(_start,_frameInfo);
136                 if (_isFlv)
137                 {
138                     _ns.play(((_url + "&start=") + _frameInfo.filepositions[frame]));
139                 }
140                 else
141                 {
142                     _ns.play(((_url + "&start=") + _frameInfo[frame].time));
143                 }
144             }
145             _metaData_loaded = true;
146         }
147         private function get_nearest_seekpoint(second:Number,seekpoints)
148         {
149             var index1 = seekpoints.length - 1;
150             var index2 = seekpoints.length - 1;
151             for (var i = 0; i != seekpoints.length; i++)
152             {
153                 if (seekpoints[i]["time"] < second)
154                 {
155                     index1 = i;
156                 }
157                 else
158                 {
159                     index2 = i;
160                     break;
161                 }
162             }
163             if (((second - seekpoints[index1]["time"]) < seekpoints[index2]["time"] - second))
164             {
165                 return index1;
166             }
167             else
168             {
169                 return index2;
170             }
171         }
172         private function get_nearest_keyframe(second:Number,keytimes)
173         {
174             var index1 = 0;
175             var index2 = 0;
176             for (var i = 0; i != keytimes.length; i++)
177             {
178                 if (keytimes[i] < second)
179                 {
180                     index1 = i;
181                 }
182                 else
183                 {
184                     index2 = i;
185                     break;
186                 }
187             }
188             if (((second - keytimes[index1]) < keytimes[index2] - second))
189             {
190                 return index1;
191             }
192             else
193             {
194                 return index2;
195             }
196         }
197         private function getVideoType(url:String):void
198         {
199             var index = url.lastIndexOf(".flv");
200             if ((index != -1))
201             {
202                 _isFlv = true;
203             }
204             else
205             {
206                 _isFlv = false;
207             }
208             _isMp4 = ! _isFlv;
209         }
210         public function get isFlv():Boolean
211         {
212             return _isFlv;
213         }
214         public function get isMp4():Boolean
215         {
216             return _isMp4;
217         }
218         public function pauseVideo():Boolean
219         {
220             if (togglepause)
221             {
222                 togglepause = false;
223                 _ns.resume();
224             }
225             else
226             {
227                 togglepause = true;
228                 _ns.pause();
229             }
230             return togglepause;
231         }
232         public function volume(vol:Number)
233         {
234             st.volume = vol;
235             _ns.soundTransform = st;
236         }
237         public function stopVideo():void
238         {
239             this.dispatchEvent(new Event("videoComplete"));
240             _ns.close();
241             _metaData_loaded = false;
242         }
243         private function _render():void
244         {
245             var timer:Timer = new Timer(100);
246             var _this = this;
247             this.dispatchEvent(new Event("videoStart"));
248             var timerEvent = function(e:TimerEvent):void
249             {
250             _this.dispatchEvent(new Event("playProgress"));
251             };
252             timer.addEventListener(TimerEvent.TIMER,timerEvent);
253             timer.start();
254         }
255         public function seekVideo(point:Number):void
256         {
257             _ns.seek(point);
258         }
259         public function get videoPaused():Boolean
260         {
261             return togglepause;
262         }
263         public function get content():Video
264         {
265             return v;
266         }
267         public function get playProgress():Number
268         {
269             return _ns.time / _duration;
270         }
271         public function get bufferProgress():Number
272         {
273             return _ns ? _ns.bytesLoaded / _ns.bytesTotal:1;
274         }
275         public function get videoTime():Number
276         {
277             return _ns ? _ns.time:0;
278         }
279         public function get totalTime():Number
280         {
281             return _duration;
282         }
283         public static function getLoader():Array
284         {
285             return _loader;
286         }
287         public function get netStream():NetStream
288         {
289             return _ns;
290         }
291         public function set url(url:String):void
292         {
293             getVideoType(url);
294             _url = url;
295         }
296         public function get isPlay():Boolean
297         {
298             return !togglepause;
299         }
300         public function set metaData_loaded(metaData_loaded:Boolean):void
301         {
302             this._metaData_loaded=metaData_loaded;
303         }
304         public function get status():String
305         {
306             return _status;
307         }
308         public function get frameInfo():Object
309         {
310             return _frameInfo;
311         }
312         public function get start():Number
313         {
314             return _start;
315         }
316         public function set start(start:Number):void
317         {
318             this._start = start;
319         }
320 
321     }
322 }

因为嫌弃greensocks的loadermax里面的videoloader太大了,自己就重写了个。

题外话

事实上,如果开启了优酷客户端的加速器去网页上看优酷,可以看到优酷也是分了段的,也会发出1.flv?start=100那种请求。而不加速器就会是下图的种子请求

链接类似于:

http://27.221.48.210/youku/6571EC9C9743582E25E8A83AE9/030002070250ECC0BDF242023AEBCA6C8500D8-AB84-D3E6-1355-AD3E89D20E76.flv?nk=410723804503_23592369908&ns=11949300_2673200&special=true

优酷视频地址分析参见http://www.cnblogs.com/keygle/p/3829653.html,, http://www.cnblogs.com/zhaojunjie/p/4009192.html

可以看出优酷是用了苹果的m3u8.m3u8将那些5-10秒的分段小视频通过索引组织起来,而且可以调整适应码率。

下面问题来了,flash怎么解析m3u8..参见http://player.sewise.com/a/yingyongshili/20140425/7.html.

这个player实际是用了osmf和HLSProvider的m3u8解析,调用起来实际上也很简单.这样就大大的增加了m3u8的适用范围。缺点就是至少增加了150k的体积。

本屌的另一篇文章 小巧的http live streaming m3u8播放器

转载请注明 TheViper   http://www.cnblogs.com/TheViper

 

posted on 2014-11-09 22:34  TheViper_  阅读(3520)  评论(0编辑  收藏  举报