视频播放器本地代理服务设计

场景 希望在播放视频的时候能边下边播。而不是等整个视频下好才能播 缓存视频,对于播放过的视频能缓存住,下次不从网络获取,节省流量带宽。用户随意拖动进度条的部分也能缓存住。 控制下载进度,用户只看了前面一点并暂停了,那么没必要整个视频都下下来。

方案

播放器Manager主要给项目使用,提供一些简洁的接口,屏蔽所有能屏蔽的细节。 播放器kit层是对播放器SDK简洁的封装,方便使用。播放器SDK基于 ffmpeg 写的独立的一个SDK。 本地server是一个http代理服务,本文将描述这个模块。 另外,播放器日志监控,数据统计由另外的统计SDK做了,没放在这里做。

首先,播放器SDK并不直接去连接视频服务器,而是先连接本地server,然后由本地server去连接视频服务器,本地server收到服务端的视频数据,再转发给播放器,相当于一个转发的功能。不断接收来自播放器的请求,然后去下载数据,然后再返回给播放器。

Server模块: 接收请求和下发数据,都使用同步非阻塞IO模式。 接收数据:使用kqueue多路复用接收IO请求。 下发数据:同步非阻塞模式下发(开一个线程下发数据,每个数据之间是同步的) unix 上的 kqueue 有个坑,无法监测socket发送缓存区由满变到不满的状态,但 linux 的 epoll 可以 完整的缓冲区状态变化需要4个,满 -> 不满,不满 -> 满,空 -> 非空,非空 -> 空

Downloader模块: 会收到来自Server的请求,内容是视频的(url + offset) 下载前会检查缓存,如果有缓存直接下发缓存的数据,没有缓存才去下载。 使用 NSURLSession 下载,NSURLSession 的每一个 task 会创建worker线程去下载数据。 worker 返回一段数据,把数据发给 server 去下发。server下发失败关闭这个 task。 worker 同时也把数据发给 Cache 模块去缓存。

Cache模块: 会收到来自Downloader的读取和写入请求,内容都是(url, offset, length) (url, offset, length)能确定唯一一个视频的块。

取视频url作为缓存的key。 一个视频逻辑上被分成 512k 为一个块存储,chunk_size = 512k。 例如一个视频有1224k, 被分成 512k + 512k + 200k,3块,每个块对应一个文件。

如下图,key + offset + totalLength 作为文件名,file_size 就是 chunk_size

读取缓存: 读取以块(512k)为单位。 内存有就内存返回,内存没有就上磁盘查找,找到就返回。 用户可能任意拖动进度条,那么 offset 可能是任意值,读取缓存的时候,就看offset对应的块存不存在,存在就返回,不存在就不返回,得重新下载了。

用NSData读取磁盘数据,它底层使用了 mmap,省掉了系统内核空间到用户空间的拷贝,速度快。

写入缓存:

写入缓存按照 512k 为一块写入。最坏的情况如下图:

用户刚好拖动到进度条到50k,然后下到1000k,他就停止播放。那么差不多 1MB 的数据缓存不了,因为第0块不满,第1块也不满。 最好的情况就是从0看起,看到刚好满足块的地方,全部能缓存。 网络好可以增大chunk_size,网络差可以减小chunk_size。减少不能缓存的情况。

用户频繁拖动进度条,产生很多零碎的块,现在内存中保存中,拼接够了一个512k的块,再写入文件。 零碎的块类似这样: (url, offset, length) (url, 0, 100),(url, 50, 150),(url, 12345, 1234),(url, 10000, 10) 块有重叠的地方,每收到一个写任务,就要去判断是否有重叠,有重叠需要合并一下。 比如现在有 (url, 0, 100) 收到一个(url, 50, 150) 发现 50 在 0 到 100 之间,那么合并为 (url, 0, 200) 如果合并后满足了一个块的范围,那么把这个块写文件记录。

缓存淘汰: 假定用户经常看的视频不能优先淘汰。那么用 LRU 淘汰策略即可,每个缓存块设置一个count,缓存命中一次就 count++,触发淘汰的时候,把 count 最小的先淘汰.

流量控制 用户只看了视频前面一点,就暂停了,那么后面的视频不再下载。 即播放器的消费速度比本地server的生产速度要慢。 播放器设置为5MB的缓存大小,用户暂停后,缓冲区肯定会占满,然后播放器不在recv()数据,那么server下发数据会报 EAGAIN 写缓存区满的错误,这个时候每隔3秒重试一次下发。设置为3秒重试是因为假设了5MB视频能够播放3秒。

如果播放器的消费速度比本地server的生产速度要快,那有可能是网速太慢了。

原作者:ck2016 原文链接:https://www.jianshu.com/p/18ed7531117a 校验:逆流的鱼yuiop

原文发布于微信公众号 - 何俊林(DriodDeveloper)

原文发表时间:2018-05-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏写代码的海盗

Nodejs课堂笔记-第四课 Dynamodb为何物

本文由Vikings(http://www.cnblogs.com/vikings-blog/) 原创,转载请标明.谢谢!   我喜欢带着目标来学习...

2725
来自专栏崔庆才的专栏

代理的基本原理

1883
来自专栏PHP技术

web缓存的作用和类型

前言&摘要 这段时间的工作内容主要是为一个客户端类型的产品增加文档在线存储和文档在线预览相关特性。由于测试的同事比较细心和专业,发现了项目实现中一些效 率低下的...

3335
来自专栏蓝天

选择设置好ext3日志模式

Linux是一种开放的、因Internet而产生的操作系统。Internet的发展、以网络为中心的计算模式如电子商务被迅速接受和普及,都为 Linux提供了更巨...

562
来自专栏数据之美

玩转 Linux 之:由 Nginx log rotation 聊聊 mv 的妙用

1、Nginx 下如何正确的做日志切分 今天发现有个 Nginx 日志 rotation 出来大小是 0,很奇怪,按公司的业务场景来说,这是不可能的。 瞅了...

22110
来自专栏linux驱动个人学习

Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度(六)

前面我们了解到了0号进程是系统所有进程的先祖, 它的进程描述符init_task是内核静态创建的, 而它在进行初始化的时候, 通过kernel_thread的方...

841
来自专栏FreeBuf

Kali Linux渗透基础知识整理(二)漏洞扫描

* 原创作者:sysorem,本文属FreeBuf原创奖励计划 漏洞扫描 网络流量 Nmap Hping3 Nessus whatweb DirBuster j...

2638
来自专栏皮振伟的专栏

[linux][nginx]nginx的graceful shutdown和worker shutdown timeout

前言: 某大佬问作者,nginx做proxy的时候,重新加载配置的时候,会不会影响已有的连接? 作者基于too young too simple的认知:clie...

1182
来自专栏北京马哥教育

在服务器上排除问题的头五分钟(干货)

遇到服务器故障,问题出现的原因很少可以一下就想到。我们基本上都会从以下步骤入手: 一、尽可能搞清楚问题的前因后果 不要一下子就扎到服务器前面,你需要先搞明白对这...

2743
来自专栏北京马哥教育

【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器

一、反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然...

3718

扫码关注云+社区