我们都了解播放器的作用就是把音视频压缩数据转换成原始的音视频数据渲染出来,这样我们就可以看到画面、听到声音了。这里的播放器就存在两个问题,第一个问题是视频源存在云端,我们每次看完视频之后重新观看,需要重新请求远端视频数据,这就会造成带宽的浪费。第二个问题是视频的秒开体验当我们从Feed流点击视频播放的时候,由于需要从云端获取视频,造成秒开体验较差。我们该如何去解决这两个问题呢?这就是我们今天要说的视频缓存库的核心功能了。下面让我们走进Android视频缓存库,看它是如何设计、如何优雅的解决这两个问题的。
下面会详细分析AndroidVideoCahce的实现原理、AndroidVideoCahce存在的问题、AndroidVideoCahce的优化重构。最终打造一款适合业务需求、稳定的视频缓存库。
AndroidVideoCache通过代理的策略将我们的网络请求代理到本地服务,本地服务首先判断播放器获取的数据本地缓存是否存在,如果存在就从本地缓存获取数据返还给播放器;如果不存在需要发起网络请求就先向本地写入数据,再从本地服务获取数据给播放器,从而做到数据的复用。

上面的时序图,大致描述了AndroidVideoCahce内部的基本流程,但内部是如何去实现的还是一头雾水,下面具体分析下AndroidVideoCahce代码结构、AndroidVideoCahce的线程模型、有多少模块、每个模块的作用、模块之间的交互;了解完了他们,AndroidVideoCahce中的知识点基本全部掌握了。

DiskUsage: 本地磁盘文件缓存策略接口
LruDiskUsage: 根据LRU算法实现的本地磁盘文件缓存策略抽象类
TotalCountLruDiskUsage: 文件数量+LRU算法实现的本地磁盘文件缓存策略实现类
TotalSizeLruDiskUsage: 文件缓存大小+LRU算法实现的本地磁盘文件缓存策略实现类
UnlimitedDiskUsage:本地磁盘文件缓存无任何限制策略实现类
FileNameGenerator:网络资源缓存到本地文件的命名接口
Md5FileNameGenerator: 网络资源缓存到本地,本地文件根据文件的md5命名实现类
FileCache: RandomAccessFile 的封装
1. 把网络获取的数据缓存到本地
2. 把本地缓存的数据提供给播放器
3. 由于网络模块写功能、本地缓存模块读功能都需要操作同一个File,需要加锁。
HeaderInjector: 添加自定义服务器请求头接口
EmptyHeadersInjector:自定义服务器请求头空实现
SourceInfoStorage: SourceInfo本地存储化接口
NoSourceInfoStorage: SourceInfo本地存储化接口的空实现
DatabaseSourceInfoStorage: SourceInfo本地存储化SQLite实现
SourceInfoStorageFactory:获取SourceInfoStorage实例的工厂
数据缓存接口;通过实现该接口我们可以把音视频数据缓存到本地文件(FileCache)或内存(ByteArrayCache)中;
获取数据接口;根据数据源存储的方式(网络、本地、内存)不同,我们可以有不同的实现;
当前视频缓存进度回调接口
Source接口的实现,内部通过HttpURLConnection与云端建立链接获取云端音视频数据
数据缓存在内存中的实现
从内存中获取数据的实现
业务端自定义数据的封装,AndroidVideoCahce内部会根据Config的配置使用
通过封装Source、Cache接口,实现从Source中获取数据保存到Cache中;
通过封装Source、Cache的具体实现类:HttpUrlSource、FileCache,实现从HttpUrlSource获取数据保存到FileCache中;
站在本地代理缓存服务的角度去看,HttpProxyCacheServerClients起到一个客户端的作用,它通过创建、封装HttpUrlSource、FileCache、HttpProxyCache、CacheListener起到一个统筹全局的作用;
内部通过ServerSocket维护一个本地服务,通过把云端的视频播放地址(url)转换为http://127.0.0.1:port/url 本地代理请求链接,这样播放器就会与我们的本地服务建立链接。然后通过HttpProxyCacheServerClients实现从云端获取数据,保存到本地,再从本地获取数据返还给播放器的逻辑。
这里从功能的角度去分析下AndroidVideoCahce;主要分析AndroidVideoCahce包含哪些功能,这些功能之间是如何联系、如何协作实现视频边播边缓冲的。
数据下载模块主要功能是从网络获取音视频数据到手机内存中;AndroidVideoCahce的主要实现类是HttpUrlSource;
数据本地缓存模块主要有两部分功能:1. 写功能: 把数据下载模块从云端获取的数据保存到本地;2. 读功能:从本地缓存中读取数据;AndroidVideoCahce的主要实现类是FileCache;
服务处理模块是一个控制模块;它通过创建、封装HttpUrlSource、FileCache、HttpProxyCache负责调控从网络获取数据并保存到本地,再从本地获取数据返回给请求端;
对某个视频缓存的数量或大小满足LRU条件时进行清除;
内部通过ServerSocket维护一个本地服务,通过把云端的视频播放地址(url)转换为http://127.0.0.1:port/url 本地代理请求链接,这样播放器就会与我们的本地服务建立链接。然后通过服务处理模块调用数据下载模块从云端获取数据,调用数据本地缓存模块保存到本地,再调用数据本地缓存模块获取数据返还给播放器的逻辑。
AndroidVideoCahce是允许多个视频并发缓存的,当前只讨论单个视频缓存的情况下,AndroidVideoCahce内部会创建几个线程及每个线程的功能;后面再讨论多个视频并发缓存的情况就比较容易了。
AndroidVideoCahce只考虑单视频缓存的情况下会涉及到5个线程:
AndroidVideoCache在实现上还有好多需要改进的地方,这里列出了几个不足之处,后面会逐个解决,达到在功能、性能、稳定都达到行业标准。
AndroidVideoCache的本地缓存在FileCache中实现;由于网络获取的数据需要保本到本地,同时服务处理需要从本地缓存中获取数据给到请求端,所以这里使用了RandomAccessFile,由于RandomAccessFile支持“随机访问”的方式访问文件,可以直接跳转到文件的任意地方来读写数据。
当网络获取的数据需要保本到本地时,通过下面的方式就可以了
@Override
public synchronized void append(byte[] data, int length) throws ProxyCacheException {
try {
if (isCompleted()) {
throw new ProxyCacheException("Error append cache: cache file " + file + " is completed!");
}
dataFile.seek(available());
dataFile.write(data, 0, length);
} catch (IOException e) {
String format = "Error writing %d bytes to %s from buffer with size %d";
throw new ProxyCacheException(String.format(format, length, dataFile, data.length), e);
}
}
当服务处理需要从本地缓存中获取数据给到请求端时:
@Override
public synchronized int read(byte[] buffer, long offset, int length) throws ProxyCacheException {
try {
dataFile.seek(offset);
return dataFile.read(buffer, 0, length);
} catch (IOException e) {
String format = "Error reading %d bytes with offset %d from file[%d bytes] to buffer[%d bytes]";
throw new ProxyCacheException(String.format(format, length, offset, available(), buffer.length), e);
}
}
这样的本地缓存其实存在的问题还是比较大的;最大的问题就是当视频很大,我们拖动视频时,就会出现视频从上个缓存点到当前拖动点缓存时间会很长,体验很差。为什么会出现这种情况就是因为这里的缓存实现只能从文件尾一点点写入缓存,只能从上个缓存点缓存到了当前拖动点才能继续播放;
public void processRequest(GetRequest request, Socket socket) throws IOException, ProxyCacheException {
OutputStream out = new BufferedOutputStream(socket.getOutputStream());
String responseHeaders = newResponseHeaders(request);
out.write(responseHeaders.getBytes("UTF-8"));
long offset = request.rangeOffset;
if (isUseCache(request)) {
responseWithCache(out, offset);
} else {
responseWithoutCache(out, offset);
}
}
private boolean isUseCache(GetRequest request) throws ProxyCacheException {
long sourceLength = source.length();
boolean sourceLengthKnown = sourceLength > 0;
long cacheAvailable = cache.available();
// do not use cache for partial requests which too far from available cache. It seems user seek video.
return !sourceLengthKnown || !request.partial || request.rangeOffset <= cacheAvailable + sourceLength * NO_CACHE_BARRIER;
}
当拖动视频之后,AndroidVideoCache内部会自己判断下,当前拖动点需要缓存的视频数据是否是在整个视频长度的20%以内,如果是就继续执行本地缓存,否则不进行本地缓存;
但这样也会有问题,当需要播放的视频量太大时,这20%的视频量也是挺多的,都必须缓存到本地,才能后面继续播放,体验也是比较差的;
例如现在有一个1G的视频,当视频缓存到100M的时候,把视频seek到300M的地方,这时候就需要把100M~300M之间的视频也需要缓存到本地才能继续播放;这200M的数据的缓存也是挺长的,会一直处在loading状态。
AndroidVideoCache内部实现的以文件内容追加的形式进行缓存的方案,适应场景比较有限,但视频比较小或视频比较大但不允许拖动是可以使用的。一旦出现视频比较大又频繁拖动的情况下,就会出现视频缓存造成体验差与不缓存造成高带宽费用的问题。这里如果想两者兼得就需要新的分片缓存实现方案了。
分片缓存就是为了解决视频拖动导致视频大量缓存造成体验差或者不缓存造成高带宽费用的问题;这里的分片与HLS协议里面的ts分片文件是不一样的;
HLS协议里面的ts分片文件是把整个文件分成一段一段的ts文件。
分片缓存核心点有三个步骤:
分片缓存文件的创建需要同时满足下面几个条件,才会创建新的分片文件;

这里举个例子来理解分片缓存文件的合并;当前播放的视频存在3个缓存文件0.download,大小10M;12x1024x1024.download,大小5M;20x1024x1024.download,大小10M;下面画了一张图加深对分片缓存文件的合并过程的理解;

本地数据的清理模块会对某个视频缓存的数量或大小满足LRU条件时进行清除;这里就涉及到对分片缓存的删除;
在AndroidVideoCache的不足中说到 AndroidVideoCache没有实现预下载的功能,预下载的同时不能抢占当前播放视频的带宽。这个是后续优化的重点,等到后面实现并上线了,这里会继续补上优化与重构过程。
动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、
2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
目前我正在使用这个正则表达式从YoutubeURL中提取视频ID:url.match(/v=([^&]*)/)[1]我怎样才能改变它,以便它也可以从这个没有v参数的YoutubeURL获取视频ID:http://www.youtube.com/user/SHAYTARDS#p/u/9/Xc81AajGUMU感谢阅读。编辑:我正在使用ruby1.8.7 最佳答案 对于Ruby1.8.7,这就可以了。url_1='http://www.youtube.com/watch?v=8WVTOUh53QY&feature=feedf'url
2022年底,OpenAI的预训练模型ChatGPT给人工智能领域的爱好者和研究人员留下了深刻的印象和启发,他展现的惊人能力将人工智能的研究和应用热度推向高潮,网上也充斥着和ChatGPT的各种聊天,他可以作诗、写小说、写代码、讨论疫情问题等。下面就是一些他的神回复:人命关天的坑: 写歌,留给词作者的机会不多了。。。 回答人类怎么样面对人工智能: 什么是ChatGPT?借用网上的一段介绍,ChatGPT是由人工智能研究实验室OpenAI在2022年11月30日发布的全新聊天机器人模型,一款人工智能技术驱动的自然语言处理工具。它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动
一、什么是web项目ui自动化测试?通过测试工具模拟人为操控浏览器,使软件按照测试人员的预定计划自动执行测试的一种方式,可以完成许多手工测试无法完成或者不易实现的繁琐工作。正确使用自动化测试,可以更全面的对软件进行测试,从而提高软件质量进而缩短迭代周期。二、构建测试用例的“九部曲”(一)创建流程包划分功能模块日常测试活动中,都会根据功能模块进行拆分,所以在设计器中我们可以通过创建流程包的方式来拆分需要测试的功能模块,如下图中操作创建一个电脑流程包并且取名为对应的功能模块名称,如果有多个功能模块就创建多个对应的流程包,实在RPA设计器有易用的图形可视化界面,方便管理较多的功能模块。(二)在流程包
目录需求基于JavaCV跨平台执行ffmpeg命令[^1]坑一内存不足坑二多个ffmpeg进程并行导致IO负载大,进而导致ioerror?坑三使用Java操作ffmpeg时,有时会卡死坑四Process的waitFor死锁问题及解决办法需求给透明背景的视频自动叠加一张背景图片基于JavaCV跨平台执行ffmpeg命令1我测试发现的本需求的最小依赖:dependency>groupId>org.bytedecogroupId>artifactId>ffmpeg-platform-gplartifactId>version>5.0-1.5.7version>dependency>核心代码:Stri
摘要本论文主要论述了如何使用Python技术开发一个短视频智能推荐,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述短视频智能推荐的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程,对系统进行各个阶段分析设计。 短视频智能推荐的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、热门视频管理、用户上传管理、系统管理,用户:首页、个人中心、用户上传管理、我的收藏管理,前台首页;首页、热门视频、用户上传、公告信息、个人中心、后台管理等功能。由于本网站的功能模块设计比较全面,所以使得整个短视频智能推荐信
运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid