背景
随着抖音、快手等短视频的崛起,短视频正在成为大家主要的娱乐消费内容,得物正在向社区化转型,短视频是非常重要的社区内容载体。
但是短视频的播放卡顿在大多数场景下比较影响用户的体验,所以我们需要一整套行之有效的播放器优化的方案。
本文为了大家更好理解播放器优化的方案,会深入浅出地分析播放器的性能瓶颈和优化重点,并给出核心的优化方案,供大家参考。
目录
播放器技术选型
播放器性能监控方案
播放器性能优化方案
边下边播
前言
为什么要按照这样的章节选题去讲解?
因为在我看来,技术选型非常重要,这个环节是不能少的,因为经过了比较严格和科学的技术选型分析,说明你对各个方案的优劣有了非常清理的理解,并且对这些技术方案是否适合我们的项目有全面的分析。
确定了技术选型,轻易不能改变,我们后续的所有优化方案都要在这个搭建好的架子上装修点缀。
播放器的监控方案之所以放在前面,因为确定监控方案,必须要搞清楚几点:
用户的痛点是什么?
怎么用技术化的手段去衡量用户的痛点?
这些衡量手段是否能在正确方向上推动我们后续的优化?
所以播放器的监控方案是优化手段的先决条件,我们只有充分分析用户的痛点才能制定出科学的监控方案。
有了播放器的监控方案,接下来播放器的优化方案就是顺理成章的事情,我们只需要明确一个个产品和用户的痛点,针对性地提出可靠的优化方案,我们完整的迭代优化才能稳步跑起来。
为什么边下边播要单独作为一个章节?
边下边播是播放类产品中一个重要的功能特点,这儿之所以单独列出来,主要有下面的原因:
边下边播的优化思路是播放器性能优化的核心点。
边下边播整体技术实现比较复杂,涉及client和server端的优化,做出来不难,做好并不容易。
希望大家看完本文,能够了解播放器的监控思路和优化方案,让我们的app播放视频丝滑、柔顺。
播放器技术选型
做一件事情选择很多,每种方案各有优劣,一时难以取舍。
播放器的方案有很多种,以Android为例,有VLC方案、ijkplayer方案、自研的ffplay方案、谷歌的ExoPlayer方案、原生的MediaPlayer方案等等。
我们需要在这么多机刷方案中选择最适合我们业务场景的,首先需要明确我们对播放器的要求是什么?
应该从以下几方面来权衡:
功能支持度
维护成本
稳定性
可扩展性
跨平台
包体积
功能支持度
我们选择播放器能够支持必要的功能是基础,如果部分功能都无法满足,那就没有继续调研下去的必要的,但是支持也不是越复杂越好,搞得越复杂,我们业务也没有这么复杂的场景,最后弄得“杀鸡用牛刀”,得不偿失。
维护成本
维护成本包括两个方面:
(1)开源项目的维护成本;
(2)项目本身的复杂程度。
第一个点是开源本身是不是在继续维护,如果开源项目本身维护地很好,我们后续的维护也会方便一点,相当于集思广益;相反开源项目已经废弃了,那后续所有的问题都要靠我们自己。
第二个点是项目本身是否复杂,如果代码比较复杂,对开发人员的要求比较高,那后续迭代维护的难度也要大一点。
稳定性
稳定性是重中之重,如果选择的播放器经常来个难查的崩溃,那光解决这些崩溃问题就让人瞪眼了。
稳定性还有另外一个方面的要求,就是项目架构不能频繁变动,如果变动过于频繁,我们已经集成到业务中的修改也要频繁修改,对我们的开发成本也是很大的。不过较成熟的开源播放器都是相对稳定的,是经过时间考验的。
可扩展性
可扩展性可以看成开源项目另一种维度的“生命延伸”,如果开源项目在设计之初就充分扩展性的问题,后续即使有新的功能点,也可以高效地扩展,不至于因为一个或者几个新功能发现目前的架构不适用,然后费了很大的劲再去调整,几次下来,估计开发也被玩废了。
跨平台
目前主要的App都有Android和iOS端,一般公司都会要求一些底层库具备跨平台的特性,一方面可以适当降低开发成本,另一方面也可以尽量保持双端体验的一致性。跨平台有优势,但是我们也要清楚,如果原生的更好用,或者说开发难度不大,也不一定非得追求跨平台。
包体积
移动端的应用对包大小都非常敏感,核心要求就是包大小越小越好,正常情况下,如果包体积过大,即使有很多优势,也不应该选择这种技术方案。
上面我们也提到了几种播放器方案:
VLC Player
ijkplayer
基于ffplay自研方案
ExoPlayer
原生的MediaPlayer
首先可以排除最后一种,原生的MediaPlayer体验实在不行,就算MediaPlayer越来越好,但是低版本的兼容也会给开发增加额外的负担。
基于ffplay自研方案也可以排除,ffplay是FFmpeg开源项目提供的播放框架,主要是这种方案的开发成本比较高,对开发的要求比较高,前期的工作量很大,我们一般要求“快速上线,小步快跑,敏捷迭代”,这种方案前期的开发时间较长,需要较长的时间才能稳定下来,如果不是较成熟的开发团队,不太建议这种方案。
那接下来就剩下VLC Player、ijkplayer、ExoPlayer三种方案。
下面全面分析一下这三种播放器的优缺点。
VLC Player
VLC是VideoLAN研究所推出的播放工程方案,于1996年就开始了,VLC是一个完全跨平台的播放器,支持Windows/Linux/MacOS/Android/iOS等平台,目前全球已经有13亿次人下载,确实非常popular。
VLC为人称道是还有它的架构,是完全模块化的架构管理体系,其代码体系主要包含四大部分:
VLC main:player的main。初始化libVLC 并加载用户界面。
libVLC core:VLC加载modules的核心模块,内部抽象出libvlc_instance_t对象,提供modules的装载、卸载机制。
modules:modules提供具体的功能,分为协议解析、解封装、解码、渲染等功能模块。
External libraries:外部的开源库。
由于VLC出现的比较早,后面的很多播放器相关的开源项目在架构涉及和功能逻辑上都不可避免地受到其影响,堪称播放器的“祖师爷”。
优点
良好的跨平台性,几乎支持所有的系统,兼容性非常好
功能非常全面,支持几乎所有的播放器相关的功能
代码架构涉及合理,解耦较好,各种modules独立性强,如果需要引入新的库或者改造某些modules非常方便
维护团队非常强大,开源社区比较活跃
缺点
为了兼容跨平台的特点,有些地方代码比较冗余
有一定的开发门槛,学习成本比较好
移动端库体积比较大,Android端编译出来的包约16M,即使经过一系列裁剪,包体积依然很大,这对宝体积非常敏感的移动端是无法忍受的
ijkplayer
ijkplayer是BiliBili公司开创的一个播放器开源工程,主要基础FFmpeg的ffplay模块扩展的,目前支持Android和iOS端,要说FFmpeg是音视频领域的一座大山,音视频开发基本上绕不过它,其中的ffplay模块更是播放器涉及的基本架构参考。
FFmpeg提供ffplay和SDL(Simple DirectMedia Layer)作为播放器的根基。其基本模块分为:
类MediaPlayer API层
ijkplayer jni层
ijkplayer消息管理
ffplay
FFmpeg base库
External libraries
整体的流程也非常清理,如果仔细看的话,还是能看出部分VLC的影子的,不过ffplay整体比较“轻巧”一点。
优点
ijkplayer整体结构比较简单,基本上复用ffplay,如果对FFmpeg有点了解的话,熟悉它并不难
ijkplayer的包相对VLC要小很多,可以裁剪至4M甚至更小
可以跨Android和iOS,国内目前主流的播放器都以ijkplayer迭代发展而来
缺点
ijkplayer的模块划分没有VLC好,主要FFmpeg是音视频处理库,播放器只是其中的一种应用场景,如果需要扩展module需要对FFmpeg的各个模块非常熟悉,有一定的门槛
ijkplayer官方维护更新比较慢,不遇到问题还好,如果真的遇到一些问题,那还是比较棘手的,不过众多开发者已经自发加入了维护大军,“自干五”的加入确实为ijkplayer的发展拓宽了新的渠道
ExoPlayer
ExoPlayer 是google推出的开源播放器,主要是集成了Android 提供的一套解码系统来解析视频和音频,将MediaCodec封装地非常完善,形成了一个性能优越,播放稳定性较好的一个开发播放器,已经再Youtube应用上得到了应用;由于Google的大力推广,目前非常流行,ExoPlayer包大小轻便,接入简单。
优点
包体积小,约1.1M
维护团队强大,基本上一个月一个大版本
缺点
无法接入软解码,可扩展性很差
无法跨端,只有Android平台
综合上面对三种播放器优劣的分析,大家可以根据根据自己的业务场景选择对应的播放架构,在此有一些建议。
关于播放器的建议
如果已知的播放场景比较简单,例如小视频场景,都是mp4视频(h264/aac格式),强烈建议使用ExoPlayer,没有比这更适合的了,如果需要考虑跨平台情况,那ExoPlayer就不行了,这里重点强调的是Android平台,iOS也有平台特色的播放器。
如果业务场景涉及多种播放形态,例如直播、长视频、超高清视频,还是建议引入可以支持软解码的播放器,方便后续硬解码切换到软解码的方案。
目前主流的移动端播放方案都是基于ijkplayer,后期不断迭代,形成自己的播放器体系。我们熟知的七牛云、腾讯云、阿里云播放器都是基于ijkplayer方案的。
播放器性能监控方案
衡量播放器的优劣主要分为两个维度:
功能维度
性能维度
功能维度例如正常的播放、暂停、倍速、音量、音视频同步等等。
这是播放器的基本盘,这个基本上没有什么问题。
性能维度一般是开发者追求的地方。
播放器的性能是主要靠开发者在搞清楚播放器原理的基础上,结合具体的播放场景,提出的一系列性能优化方案。
但是在谈性能优化之前,我想先分析一下播放器的性能监控方案,衡量指标确定好了,给我们后期的优化提供目标。
性能监控方案必须着眼于用户关注的核心体验,能够通过这些指标为播放器的持续优化提供理论和数据的支撑。
我们从四个方面来衡量播放器的性能:
播放成功率
播放首帧速度
播放卡顿
播放器资源占用
在分析这四个指标之前,我们先介绍播放器的两种性能流水线——性能pipeline。
播放器全链路pipeline
播放器网络请求pipeline
播放器全链路pipeline
下面是播放器全链路pipeline图,输入一个网络URL,首先要网络请求,得到数据流,读取流数据,嗅探视频的封装格式,识别到具体的封装格式,然后解封装视频文件,分离出具体的音频流和视频流,准备好两个队列:
video packet queue:存放视频未解封的数据包
audio packet queue:存放视频未解封的数据包
然后分别启动视频解码线程和音频解码线程分别取对应队列中的原始数据,将解码好的数据也放入两个队列中:
video frame queue:存放视频解码好的数据帧
audio frame queue:存放音频解码好的数据帧
接下来渲染视频帧和音频帧的时候做好音视频同步的工作,音视频同步算法一般以音频帧时间为准,因为人耳毕竟对音频更加敏感一点。
我们将播放器拆分为一个个子流程,是为了更好地监控每一个过程。
做好pipeline的漏斗模型,只有完成每一步到达最后一步,才能算真正的播放成功,每一步都有可能会失败,需要我们左海全链路的监控方案。
播放器网络请求pipeline
上面是播放器全链路pipeline,其中网络加载模块是第一步,也是最重要的一步,也可以将网络加载细分为播放器网络请求pipeline,下面是请求流程图:
网络请求首先要经过dns请求,dns解析,获取对应的IP地址,再建立连接,TCP握手完成建立连接,发送request请求,(https还需要ssl或者tls验证),然后收到response数据。网络请求优化是播放器性能优化的核心点。
正常播放器的功能基本上区别不大,网络加载依赖客户端、服务端多方,所以我们应该将优化的重点放在这里地方。
下一节讲到性能优化的地方会详细展开分析。
介绍上面两种类型的pipeline,是为了大家更好地理解播放器的基本流程,之后我们提出优化方案大家理解也容易一点。
下面我们开始定义播放器的四大指标:
播放成功率
播放成功率是播放器最基础的指标,如果视频或者音频都播放失败,那其他的一切优化都无从谈起,所以成功率是播放器的第一核心指标。
这儿只是先定义指标,具体的优化建议等到下一章再详细展开谈谈。
播放成功率 = 1 - 播放失败次数 / 播放总次数
播放首帧速度
播放首帧耗时就是从点击播放开始,到播放器出现画面总共的耗时,这是播放器另外一个核心的指标,首帧速度直接影响用户接下来的观看体验,如果点击播放要等很长时间才能出现画面,很有可能用户就不等了,那就因为首帧速度慢导致用户流失了。
点击播放的时间点我们都非常清楚,那什么时候才能算播放画面被渲染出来?
通常我们都会将第一帧解码出来的时间点等同于首帧的时间点,因为被解码出来,到渲染到surface上,这中间的耗时可以忽略不计。ijkplayer和ExoPlayer都是采用这种计算方式。
首帧耗时 = 第一帧解码完成的时间点 - 点击播放的时间点
播放卡顿
播放卡顿和上面两个指标不同,上面两个指标是一个时间点指标,播放卡顿却是一个时间段的指标,主要考察一段时间的卡顿情况。
首先我们要明确一个概念:什么是卡顿?
可以从两个不同的角度来定义卡顿
用户体验上的卡顿
技术卡顿
用户体验上的卡顿
从用户体验的角度来讲,如果播放的过程中出现“转圈”——loading dialog,就说明遇到了卡段,但是这个“转圈”是开发者调出来的,一般开发者会在本地定时去校验当前播放的时间点和上一次记录的时间点,如果轮询发现当前播放的时间点和上次记录的时间点一样,就认为是卡顿。
这样的判断无可厚非,是从用户的体验的角度来定义的,但是这种检测的定时时间一般比较大,有些是1000ms检测一次,有些是500ms检测一次,如果是小于500ms的卡顿就无法检测出来了。所以我们又提出了另一个检测方式——可以在播放SDK内部检测卡顿。
技术卡顿
我们能不能在播放器内部监控播放器的流程来发现卡顿?
到这里如果大家不太熟悉播放器的完整流程,估计理解起来会有点困难。
下面我先简单介绍一下播放器内部的工作原理。
一个播放器内部基本都有四个线程在工作:
网络请求线程,如果是本地文件,那就是协议解析线程
音频解码线程
视频解码线程
播放渲染线程
上图清楚地介绍了四个线程之间的关系,其中播放渲染线程是影响卡顿最直接的线程,技术卡顿的埋点可以在这个线程中完成。
如果当前视频的帧率正常,大于20帧,在播放渲染线程中的帧率如果低于20fps,就认为是一次卡顿。那么这时候要完整记录一下其他三个线程的工作情况。
video_packet_queue和audio_packet_queue的数据
video_frame_queue和audio_frame_queue的数据
如果发生卡顿了我们需要记录什么数据:
卡顿次数
卡顿耗时
卡顿时四个队列的数据情况
就卡顿类型而言,我们分为两种:
主动卡顿
拖动导致的卡顿
主动卡顿
主动卡顿就是在播放视频的过程中,用户没有做任何操作,是指没有点击暂停、拖动进度条等操作,播放中的视频突然卡住了,这种卡顿称为主动卡顿,这种卡顿时用户绝对无法忍受的,体验极差。
拖动导致的卡顿
与之相对应的是拖动进度条产生的卡段,众所周知,播放器是可以拖动进度条的,播放的过程中用户拖动播放进度条,拖动操作完成后,如果视频卡住,这种卡卡顿称为拖动导致的卡顿。
拖动卡顿一般而言是可预期的,用户是能够接受的,只要不是卡顿时间太长都还好。
上面交代了两种定义卡顿的维度和两种不同的卡顿类型,下面我们提出衡量卡顿的指标:
单次播放的平均卡顿次数
单次播放的平均卡顿时间
播放器资源占用
播放器的资源占用就是播放视频消耗的资源或者占用的内存,这个似乎不单单是播放器锁监控的,应该放在整个应用的角度去考虑这个事情,播放器由于内部包含两个MediaCodec(一个音频解码、一个视频解码),占用资源本身就很多。
我们知道整个手机共享的MediaCodec实例一般是16个,而一个播放器实例就要占用两个MediaCodec实例,要是再来几个预加载什么的?那估计就一直OOM了。
所以监控播放器资源核心就是监控MediaCodec实例。当前由播放器占用的MediaCodec实例有多少个?
在满足基本功能的情况下,当然越少越好,越少说明播放器对资源的占用越小,播放器导致的OOM就会更少。
播放器性能优化方案
播放器的性能优化核心是围绕“好”、“快”、“省”三点进行的。
好:播放成功率高,兼容性好
快:首帧速度快,卡顿少
省:占用内存少,体验流畅
格式支持
播放器成功率优化首先需要关注业务形态的视频格式,共有三种类型的格式:
解封装格式
视频解码格式
音频解码格式
这些是硬指标,如果无法解析格式,视频肯定无法播放,所以需要选择一些扩展性比较好的播放器,可以支持接入解封装、解码格式。
如果业务中视频都是自有的源,解封装格式和解码格式都是固定的,例如像得物的社区视频都是MP4的封装格式、H264的视频编码格式、AAC的音频编码格式,不需要引入过多的格式支持而使包变得很大。
软硬解码切换也是播放器成功率的一种优化手段,硬解码效率高、解码速度快,但是支持的格式少、资源有限、兼容性差、渲染的效果较差一些,所以在一些硬解码失败的情况下需要有软解码做兜底。
特别是一些低端机,硬解码视频各种问题,没有软解码确实不行。
网络优化
视频加载过程中最重要并且也是可优化的环节就是网络请求优化,上一章在介绍《播放器网络请求pipeline》的时候详细介绍了网络请求的全过程。
这里我们分析一下可优化的点。
DNS优化
DNS解析请求是网络请求的第一个环节,DNS耗时也是不容小觑的,下面看一个例子:
访问https://www.dewu.com站点,光DNS解析请求就耗时0.172763s,这其实是一个比较长的耗时。我在播放视频的时候如果能优化掉这部分的耗时,确实能进一步提升播放流畅度。
如果没有任何服务端的任何优化,我们在客户端可以实现一个DNS (Domain-IP) 缓存模型,将域名-IP数据保存在数据库中,然后下次请求对应域名时,在数据库中查询是否有对应的IP,不过这个数据库也要做好淘汰机制,可以设置一个淘汰时间,例如两小时清理一次,可以防止存储的IP失效。
我们也可以接入一些外部的HTTP-DNS库,借助云服务商的HTTP-DNS库来提升DNS解析速度,这个一般是收费的。
链接复用
网络请求的第二个阶段就是建立连接,对于TCP连接就是通常所说的三次握手,连接建立之后,可以在此连接层之上发送数据,如果视频的域名是相同的,此TCP连接是可以复用的。
目前大火的短视频上使用的域名一般不会很多,基本上可以枚举出来,在应用启动时就预先创建这些域名的连接,然后后续就可以复用这些连接,就可以省去建立链接的时间。
初始请求buffer控制
上一章在介绍《播放器全链路pipeline》的地方介绍过播放视频,首先网络请求数据,然后嗅探、解封装,那么问题来了?要请求多少数据呢?
如果需要快速出现首帧,肯定是希望请求的数据越少越好,请求的数据越少,请求的时间就越短,速度也就更快,这个大小要根据视频的几个属性来估算出来:帧率、分辨率、GOP大小、码率。
帧率:单位时间出现视频帧的个数
分辨率:视频帧的宽高
GOP大小:Group of Pictures,是一组视频帧的时间间隔,通俗讲就是两个IDR帧的时间间隔(IDR帧就是它不仅是关键帧而且它之后的任何帧不会依赖IDR之前的帧,IDR帧能做到完全隔绝它之前和之后的帧)
码率:单位时间传输的数据位数
首先需要保证第一帧是IDR帧,现在直播场景一般都可以保证的,直播的GOP大小一般是2s,初始buffer的大小设置为请求10帧左右的数据,这样可以快速渲染首帧,首帧出来之后,可以根据网络状态动态调整请求buffer大小。
HTTP3协议应用
谷歌推出的QUIC协议经过多年的演进,目前已经被推为HTTP3.0的标准,其在HTTP2.0的基础上跟进一步,基于UDP基础上做传输控制和优化,可以解决很多TCP协议上的瓶颈问题,主要特点是:
解决队头阻塞问题
可以实现0-RTT的连接
网络切换情况还可以复用连接
前向纠错FEC机制可以解决弱网或者丢包严重的场景
DH(Diffie-Hellman)迪菲-赫尔曼算法更安全
HTTP3.0的上述优势,确实可以缩短视频网络的时间。
格式优化
指定封装、解码格式
格式优化主要是明确特定格式的情况下,我们提前创建解码器,上一章在介绍《播放器全链路pipeline》的地方谈过封装嗅探、创建解码器等流程,这些都是有严格先后顺序关系的。
如果我们能提前获知视频的封装格式、视频音频的编码格式,那就可以免去封装格式的嗅探时间,提前创建解码器(创建MediaCodec也是耗时的,平均需要25ms左右),极致优化,就要考虑到每一个耗时点。
MP4格式优化
MP4是现在非常常见的封装格式,但是MP4格式有一个特点,MP4本质是一个BOX的嵌套结构,就是像套娃一样,主要包含四个一级文件索引,如下图:有些文件是可以没有free列表的,但是不能没有mdat和moov结构。
moov是MP4文件中非常重要的一个BOX,其中存放媒体的metadata信息,MP4文件的所有属性信息都会在moov中显示,所以moov又称为MP4的头文件,就是通过将moov信息解析出来,根据moov中对MP4文件的数据排列解析规则来解析mdat数据。
换言之,如果没有解析到moov数据,是无法解析mdat数据的,那视频就无法播放。就像下面的情况:找不到moov,就无法解析视频真正的mdat数据。
从上面的moov和mdat的排列来看,moov一般在mdat之前,但是有不少情况下moov在mdat之后。而我们网络请求一般是顺序请求的,对于moov在mdat之后的视频,播放就可能会失败。
这时候有两种方案:
双端IO解析,如果前面找不到moov,就到尾部去找
服务端将MP4结构调整,将moov放到mdat之前
显而易见,双端IO解析方式很耗时,不可取,比较通用的还是方法二,需要服务端支持,通过下面的指令可以改造MP4结构:
ffmpeg -i input.mp4 -movflags faststart output.mp4
动态码率
动态码率既适用于点播,也适用于直播,点播场景中常用的是HLS和DASH方案。
HLS就是HTTP Live Stream,是苹果推出的直播方案,也可以用在点播,HLS有Media Playlist和Master Playlist,Media Playlist例子如下:每一个TS代表一个视频小片段。
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXTINF:9.009,
http://media.example.com/first.ts
#EXTINF:9.009,
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
#EXT-X-ENDLIST
Master Playlist中不直接包含TS片段,而是再拥有各个不同码率的子HLS链接:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/lo_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=440000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/hi_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/high/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example.com/audio/index.m3u8
#EXT-X-ENDLIST
上面列出了几种不同码率的HLS链接,可以根据当前的网络状况选择对应的码率。
HLS由于延时比较严重,目前在直播场景中用得不是特别多。
但是Apple不是坐以待毙的主,最近苹果推出了LL-HLS(低延时的HLS)方案,大大降低了HLS延时,也不失为直播的一种选择方案。
VIDEO-ID复用
现在各家公司为了保护自己的短视频链接,都采用了动态url的方法,同样的视频源,半小时就会生成一个新的url,之前的url失效了,我们视频缓存一般会采用url作为key,但是url失效很快,那本地的缓存就无法被复用了,缓存的流程被无情的浪费,其实在url之外,我们可以用VIDEO-ID来唯一标识一个视频,即使url发生了变化,但是只要视频没变,VIDEO-ID就不变,我们缓存视频可以使用VIDEO-ID来代替url,这样本地缓存的视频不会担心无法复用的问题。
不过即使是缓存的视频,也是有过期时间的,不能无限期的使用,可以根据实际情况指定一个过期时间,例如三天未被使用,此视频就会被清理。
预加载方案
短视频优化中,预加载是常用的优化方案,下面我们剖析几种预加载方案,来探讨其中的优化点。
传统的预加载方案
传统的预加载方案如下图,在播放视频1的时候,分别创建多个播放器实例,预加载下面几个视频。
为什么创建播放器实例,才能预加载视频?
因为播放器中包含网络加载模块,必须要创建播放器实例,调用prepare接口,才能实现网络加载和codec创建功能。
其实简单分析一下既可以发现,这种预加载方案问题很多,最主要的问题有三个:
预加载的时机不明确,很容易和当前播放的视频抢带宽
预加载控制太弱,不知道预加载多少,调用了播放器的prepare之后,完全交给播放器,反而对开发者完全透明
预加载创建的播放器实例太多,浪费了太多了资源,很容易造成ARN或者OOM
在仔细分析这种方式的缺点之后,我们不得不提出一个问题,预加载的原则是什么?
换言之,预加载如果不满足这些原则,那就没有必要继续下去了,根据长期的实践,我们提出了下面的预加载原则:
当前播放的视频的优先级最高,任何视频都不能影响当前播放的视频
预加载的视频是按照顺序的,预加载排在后面的视频的加载优先级低于排在前面的视频
当带宽受限时,预加载是没有意义的,就需要我们能做到带宽可衡量
预加载可控,包括预加载多少,什么时候停止,如果不可能,很有可能影响当前播放的视频,进而影响体验
有了上面的上面这四点原则,是指导我们预加载的行动指南,下面我们提出了改进后的预加载方案。
改进后的预加载方案
如下图,改进后的预加载明确了预加载的时机,而且实现了预加载控制,并且实现了全局复用一个播放器实例。
但是我们上面提到了播放器中包含了视频的网络加载,全局复用同一个播放器实例怎么能做到既能播放视频,又能预加载下面的视频呢?
其实就是将播放器的网络加载模块独立出来,具体实现的方案是“本地代理”,就是下一章我们着重要讲的《边下边播》,这儿我们先一笔带过。
当前播放视频1的时候,实时计算(缓冲距离-播放距离)> 安全阈值,这个安全阈值是灵活可配置的,其实就是为了保证即将进行的预加载不会影响当前播放的视频。
开始预加载视频2,当视频2预加载1个GOP大小的时候,停掉视频2预加载,开始预加载视频3,至于这个GOP大小,是服务器告知客户端的,其实客户顿也可以根据码率、帧率计算一个合理的大小,预加载5s左右。既能保证播放的时候快速出现首帧,又不会过分浪费流量和带宽。
当视频3预加载1个GOP大小的时候,停掉视频3的预加载,开始预加载视频4,后面依次如此。
我们在实践的过程中发现,这种预加载方案也是有一些缺陷的。
主要有两个:
没有实现带宽监控,预加载判断中只是加上 (缓冲距离-播放距离)> 安全阈值,并没有监控当前的加载带宽,如果在进行预加载的过程中中带宽被迅速抢占,很有可能影响当前视频的播放。
全局复用同一个播放器,复用同一个codec实例,会造成codec频繁的reset create,造成codec异常的概率很高。
所以我们又提出了再次改进后的预加载方案。
再次改进后的预加载方案
我们吸取了之前几种预加载方案的优点,加上带宽控制,保留了复用同一个播放器实例,但是底层使用codec队列,使用多个codec轮换的方式,解决了codec频繁reset create导致的异常概率过高的问题。
当前播放视频1,实时计算(缓冲距离-播放距离)> 安全阈值,这时候可以预加载后面的视频,如果在预加载的过程中,发现当前视频的加载速度低于一个最低值(最低值概率码率计算得到,小于这个最低值,说明当前视频加载收到了影响),后续的预加载停止,等到符合预加载条件的时候再继续预加载。
开始预加载视频2,当视频2预加载1个GOP大小的时候,停掉视频2预加载,开始预加载视频3。
当视频3预加载1个GOP大小的时候,停掉视频3的预加载,开始预加载视频4,后面依次如此。
这种预加载方案解决了我们上面提出了预加载的问题,可以很好地提升播放体验。预加载中使用的核心功能就是“边下边播”,下面我们介绍一下这种技术方案,帮我们落下最后一块砖。
边下边播
边下边播大家可能不会陌生,早期用过迅雷和快播的同学都知道这个功能,但我们这儿谈得边下边播和它们的边下边播不一样,不是采用P2P的架构做的,只是在客户端架设一个本地代理实现“边下边播”的功能。
如下图,在播放器SDK和视频源服务端之间假设一个桥梁作为代理服务,实现视频源服务端之间到播放端的加载控制。
边下边播主要有三个优势:
定制优化方便:使用本地代理可以将播放器网络模块独立出来,更容易做网络层优化。
二次打开快:缓存复用,后续打开同样文件,直接复用本地缓存。
实现player复用:Player复用中非常重要的一环是本地代理,使用本地代理可以大大降低占用的资源。
使用过AndroidVideoCache库的同学都比较清楚怎么做边下边播,这儿我就不赘述了,但是AndroidVideoCache留下了一些未解决的点需要我们去解决,这儿必须要重点提一下。
MP4异常结构怎么实现边下边播
MP4的结构问题是老生常谈了,上一章也谈到了MP4的结构问题,moov头部和mdat数据的位置问题,moov在mdat之前还是moov在mdat之后,下面看一下MP4的完全结构图。
正常情况下网络请求是顺序请求的,如果moov在mdat之后,是无法做边下边播的,这时候是不是就没有办法了?
我们已经知道了moov不是在mdat之前就是在mdat之后,那如果顺序请求的时候在前面找不到moov结构,那就通过range请求文件尾部查找moov结构,查到了moov结构就能够实现了边下边播了。
拖动进度条怎么实现边下边播
开始边下边播的情况下,已经缓存到了cached_position位置,这时候是顺序缓存的,如果用户拖动进度条到一个新的位置,这个位置已经超过了目前的cached_position,我应该怎么做?
下面有三种方案:
方案一:继续沿着cached_position顺序缓存下去。
方案二:只要当前拖动的进度条超过cached_position,那就不继续缓存,后续的数据完全是网络请求。
方案三:拖动的进度条即使超过了cached_position, 从新的位置开始发起Range 请求。
方案一:
继续沿着cached_position顺序缓存下去,我拖动进度条的位置和cached_position相隔很远,如果采用这种方案拖动进度条之后播放会很慢,所以方案一被毙掉了。
方案二:
方案二的做法也是可以的,拖动进度条之后也不会卡,但是也有问题,就是无法做法真正的边下边播,只能顺序下载。目前网络上热门的开源项目https://github.com/danikula/AndroidVideoCache 就是采用的这种方案。
方案三:
解决拖动之后卡顿,也解决了只能顺序下载的问题。目前是最优的解决方案。
首先本地要维护一个VideoRange 数据结构:
public class VideoRange {
private long mStart; //分片的起始位置
private long mEnd; //分片的结束位置
}
LinkedHashMapmVideoRangeMap
mVideoRangeMap中维护了一个VideoRange列表,key是VideoRange的起始位置,value是VideoRange的对象,mVideoRangeMap是按照key顺序排列的。
如果两个VideoRange之间是部分重合的,是需要merge成一个新的VideoRange的。
M3U8怎么实现边下边播
整视频的边下边播其实很好理解,即使有MP4的结构问题什么的?但是毕竟是一个整文件,Range请求还是比较好弄的,M3U8视频如何做边下边播了?
头条播放器、阿里云播放器或者说市面上很多其他的播放器提供的边下边播功能,都明确说了只支持MP4视频。
但是网络上有很多M3U8的视频,我们在播放M3U8视频的时候支持边下边播。
M3U8视频是一个由M3U8索引文件按照特定规则组成的一个视频,其中M3U8索引文件管理了很多分片视频文件,这个M3U8索引文件本质上就是一个文本。
例如https://iqiyi.zuidameiju.com/20200227/12397_4c680974/index.m3u8,索引文本是:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:7.0
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000000.ts
#EXTINF:6.255,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000001.ts
#EXTINF:3.753,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000002.ts
#EXTINF:2.919,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000003.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000004.ts
#EXTINF:5.421,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000005.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000006.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000007.ts
#EXTINF:1.9599,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000008.ts
#EXTINF:4.7121,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000009.ts
#EXTINF:6.1716,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000010.ts
#EXTINF:3.5862,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000011.ts
#EXTINF:0.7923,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000012.ts
#EXTINF:5.5878,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000013.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000014.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000015.ts
#EXTINF:2.6271,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000016.ts
#EXTINF:5.1291,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000017.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000018.ts
#EXTINF:4.2117,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000019.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000020.ts
#EXTINF:2.8356,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000021.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000022.ts
#EXTINF:6.0048,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000023.ts
#EXTINF:2.2935,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000024.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000025.ts
#EXTINF:4.3785,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000026.ts
#EXTINF:4.0032,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000027.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000028.ts
#EXTINF:4.6287,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000029.ts
#EXTINF:2.3352,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000030.ts
#EXTINF:3.2943,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000031.ts
#EXTINF:7.1724,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000032.ts
#EXTINF:2.2101,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000033.ts
#EXTINF:3.6279,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000034.ts
#EXTINF:2.9607,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000035.ts
#EXTINF:3.753,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000036.ts
#EXTINF:4.0032,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000037.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000038.ts
#EXTINF:5.5044,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000039.ts
#EXTINF:5.2959,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000040.ts
#EXTINF:0.5421,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000041.ts
#EXTINF:6.255,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000042.ts
#EXTINF:2.2518,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000043.ts
#EXTINF:5.004,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000044.ts
#EXTINF:2.502,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000045.ts
#EXTINF:4.5036,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000046.ts
#EXTINF:4.7955,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000047.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000048.ts
#EXTINF:4.5453,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000049.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000050.ts
#EXTINF:1.8348,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000051.ts
#EXTINF:4.0866,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000052.ts
#EXTINF:7.0473,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000053.ts
#EXTINF:4.0032,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000054.ts
#EXTINF:0.9591,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000055.ts
#EXTINF:6.2133,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000056.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000057.ts
#EXTINF:3.6696,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000058.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000059.ts
#EXTINF:1.8348,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000060.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000061.ts
#EXTINF:5.004,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000062.ts
#EXTINF:4.587,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000063.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000064.ts
#EXTINF:2.2935,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000065.ts
#EXTINF:4.17,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000066.ts
#EXTINF:1.0425,
https://iqiyi.zuidameiju.com/20200227/12397_4c680974/1000k/hls/f2b17811203000067.ts
#EXT-X-ENDLIST
M3U8索引文件中有很多个分片视频,我们解析完M3U8文件之后,还要分别请求各个分片文件,播放器是通过索引文件找到对应的分片文件,然后解封--->解码分别文件,最终达成播放M3U8视频的目的。
所以我们做M3U8视频的边下边播,还是不能脱离M3U8索引文件,只不过需要对索引文件做一下改造:
构造一个本地代理的M3U8索引文件
发起对M3U8分片文件的请求
local proxy server 端分别读取下载的分片文件发送到播放器客户端
我们采用特定的分隔符&jeffmony_seg&来分割几个字段,这样在local proxy server端就有更多的信息来解析当前的分片文件了。
构建好的本地代理M3U8索引文件如下:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:7.0
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8wLnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:6.255,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xLnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:3.753,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yLnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:2.919,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zLnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80LnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:5.421,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81LnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82LnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC83LnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:1.9599,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDgudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC84LnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:4.7121,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMDkudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC85LnRzJmplZmZtb255X3NlZyZ1bmtub3du
#EXTINF:6.1716,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xMC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:3.5862,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xMS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:0.7923,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xMi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:5.5878,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xMy50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xNC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xNS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.6271,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xNi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:5.1291,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xNy50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTgudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xOC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.2117,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMTkudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8xOS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yMC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.8356,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yMS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yMi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:6.0048,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yMy50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.2935,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yNC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yNS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.3785,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yNi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.0032,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yNy50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjgudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yOC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.6287,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMjkudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8yOS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.3352,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zMC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:3.2943,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zMS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:7.1724,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zMi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.2101,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zMy50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:3.6279,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zNC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.9607,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zNS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:3.753,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zNi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.0032,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zNy50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzgudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zOC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:5.5044,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwMzkudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC8zOS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:5.2959,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80MC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:0.5421,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80MS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:6.255,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80Mi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.2518,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80My50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:5.004,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80NC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.502,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80NS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.5036,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80Ni50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.7955,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80Ny50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDgudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80OC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.5453,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNDkudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC80OS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81MC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:1.8348,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81MS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.0866,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81Mi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:7.0473,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81My50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.0032,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81NC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:0.9591,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81NS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:6.2133,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81Ni50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81Ny50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:3.6696,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTgudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81OC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNTkudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC81OS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:1.8348,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjAudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82MC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjEudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82MS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:5.004,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjIudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82Mi50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.587,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjMudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82My50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjQudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82NC50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:2.2935,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjUudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82NS50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:4.17,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjYudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82Ni50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXTINF:1.0425,
http://127.0.0.1:39215/aHR0cHM6Ly9pcWl5aS56dWlkYW1laWp1LmNvbS8yMDIwMDIyNy8xMjM5N180YzY4MDk3NC8xMDAway9obHMvZjJiMTc4MTEyMDMwMDAwNjcudHMmamVmZm1vbnlfc2VnJi84NzdkOWQ2ZGYzNWQ3MzQ4MjQxZDcxNzdjNjZiZWEzZC82Ny50cyZqZWZmbW9ueV9zZWcmdW5rbm93bg
#EXT-X-ENDLIST
这样M3U8文件就可以实现边下边播了,希望大家从中能有所收获。
*文/Jeff Mony