小巧的http live streaming m3u8播放器

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

原来发表过一篇分段播放的flash播放器。这个播放器其实就没有神马原理,就是把一个视频分红好几个视频,点播的时候经过关键帧(keyframe)索引找到离点击点最近的关键帧播放。若是当前快要播放完,就去加载下一段。当前播放完,就播放下一段。git

原理很简单,实现起来却非常纠结,痛苦。由于本质上是一开始就建立了几个video,播放,点击,缓冲等时候就须要不停的计算下一个要播放的第几个video,而后像放幻灯片那样切换,虽然不明显。而后计算的时候兼容flv和mp4也很无语,就像搞浏览器兼容同样。另外,点播的时候会多一次请求,用于获取关键帧信息。若是这个关键帧信息很大很长的话,体验是很是很差的。github

这么多不足,就尝试下另外一种方案hls.chrome

hls m3u8的优势在于不错的兼容性。浏览器

能够看到m3u8通杀移动设备,而不支持的设备都是浏览器,能够经过flash播放器解决。事实上如今有长视频的视频网站在pc端基本上都用的m3u8.短视频的话用视频伪流技术(pseudo streaming)就已经能够知足要求了。缓存

具体怎么写呢?一般都是用的osmf和HLSProvider,好比百度云网盘里面的播放器,less

HLSProvider(org.denivip.osmf包)已经封装好了一切,com.baidu.player.DiskPlayer里面是很简单的调用。ide

然而我却发现了更好的东西flashls。 这个东西好在体积小,它例子里的flashlsChromeless.swf只有36kb.刚开始我不敢相信,由于那些视频网站的swf(皮肤swf除外)都是150kb以上,这让我以为好像写一个flash hls写完真的就要好几百kb,另外,它没有其余依赖,好比加密类,osmf....post

事实上,真正对hls m3u8的解析要不了那么多.flex

这类hls plugin一般都被当作那些开源播放器(flowplayer,osmf,jwplayer)的hls插件,用以支持hls.好比上面的HLSProvider就只支持OSMF 2.0 based video players,而osmf即便是只有最基本的功能,也有100多kb,再加上hurlant加密包,就更大了。

效果

下面开始进入正题,看看hls player是怎么作的。

1.进入flashls文件下src文件夹,取出org包,放到项目文件夹。将里面每一个文件形如CONFIG::LOGGING{}的代码去除,由于没有flex builder环境,flash没法编译。这个是去除后的flashls

2.调用flashls封装,具体的能够看flashls examle目录下chromeless的那个例子,很详细。

hls事件

        private function _init_events()
        {
            stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoState);
        }
        private function _onStageVideoState(event : StageVideoAvailabilityEvent):void
        {
            var available : Boolean = (event.availability == StageVideoAvailability.AVAILABLE);
            _hls = new HLS();
            HLSSettings.maxBufferLength = 10;//最大缓存长度
            HLSSettings.seekMode = "ACCURATE";//查找模式
            _hls.stage = stage;
            _hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestHandler);
            _hls.addEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);//当前播放回调
            _hls.addEventListener(HLSEvent.FRAGMENT_PLAYING, _fragmentPlayingHandler);//片断播放回调
            _hls.addEventListener(HLSEvent.PLAYBACK_STATE, _stateHandler);//当前状态回调
            if (available && stage.stageVideos.length > 0)
            {
                _stageVideo = stage.stageVideos[0];
                _stageVideo.attachNetStream(_hls.stream);
            }
            else
            {
                _video = new Video();
                addChild(_video);
                _video.smoothing = true;
                _video.attachNetStream(_hls.stream);
            }
            stage.removeEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoState);
        }

两个设置须要注意

maxBufferLength表示最大的缓冲长度,好比个人片断是10秒一个,maxBufferLength设置成20秒,那么当我播放的时候,播放器会加载后两个片断,若是暂停了,那播放器缓冲完后两个片断就再也不加载片断了。这个作的真的很赞,既保证了用户体验,又节约了流量,另外若是在m3u8文件中配置了多码率的话,会根据用户当前的网速,匹配相应清晰度的片断。

seekMode能够为ACCURATE,KEYFRAME,SEGMENT。

ACCURATE表示点播时会精确的跳到点播位置,这个乍看之下很好,实际用时会发现若是片断稍微长一点,画面会从点播的片断开头快进到点播位置。

KEYFRAME表示定位基于关键帧,这个也有问题,那就是通常的关键帧是几秒一个,这样点播的时候会有几秒的偏差,由于只能用关键帧定位。

SEGMENT表示点播时会跳到包含点播位置的片断的开头。在直播的时候能够用这个。

而后是回调

        private function _manifestHandler(event : HLSEvent):void
        {
            _duration = event.levels[_hls.startlevel].duration;
            if (_autoLoad)
            {
                _play(-1);
            }
        }
        private function _mediaTimeHandler(event : HLSEvent):void
        {
            _duration = event.mediatime.duration;
            _media_position = event.mediatime.position;
            nav.progress_line.x = _media_position / _duration * W;
            nav.progressBar.width = (_media_position + event.mediatime.buffer) / _duration * W;
            nav.notify.text = formatTime(_media_position) + " / " + formatTime(_duration);
        }
        private function _fragmentPlayingHandler(event : HLSEvent):void
        {
            _video.width = _videoWidth = event.playMetrics.video_width;
            _video.height = _videoHeight = event.playMetrics.video_height;
            _video.x=(stage.stageWidth-_video.width)*0.5;
            _video.y=(stage.stageHeight-_video.height)*0.5;
        }
        private function _stateHandler(event : HLSEvent):void
        {
            if (event.state == 'PLAYING_BUFFERING')
            {
                buffering.visible = true;
            }
            else
            {
                buffering.visible = false;
            }
        }

_manifestHandler里面能够获得视频的总长度,注意这里不是片断长度。

_mediaTimeHandler也能够获得视频总长度,还有视频播放的当前位置,当前缓冲长度。所以里面能够更新播放条,缓冲条长度,和播放时间。

_stateHandler能够获得播放器视频流当前的状态,好比中止,暂停,缓冲,播放等状态。

_fragmentPlayingHandler里面能够获取视频信息,好比宽度,高度

最后是hls对netstream封装的方法

        private function _load(url : String):void
        {
            _hls.load(url);
        }
        private function _play(position : Number = -1):void
        {
            _hls.stream.play(null, position);
        }
        private function _pause():void
        {
            _hls.stream.pause();
        }
        protected function _resume():void//回放
        {
            _hls.stream.resume();
        }
        private function _seek(position : Number):void
        {
            _hls.stream.seek(position);
        }
        private function _stop():void
        {
            _hls.stream.close();
        }
        private function _setVolume(percent : Number):void
        {
            st.volume = percent / 100;
            _hls.stream.soundTransform = st;
        }
        private function _getVolume():Number
        {
            return _hls.stream.soundTransform.volume;
        }

里面须要注意的_load方法,传入的是m3u8文件地址,不是视频地址。播放器会自动解析m3u8文件,加载相应视频片断。

3.视频分段,并生成m3u8文件

能够看这一篇文章.

须要注意的是这里的音频编码是aac,是ffmpeg实验的东西,须要加上后面的-strict -2才不会报错。另外,-hls_list_size参数取的稍微大点,由于它表示写入m3u8文件的片断信息个数,好比取值为3,那只有3个片断信息被写入m3u8。

默认获得的片断格式是ts,这个格式不像mp4,flv,f4v.ts是独立编码,不依赖头信息的,在点播的时候不像前面说的那些格式,须要加载头信息,获取关键帧列表后,才能根据关键帧跳到点播位置。

最后说下怎么使用这个播放器

        flash_object.embedSWF('http://localhost/hls_example/youku_player.swf','wrap_player','youku_player','720','540',{
            url:'http://localhost/hls_example/videos/video.m3u8'
        },{wmode:'transparent'});

想播放器传入url参数,值为m3u8地址就可使用了。

hls_example

播放器源码

只有44kb!

相关文章
相关标签/搜索