seek到未加载切片也同样,从根据seek位置设定start参数后开始加载。 如此以来在任何情况下seek都可以精确到关键帧,缺点是把正在加载的切片关掉会造成数据浪费。从切片中间开始加载也会造成一个切片内容不完整。下次seek的时候如果不巧是在这个切片start位置之前,就需要重新加载该切片。这些都会造成数据浪费。好在一般用户不会吃饱了没事儿seek来seek去。
通过连接池来限制连接数量
从上文的几个策略可以看出,如果视频分得越短小,无论对seek的精确度,还是数据浪费情况都是有好处的,但是这带来的一个问题是需要实例化更多的NetStream来维护切片。另外对于时长较长的视频来说,NetStream的数量也会变得很多。但实际上NetStream能同时开启的连接数量是有限的,这不是内存问题,而是Flash提供的连接数有限。超过了这个限制NetStream就没办法正常工作了,而且也不报错。这个限制在不同浏览器下还不一样,我怀疑这和浏览器底层有关。
所以为了限制NetStream的数量,我们需要设计一个NetStream连接池来管理所有的NetStream。连接池上限不能小于最大缓冲举例可能加载的最多分片数,否则逻辑上就是有问题滴。
我们可以从连接池中取得一个新的NetStream来使用(这个NetStream可能是别的NetStream关闭后的,不过你可以把它当新的用)当连接池数量满的时候,他就会自动把一些老的处于连接状态的NetStream关闭掉。这个淘汰原则是基于空间局部性原理的,也就是说和当前播放头位置距离最远的切片应该首先被关掉(处于最大缓冲距离之内的切片不能关闭)。因为根据概率统计发现大部分的seek都出现在播放头附近(可能为了找什么情节)。
推荐使用数据生成模式
通过多个NetStream切换的方式播放视频,在切换的时候会出现不明显的爆音,但是仔细听还是能够发现。这也是我在上文中提到的文件分割得太短小出现的另外一个问题,爆音太频繁了,可能影响视频观看。
所以要从根本上解决这个问题,我们就要放弃NetStream切换的方式,转用数据生成模式。数据生成模式可以把请求的切片做得很小(但也不要太小,否则服务器性能降低)。切片做小的一个好处是请求更快的完成,那么请求被打断的几率就会降低,当请求完成之后,下次请求同样的资源就能从浏览器缓冲中取。所以小切片更容易被缓存。而上文中的小切片产生的问题在这里不复存在。如图所示。

我们根据播放头的位置,往后加载分片数据,直到最大缓冲距离,这和前面提到的方式类似。而后我们把这些加载的二进制数据保存在内存中。从播放后往后一定的距离(我们称作NS缓冲长度),如果有分片进入,那么就把它appendBytes到用于播放的NetStream中。图中所示的蓝色部分就是保存在内存中的数据,它也有前面提到的连接池类似的淘汰机制用于控制内存总大小。被从内存中释放掉的数据,我们可以在浏览器缓存中找到(因为已经加载过了),如果要使用的话,我们可以像请求服务端数据一样的方式快速请求到这些数据(当然比从内存中慢一些)。图中白色方框的是还未加载过的数据,他们在服务器上等待加载。如图所示就是数据的三级查询。

如果用户进行seek:
- seek的位置位于内存中的数据:先清空NetStream的缓冲,然后把内存中响应位置的数据往后一定距离(NS缓冲长度以上)加入到NetStream中用于播放。
- seek的位置位于缓存中:先把缓存中的数据加载到内存中,然后通过第一条的方式实现。
- seek的位置位于服务器上:从服务器上加载数据分片数据到内存中,然后通过第一条的方式实现。
如果分片数据较大,seek的位置在分片中间,那么也可以从分片中间开始加载,这样可以从逻辑上把一个分片分为了两个。
数据生成模式从本质上保证了播放质量,杜绝了数据浪费,保证了seek精确度,服务器实现上也异常简单,真是视频播放首选!
赠品:用分段方式做直播
这种方式需要服务器做实时分片并分发到CDN。比如服务器从直播数据源里把30秒的视频数据打包成一个数据包分发到CDN上,所以理论上直播至少会延迟30秒。不过对于实时性不是特别强的直播,这种方式的负载能力会更好。
传统的长连接方式直播,需要客户端和服务器一直保持连接,服务器需要维护每个客户端的连接,但实际上传输30秒的视频数据只需要1秒,所以如果采用HTTP的方式,因为传输完毕就可以服务别人了,所以理论上维护连接的效率可以提高30倍。
这里我们要求服务器提供一个视频地址列表,列表里提供了最新的N个视频分片地址。这样客户端通过轮询这个视频列表就能让客户端和直播保持同步。

如图所示客户端维护着一个切片列表队列,通过轮询服务器,我们把最新的视频地址添加到队列中,而播放模块则从队列中取出最老的切片地址加载播放。
如果用户网络较差,那么播放就会卡顿,所以从队列中取出切片地址的频率就会降低,队列会越来越长。队列越长说明视频播放的延迟越大。
所以当队列长于某一个临界值时(我们设定的),我们就把队列清空到只剩一个最近的地址,直到下一次这个地址被取出时,才允许队列继续变长。这个队列清空的操作实际上是对因播放卡顿引起的延迟做了矫正,让直播不要延迟得太厉害。