效果:

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

本文不讨论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

 

分段播放的flash播放器的更多相关文章

  1. eletron 播放rtmp flash 播放器问题

    1 安装 flash https://www.flash.cn/ 2 man.js 配置 参考 https://newsn.net/say/electron-flash-win.html 3 播放器 ...

  2. flash视频器播放器代码

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  3. flash播放器遮挡页面中元素问题解决

    今天在做一个包含Flash播放器的页面弹出效果时发现Flash播放器总是跑到页面最上层,发现这个问题与Flash的”wmode”属性有关,至于该元素详细此处不做记录,解决办法如下: IE:加入参数:& ...

  4. flash播放器插件与flash播放器的区别

    flash插件是一个网页ActiveX控件,而flash播放器是一个exe的可执行程序.前者用于播放网页中的falsh动画,而后者用于播放本地swf格式文件.

  5. 我们计划为EasyDSS定制开发一款超低延时的EasyPlayer Flash播放器

    现象 最近团队在做EasyDSS RTMP流媒体服务器开发的过程中,遇到了一个关于延时累积的问题,先大概描述一下过程: 在EasyRTMP Android进行长时间的RTMP推流压力测试,在EasyD ...

  6. 浏览器文档播放Shockwave Flash 插件问题

    浏览器被提示shockwave flash crashed怎么办?在使用浏览器的时候经常被提示shockwave flash crashed,flash插件崩溃,网页就会出现一些无法显示的文件,下面绿 ...

  7. EasyDSS RTMP流媒体服务器videojs flash播放RTMP/HLS提示错误的解决方案

    本文转自EasyDSS团队成员StarIT的博客:http://blog.csdn.net/staritstarit/article/details/73692715 问题 在博客<EasyDS ...

  8. Flash播放控件属性详解

    Flash 播放控件属性详解 一.属性篇 1.AlignMode(读写)  语法:AlignMode As Long  说明:对齐方式(与SAlign 属性联动).当控件的长宽比例与影片不一致且WMo ...

  9. 遭遇flash播放mp3诡异问题

    在部分ie10+flash player 播放mp3,播放第二句话时,中断无法正常播放,(客户的机器上),自己公司的机器测试了几个,都没发现这个问题.其它浏览器(chrome,firefox)也没发现 ...

随机推荐

  1. SIP 状态码

    SIP应答消息状态码 与功能 类型 状态码 状态说明临时应答(1XX) 100 Trying 正在处理中180 Ringing 振铃181 call being forwarder 呼叫正在前向182 ...

  2. Android的CursorLoader用法小结

    工作内容集中到Contact模块,这个应用查询数据的地方很多,其使用了CursorLoader这个工具大大简化了代码复杂度.Android自3.0提供了Loader机制,当时google的API只是简 ...

  3. memcached应用场景(转)

     memcached最吸引人的地方主要在于它的分布式.分布式对于互联网应用来讲,按照用途基本上可划分为三种方式:分布式计算.分布式存储和两者兼而有之.memcached是分布式存储的一种.我们常见的分 ...

  4. application in 2014

    OA WEBSITE ERP ISO ANDROID EF+MVC4+CATCHE+JQuery+js+div+css+web性能优化+webservice+sql2008+设计模式+wcf+多线程 ...

  5. 学习ios键盘和textfield之间操作体会

    所需要计算就是,键盘移动以后是否遮挡住了textfield,需要用到的计算公式: int offset = 键盘的高度-(self.frame.size.height - self.textfiled ...

  6. BestCoder Round #84 Aaronson

    Aaronson 题意: 给个中文链接:戳戳戳 题解: 这题一看给的公式就是二进制,之后马上就能想到当m大于等于二进制的位数时,输出n的二进制的1的个数就好了.之后就是m小于二进制的位数时,只要加上2 ...

  7. Edmonds_Karp 算法入门详解(转)

    转载自:http://blog.csdn.net/hsqlsd/article/details/7862903 有n个点,有m条有向边,有一个点很特殊,只出不进,叫做源点,通常规定为1号点.另一个点也 ...

  8. Transact-SQL的除法问题

    SELECT 3800/365, 3800.0/365; 执行上面的sql,得到的结果是:10, 10.410958 返回优先级较高的参数的数据类型. 有关详细信息,请参阅数据类型优先级 (Trans ...

  9. R中根据匹配原则将一列拆分为几列的方法

    例如我们需要将一下数据的第二列从and处拆分为两列: before = data.frame(attr = c(1,30,4,6), type=c('foo_and_bar','foo_and_bar ...

  10. 里德九步审讯法 z

    在现实生活中,警方审讯靠的不仅仅是自信和创造力(尽管这两点对审讯工作确有帮助)——审讯者还要在交际影响的心理战术方面接受过高水平训练.       让一个人认罪可不是件容易事,而警察有时能让无辜者承认 ...