效果:
视频分段好处显而易见,就是节省流量,因为看视频很多时候都不会看完,还有很多时候是跳着看的。还有的时候也许用户暂停视频出去买东西了。。。
本文不讨论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,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,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