@
Kinnikuman #10
这个场景我也没什么经验,结合 #9 #11 楼的引用随便说说。
1. 硬盘、内存速度
目前常见的硬件,即便是机械硬盘,其加载速度也远大于被加载视频的播放速度,更不用说内存了。
2. 硬盘文件的缓存机制
我在前面的回复里解释了一部分。再进一步说,你的应用不会直接读写硬盘,操作系统内核替你“智能”完成硬盘文件在内存中的缓存工作。
当然你也可以手动申请内存,然后读取硬盘文件内容之后保存在申请到的内存中,同时自己编写缓存内容更新的逻辑。这样做只适用于非常有限的场景,比如磁盘 IO 长期被后台应用占用,或者需要反复在多个超大(超过内存容量)文件之间切换。对于一个视频播放器而言,不需要考虑这些事情。
3. 缓存容量设定
我理解你设想中的方案都有一个隐式前提,视频文件非常大,需要尽可能多缓存。但是一般来说,除非你要提供“保存视频文件到本地以备无网络时观看”这个本质上名为“下载”功能,绝大多数时间只缓存一定量的数据即可。换个说法,下载功能可以是按需( on-demand )的,填满缓存容量就可以暂停。
也就是说,内存、硬盘的二级缓存机制是没有必要的。用内存缓存的唯一目的就是避免硬盘读写,硬盘缓存是解决内存缓存不够的才用的,一旦使用硬盘作为缓存就没必要再做内存缓存。
4. 缓存的内容取决于来源协议或者格式
根据上面的分析,本地文件技术上说是不需要缓存的,或者说不需要你手动缓存的。
网络视频有可能是以网盘作为后端,本质上还是特定格式视频文件的形式,也有可能是基于某种流媒体协议。对于前者,缓存的就是文件。对于后者,缓存的是视频流意义上的 packet (非网络意义的 packet )。
5. 播放器本身不关心缓存后端的来源是什么,只关心从特定的来源流式读取。
比如桌面浏览器可以指定缓存后端是内存还是硬盘,但内嵌播放器是无需关心的。播放器这类本地应用,也只需要为数据流的消费者提供一个来源。即播放逻辑永远是固定的,至于来源(缓存)与播放行为是无关的。
6. 下载、解码和播放之间解耦
前面有人引用 mpv 处理缓存的逻辑,它缓存的对象是 packet 经过 demuxer 处理后的数据,即缓存发生于 demuxer 和 decoder 之间。前面 3/4/5 点综合起来说的也是这个意思,下载并不是直接对接播放的,缓存发生于中间解码的部分。不需要对下载和播放逻辑做特殊处理,所有的特殊行为都在中间解码阶段。
7. 缓存的底层数据结构
缓存确实可以用 FIFO 数据结构表达,考虑到播放器的使用场景,固定容量的缓存一定会遇到周期性完整替换的需求。
可以考虑 ring buffer ,这样就需要控制生产者写入速率与消费者播放速率一致。或者考虑 double buffering ,用手动切换缓存后端简化速率匹配。