Android 边播边缓存的实现(MP4 未加密m3u8)
实现思路
红色框的 ProxyServer就是需要实现的一个代理服务器。 当客户端拿到一个视频的url(mp4或者m3u8)时,通过proxyServer转化为一个代理的url,然后请求代理服务器;代理服务器接收到客户端的请求后,先查看本地是否存在缓存,如果不存在则向真实服务器发送请求,拿到结果后再存到本地。
实现重点
缓存是一个代理服务器的主要部分,所以这部分是一个重点。本设计的缓存是一个分片的LRU缓存。分片的好处是灵活方便做LRU。当真实服务器返回一个大文件时,我们在进行切割后缓存在本地,并返回给客户端,不用等待所有数据返回后再返回给客户端。
使用方式
在app初始化的时候 创建代理服务器
public class APP extends Application {
private static VideoCacheServer videoCacheServer;
@Override
public void onCreate() {
super.onCreate();
if (videoCacheServer == null) {
// 缓存路径
String cachePath = getCacheDir().getAbsolutePath();
// 缓存大小 1024 * 1024 * 500
videoCacheServer = new VideoCacheServer(cachePath, 1024 * 1024 * 500);
}
}
public static VideoCacheServer getVideoProxyServer() {
return videoCacheServer;
}
}
代理服务建立好了 ,使用的时候只需要将真实url转换为代理url就好了
String proxyUrl = APP.getVideoProxyServer().getLocalProxyUrl("https://sina.com-h-sina.com/20181024/21342_8f737b71/1000k/hls/index.m3u8");
videoView.setVideoPath(proxyUrl);
转换的规则即讲https的请求转换为http的请求 ,并且替换域名为代理服务器的地址,将真实服务器的地址作为参数添加到代理url的后面。
例如 sina.com-h-sina.com/20181024/21… 地址转换后变成了 https://127.0.0.1:3260/20181024/21342_8f737b71/1000k/hls/index.m3u8?RealHostParam=sina.com-h-sina.com 3260是VideoCacheServer监听的端口
实现细节
代理服务器的建立
public class VideoCacheServer{
private ExecutorService pool = Executors.newFixedThreadPool(20);
public int start() {
if (isRunning) {
return curPort;
}
curPort = new Random().nextInt(65535);
try {
final ServerSocket server = new ServerSocket(curPort);
isRunning = true;
singleService.submit(new Runnable() {
@Override
public void run() {
while (isRunning) {
try {
Socket connection = server.accept();
connection.setKeepAlive(true);
pool.submit(new ProxyHandler(connection));
} catch (IOException ex) {
if (Constant.enableLog) {
logger.log(Level.WARNING, "Exception accepting connection", ex);
}
} catch (Exception ex) {
if (Constant.enableLog) {
logger.log(Level.SEVERE, "Unexpected error", ex);
}
}
}
}
});
return curPort;
} catch (IOException e) {
e.printStackTrace();
return start();
}
}
}
通过socket实现端口的监听,当请求到来时,使用ProxyHandler来处理。
public class ProxyHandler implements Runnable {
private Socket realClientSocket;
ProxyHandler(Socket realClientSocket) {
this.realClientSocket = realClientSocket;
}
@Override
public void run() {
try {
BufferedOutputStream outputStream = new BufferedOutputStream(realClientSocket.getOutputStream());
BufferedInputStream inputStream = new BufferedInputStream(realClientSocket.getInputStream());
HttpRequest realRequest = HttpRequest.parse(inputStream);
HttpResponse response = getResponseWithInterceptorChain(realRequest);
writeResponseAndClose(response, outputStream);
} catch (Exception e) {
if (Constant.enableLog) {
logger.log(Level.SEVERE, "error proxy ", e);
}
} finally {
CloseUtil.close(realClientSocket);
}
}
private HttpResponse getResponseWithInterceptorChain(HttpRequest realRequest) {
List<Interceptor> interceptors = new ArrayList<>();
interceptors.add(new VideoTypeInterceptor());
interceptors.add(new HostFilterInterceptor(curPort));
interceptors.add(new CacheInterceptor(diskCache));
interceptors.add(new ConnectInterceptor());
InterceptorChain interceptorChain = new InterceptorChain(interceptors, realRequest, 0);
return interceptorChain.proceed(realRequest);
}
}
ProxyHandler中使用拦截器的模式,将请求分部处理
VideoTypeInterceptor 将代理的url 还原为真实的url
CacheInterceptor 用于缓存
ConnectInterceptor 建立代理服务器与真实服务器的连接
VideoTypeInterceptor 主要是针对m3u8类型,因为m3u8会先返回一个m3u8的文件,文件里面记录了每个ts的地址,VideoTypeInterceptor就是将返回的文件中的ts地址转换为代理服务器的地址
项目地址 https://github.com/ZhangHao555/VideoCacheServerDemo
代码知识SEO上一篇 : SQL左连接和右连接原理及实例解析
下一篇 : spring boot 如何优雅关闭服务
-
SEO外包最佳选择国内专业的白帽SEO机构,熟知搜索算法,各行业企业站优化策略!
SEO公司
-
可定制SEO优化套餐基于整站优化与品牌搜索展现,定制个性化营销推广方案!
SEO套餐
-
SEO入门教程多年积累SEO实战案例,从新手到专家,从入门到精通,海量的SEO学习资料!
SEO教程
-
SEO项目资源高质量SEO项目资源,稀缺性外链,优质文案代写,老域名提权,云主机相关配置折扣!
SEO资源
-
SEO快速建站快速搭建符合搜索引擎友好的企业网站,协助备案,域名选择,服务器配置等相关服务!
SEO建站
-
快速搜索引擎优化建议没有任何SEO机构,可以承诺搜索引擎排名的具体位置,如果有,那么请您多注意!专业的SEO机构,一般情况下只能确保目标关键词进入到首页或者前几页,如果您有相关问题,欢迎咨询!