• 小巧的http live streaming m3u8播放器


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

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

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

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

    hls m3u8的优点在于不错的兼容性。

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

    具体怎么写呢?通常都是用的osmf和HLSProvider,比如百度云网盘里面的播放器,

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

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

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

    这类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!

     

  • 相关阅读:
    NTP on FreeBSD 12.1
    Set proxy server on FreeBSD 12.1
    win32 disk imager使用后u盘容量恢复
    How to install Google Chrome Browser on Kali Linux
    Set NTP Service and timezone on Kali Linux
    Set static IP address and DNS on FreeBSD
    github博客标题显示不了可能是标题包含 特殊符号比如 : (冒号)
    server certificate verification failed. CAfile: none CRLfile: none
    删除文件和目录(彻底的)
    如何在Curl中使用Socks5代理
  • 原文地址:https://www.cnblogs.com/TheViper/p/4363383.html
Copyright © 2020-2023  润新知