聊一聊关于视频缩略图缓存策略

news2024/11/29 17:51:09

作者:一只修仙的猿

最近回归android业务开发,开发了如下图的视频剪辑时间轴(图源:剪映):

对于时间轴上的缩略图,需要去解码器加载获取。若每次都去解码器获取,会导致缩略图加载卡顿,无法满足性能需求,因此这里需要对缩略图进行缓存来提高加载效率。那么其中的缓存策略,就是一个值得我们思考的关键点。

这篇文章来介绍这个缩略图缓存的思考与设计的过程,希望能够对你有所帮助。

背景

视频时间轴,我使用的是RecyclerView来实现,其中,每个Item为一个ImageView,即一个缩略图。如下图所示:

缩略图使用时间戳在解码器中进行定位获取。例如一个10s的视频,需要显示10个缩略图,则每个缩略图对应的视频时间位置是0s、1s、2s…9s。

缩略图加载的时机是:

  1. 当我们滑动时间轴时,一个item从不可见到可见,该item的onBindViewHolder()方法会被调用,则对应时间的缩略图会被加载一次。
  2. 当我们调用RecyclerView的notifyDataChanged()时,屏幕上显示的所有缩略图,都会被重新加载一次。

在我们的项目中,缩略图解码器的性能比较差。举个例子,一个缩略图的加载耗时,可能是1s。假如我们不使用缓存,那么我们每次滑动到一个新的位置,都需要等待好几秒,缩略图才能完全显示完毕,这个体验是非常差的。

优化的方法,其中最直接的,是降低获取缩略图接口的耗时,例如从1s降低到0.1s,但这个优化对于负责这个模块的同事来说是一个巨大的挑战。且假如缩短到0.1s,其耗时依旧是不可接受的。

第二个优化方法,就是我们自己想办法,也就是今天我要聊的:增加缩略图缓存。增加了缓存之后,首次加载使用多媒体接口,依旧很慢。但是加载一次之后,响应延迟就可以达到无感了。

那么,这个缓存策略我们该如何设计?

内存缓存

首先最直接的方式,是增加内存缓存,说人话就是,使用一个HashMap,来缓存从解码器中获取的缩略图Bitmap。如下:

public class ThumbnailKey {
    int position = 0;
    String videoPath = "";

    @Override
    public boolean equals(Object obj) {...}

    @Override
    public int hashCode() {...}
}

HashMap<ThumbnailKey,Bitmap> mThumbnailMap;
  1. 我这里创建了ThumbnailKey类表示一个缩略图:视频+时间戳。由于我们需要使用其作为HashMap的Key,所以要重写hashcode()equals()方法。
  2. 创建HashMap对象来存储缩略图

这样,每次加载缩略图的时候,把结果存储在HashMap中,下次请求就直接从Map中去获取即可。Map中没有,再去解码器中加载。

但这里我们很容易发现一个问题:内存暴涨

如果缓存没有上限且视频比较长,那么缓存的bitmap内存占用会非常巨大。最终导致软件性能降低、甚至可能OOM。因此我们不能无限制地缓存缩略图,必须设置一个上限。这里我们结合LRU淘汰规则,使用LRUCache来代替HashMap,就可以很好地解决这个问题。LRUCache是android提供的一个官方库,内部使用的是LinkedHashMap,我们直接使用即可。

如果仅使用内存缓存,在长距离滑动超出内存缓存的范围时,仍然需要从解码器中重新加载。且由于内存的珍贵,上限无法设置地太大。

因此,这里我们需要引入另一个速度稍慢,但是量管够的缓存磁盘缓存

磁盘缓存

磁盘缓存的速度虽然比内存缓存慢许多,但对于解码器的解码速度也是降维打击了。磁盘缓存在读取一张缩略图的耗时是毫米级别的,平均耗时3ms。加载完成一屏幕的缩略图,假设6张,只需要18ms,这个耗时是完全满足需求的。

磁盘相比内存还有另一个好处,就是量大管饱。一张缩略图对应的bitmap大小大概是150k。一秒钟一个缩略图,一个10分钟的视频,所有缩略图的大小大概是88Mb。这个内存占用相对于磁盘来说都是小ks。作为对比,小而美的国民APP微信,磁盘占用都是以G为单位。

因此,我们完全可以将所有缩略图缓存在磁盘中,实现整个视频不管如何滑动,都能实现无感零延迟加载缩略图,且对应的内存开销,是可接受的。

这么看来,我们几乎只需要使用磁盘缓存就满足需求了,那岂不是可以直接取消内存缓存,还能减少内存占用?

这个逻辑没有问题,但是我们忽略了RecyclerView的一个刷新特性。当我们调用notifyDataChanged()的时候,会刷新当前显示的所有缩略图。那么在一些需要频繁调用notifyDataChanged()的场景,例如拖动剪辑视频的时候,会不断地去刷新缩略图,频率甚至可能是毫秒级的。磁盘缓存虽然很快,但是在他依旧是一个耗时操作,和内存缓存相比,依旧很慢。其次,当我们高频地左右滑动时间轴,那么显示之外的的缩略图也会被频繁加载。

磁盘读取文件本身是一个耗时的IO操作,高频地进行IO操作,也会降低我们程序的性能。因此这里我们需要结合内存缓存一起来使用。

我们内存缓存,主要解决的场景,是时间轴频繁刷新、以及左右快速来回拖动导致的缩略图频繁请求。那么我们确定内存缓存的上限,为一个屏幕上能显示的缩略图数量的三倍即可。用较少的内存占用,实现较好的表现效果。

ok,到这里我们回顾一下我们整体的缓存策略:

  1. 当发起缩略图请求时,优先判断是否有内存缓存。
  2. 没有内存缓存,则判断是否有磁盘缓存。若存在磁盘缓存则通过IO去加载缩略图,并将结果缓存到内存中。
  3. 没有磁盘缓存,则需要通过解码器去获取缩略图,并将结果缓存到内存和磁盘中。

需要注意的是,每次完成编辑后,需要同步删除所有的磁盘缓存。否则随着时间的推移,我们的app磁盘内存占用,也要向小而美app靠近了。

我们理论分析到这,那么这个缓存策略不就ok了吗?如果仅仅是局限于分析,这个大框架策略,确实没毛病。但在真正落实到实现时,会发现有一些优化的点还需要我们关注,而且会很大程度上,影响我们的性能表现。

结合具体场景优化

1. 异步请求任务去重

从我们上面整体缓存策略来说,每一张缩略图只需要通过解码器加载一次,然后存储在磁盘与内存中即可,也就是理论上,只有首次加载是非常耗时的。

但在实际开发中,RecyclerView的notifyDataChanged()很有可能频繁触发,导致解码器获取缩略图的时候,累积了很多相同的请求。

比如当前正在显示的缩略图如下:

当我们正在瞬间刷新三次的时候,就会累积12个缩略图请求,其中6个是重复的。此时解码器就会把性能,浪费在一些无意义的缩略图请求上。因此我们需要对这6个重复的缩略图进行去重,让同一个缩略图,仅会通过解码器加载一次。

而磁盘加载也是同理,毕竟也是一个耗时的异步操作,也是需要进行缩略图请求任务去重处理。

上面两种异步请求后的缩略图数据,放到内存缓存中就无需要进行去重处理了。

去重的方式很多,例如使用HashSet等。

2. 优先加载当前正在显示的缩略图、预加载缩略图

在体验上,我们还可以做一些优化。

例如解码器请求队列改为请求栈,优先处理当前屏幕上显示的缩略图请求,这样就可以更快看到缩略图显示。

例如可以将所有缩略图在进入剪辑页面的时候全部放入请求栈中,提前预加载缩略图。滑动时,再将新的缩略图请求从栈中提升到栈顶,优先加载当前显示的缩略图。

这些优化策略还有很多细节可以说,这里就不详细展开了。

最后

最后我们再来回顾一下整体的缓存策略,如下图:

相比上个流程图,增加了任务去重以及请求栈结构。

整个优化策略看下来有没有一丢丢眼熟,是不是操作系统的多级缓存很像?我们学习的一些基础知识、思想、策略等,有时候看着很高大上,但在实际应用中,还是有很大的帮助。

其次更重要的一点是,对于策略的分析到方案的落地,中间还存在很多的问题。方案思考分析仅仅只是整体的框架,将这套框架应用到具体的项目中,要完善很多的细节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/619899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

webpack处理图片资源(jpeg,jpg,png等)

在webpack5以前&#xff0c;我们处理图片资源通过 file-loader 和 url-loader 进行处理 现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了&#xff0c;我们只需要简单配置即可处理图片资源 webpack.config.js配置 {test: /\.(png|jpe?g|gif|webp)$/,type: "as…

Kubernetes高级存储

Kubernetes高级存储 PV PVC k8s支持的存储系统很多&#xff0c;全部掌握不现实。为了屏蔽底层存储实现的细节&#xff0c;方便用户使用&#xff0c;k8s引入PV和PVC两种资源对象。 PV(Persistent Volume)持久化卷&#xff0c;对底层共享存储的抽象&#xff0c;一般由k8s管理员进…

如何通过Shopee大数据选品,在3分钟选出热销爆款!

近年来&#xff0c;随着互联网技术的不断发展&#xff0c;人工智能和大数据成为越来越多人们熟知的概念。通过大数据分析进行选品&#xff0c;能够快速精准地预判各行业类目的变化趋势&#xff0c;帮助我们有效地优化选品、做出正确的销售决策。 大数据选品是指通过Shopee多品类…

Linux——进程地址空间

目录 1、程序地址空间 1.1 研究背景 1.2 程序地址空间 1.3 空间布局图代码测试 1.4 用户空间及内核空间 1.5 Linux及windows对比 1.6 分析Linux下虚拟地址及物理地址 2、进程地址空间 2.1 地址空间概念 2.2 地址空间及页表映射分析 2.3 写时拷贝及虚拟地址再次分析 …

【Flowable】Flowable网关

网关用来控制流程的流向 1.排他网关 排他网关&#xff08;exclusive gateway&#xff09;&#xff08;也叫异或网关 XOR gateway&#xff0c;或者更专业的&#xff0c;基于数据的排他网关 exclusive data-based gateway&#xff09;&#xff0c;用于对流程中的决策建模。当执行…

类脑计算讲解

当前&#xff0c;人工智能的发展有两个主要路径&#xff0c;一个是沿计算机科学发展而来的深度学习途径&#xff0c;另一个是沿着模仿人脑发展而来的类脑计算途径。 类脑计算途径 这个方向是以模拟人脑神经网络计算为基础而发展出的一种新型芯片&#xff0c;通过模拟神经元和…

直播商品库功能(互动功能接收端JS-SDK)

功能概述 图&#xff1a;边看边买--效果截图 本模块主要处理商品库相关逻辑&#xff0c;如展示商品、商品推送和商品上下架等消息。 初始化及销毁 在实例化该模块并进行使用之前&#xff0c;需要对SDK进行初始化配置&#xff0c;详细见参考文档。 在线文件引入方式 // scri…

【论文阅读】Lora

概述 目的在原有大模型上进行fine tune&#xff0c;训练个性化模型 idea&#xff1a;将pretrained model参数冻住&#xff0c;额外训练一个module进行调整&#xff0c;最终输出是原始输出经过module的输出。 技巧&#xff1a;通过低秩分解大大降低了需要训练参数的数量。矩阵…

简单AES加解密Demo——带你了解AES

1.AES简介 AES的全称是Advanced Encryption Standard&#xff0c;意思是高级加密标准。它的出现主要是为了取代DES加密算法的&#xff0c;因为我们都知道DES算法的密钥长度是56Bit&#xff0c;因此算法的理论安全强度是2的56次方。但二十世纪中后期正是计算机飞速发展的阶段&am…

外包的水太深了,18k的阿里外包不太敢去.....

有挺多测试员曾在BAT、网易这些大厂做过外包&#xff0c;想必大家也是非常关心此类问题&#xff0c;我就想介绍下“什么是外包&#xff1f;”&#xff0c;“外包公司的现状”&#xff0c;就“为什么这么多人鄙视外包测试岗&#xff1f;”、”阿里18K的外包测试岗能去吗&#xf…

phpstudy搭建dvwa(以及搭建dvwa问题解决)

目录 phpstudy 下载 问题解决 启动问题 DVWA 下载 安装 配置 phpstudy 下载 小皮面板(phpstudy) - 让天下没有难配的服务器环境&#xff01; (xp.cn) 问题解决 启动问题 要使用dvwa靶场&#xff0c;Apache和myql都是需要启动的&#xff0c;但是可能会遇到mysql启动不…

三大抽样分布

1.三大抽样分布 本人博客&#xff1a;总体分布、样本分布、抽样分布的区别 每一个样本统计量&#xff08;本质是随机变量&#xff09;都有一个分布 以样本平均数为例&#xff0c;它是总体平均数的一个估计量&#xff0c;如果按照相同的样本容量&#xff0c;相同的抽样方式&am…

LVS负载均衡群集——NAT模式实例

目录 一、集群与分布式1.1 集群的含义1.2 LVS模型1.3 系统性能扩展方式1.4 群集的三种类型1.4.1 负载均衡群集1.4.2 高可用群集1.4.3 高性能运算群集 1.5 LVS 的负载调度算法①轮询&#xff08;Round Robin&#xff09;②加权轮询&#xff08;Weighted Round Robin&#xff09;…

电脑重装系统到一半遇到死机该如何解决

在进行电脑重装系统的过程中&#xff0c;有时会遇到系统卡住不动的情况&#xff0c;让人苦恼不已。本文将为您解析电脑重装系统中途卡住的原因&#xff0c;并提供有效的解决方法&#xff0c;帮助您顺利完成系统重装。 工具/原料&#xff1a; 系统版本&#xff1a;windows10专业…

.Net Core 6 WebApi 项目搭建(二)

书接上文&#xff0c;上文写了个简单的.net core api程序创建流程&#xff0c;今天来写一下简单项目搭建步骤。 一.Autofac反射程序集方式服务注册 我们这里还是使用Autofac容器&#xff0c;具体使用教程可参考文章《.NET Core基础知识-依赖注入&#xff08;Autofac&#xff…

七、进程程序替换

文章目录 一、进程程序替换&#xff08;一&#xff09;概念&#xff08;二&#xff09;为什么程序替换&#xff08;三&#xff09;程序替换的原理&#xff08;四&#xff09;如何进行程序替换1. execl2. 引入进程创建——子进程执行程序替换&#xff0c;会不会影响父进程呢? &…

node.js卸载、安装、配置详解

node.js卸载、安装、配置详解 一、 node.js卸载二、下载安装2.1 下载2.2 安装2.2.1 选择msi安装2.2.2 选择zip安装 三、配置3.1 环境变量配置3.2 修改缓存、全局模块路径3.3 全局安装3.4 设置淘宝镜像3.5 全局安装 四、node-red安装及配置 一、 node.js卸载 第一步&#xff1a…

Salesforce顾问如何实现逆袭成为公司CIO?

Salesforce是一个适用于所有业务流程的绝佳平台&#xff0c;它的设置方式意味着使用者可以培养出独特的技能。其中一些从业者非常适合担任高管&#xff0c;Trailblazers通常会晋升到高层职位。 本文将帮助Trailblazers了解职位晋升需要的能力&#xff0c;为Salesforce之旅做好…

【大数据原理与技术】期末习题总结大全,建议收藏

【大数据原理与技术】期末习题总结大全&#xff0c;建议收藏 &#x1f4e2;&#x1f4e2;题目来源于B站&#xff0c;慕课网&#xff0c;百度 &#xff0c;适用于期末复习&#xff0c;内容仅供参考&#xff0c;祝大家考试顺利&#xff01; &#x1f4e2;以下思维导图我是根据我们…

LiveGBS国标GB/T28181流媒体平台功能-作为下级国标平台级联到第三方海康大华宇视华为等国标平台及其它政务公安内网国标视频平台

LiveGBS国标GB/T28181流媒体平台功能-作为下级国标平台级联到第三方海康大华宇视华为等国标平台及其它政务公安内网国标视频平台 1、GB/T28181级联是什么2、搭建GB28181国标流媒体平台3、获取上级平台接入信息3.1、如何提供信息给上级3.2、上级国标平台如何添加下级域3.2、接入…