Android视频/音频缓存框架AndroidVideoCache(Okhttp)详解

时间:2021-05-20

关于安卓边下边播功能,供大家参考,具体内容如下

对于视频/音频软件,音乐软件,视频软件,都有缓存这个功能,那如何实现边下边播功能:

  • 如何实现这个边下边播功能?
  • 文件是否支持同时读写?(Mediaplayer 播放文件,从网络上下载文件)
  • 播放与下载进度如何协调?
  • 已缓存的文件需及时清理

经过一番折腾,我 find 了 : [ AndroidVideoCache ],这个库是 danikula 大神写,看完源码后收益匪浅。实现流媒体边下边播原理利用socket 开启一个本机的代理服务器

结合自身需求,修改了该库,使用okhttp进行网络请求:
AndroidVideoCache (改成 okhttp 缓存)

package com.danikula.videocache;import android.text.TextUtils;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InterruptedIOException;import java.util.Map;import java.util.concurrent.TimeUnit;import com.danikula.videocache.file.MyLog;import okhttp3.Call;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;import static com.danikula.videocache.ProxyCacheUtils.DEFAULT_BUFFER_SIZE;import static com.danikula.videocache.ProxyCacheUtils.LOG_TAG;import static java.net.HttpURLConnection.HTTP_OK;import static java.net.HttpURLConnection.HTTP_PARTIAL;/** * {@link Source} that uses http resource as source for {@link ProxyCache}. * * @author Alexey Danilov (danikula@gmail.com). * * 从URL 获取数据 */public class HttpUrlSource implements Source { private static final int MAX_REDIRECTS = 5; public final String url; private static OkHttpClient okHttpClient = new OkHttpClient(); private Call requestCall = null; private InputStream inputStream; private volatile int length = Integer.MIN_VALUE; private volatile String mime; private Map<String, String> headers; public HttpUrlSource(String url) { this(url, ProxyCacheUtils.getSupposablyMime(url)); } public HttpUrlSource(String url, Map<String, String> headers) { this(url, ProxyCacheUtils.getSupposablyMime(url)); this.headers = headers; } public HttpUrlSource(String url, String mime) { this.url = Preconditions.checkNotNull(url); this.mime = mime; } public HttpUrlSource(HttpUrlSource source) { this.url = source.url; this.mime = source.mime; this.length = source.length; } @Override public synchronized int length() throws ProxyCacheException { if (length == Integer.MIN_VALUE) { fetchContentInfo(); } return length; } @Override public void open(int offset) throws ProxyCacheException { try { Response response = openConnection(offset, -1); mime = response.header("Content-Type"); inputStream = new BufferedInputStream(response.body().byteStream(), DEFAULT_BUFFER_SIZE); length = readSourceAvailableBytes(response, offset, response.code()); } catch (IOException e) { throw new ProxyCacheException("Error opening okHttpClient for " + url + " with offset " + offset, e); } } private int readSourceAvailableBytes(Response response, int offset, int responseCode) throws IOException { int contentLength = Integer.valueOf(response.header("Content-Length", "-1")); return responseCode == HTTP_OK ? contentLength : responseCode == HTTP_PARTIAL ? contentLength + offset : length; } @Override public void close() throws ProxyCacheException { if (okHttpClient != null && inputStream != null && requestCall != null) { try { inputStream.close(); requestCall.cancel(); } catch (IOException e) { e.printStackTrace(); } } } @Override public int read(byte[] buffer) throws ProxyCacheException { if (inputStream == null) { throw new ProxyCacheException("Error reading data from " + url + ": okHttpClient is absent!"); } try { return inputStream.read(buffer, 0, buffer.length); } catch (InterruptedIOException e) { throw new InterruptedProxyCacheException("Reading source " + url + " is interrupted", e); } catch (IOException e) { throw new ProxyCacheException("Error reading data from " + url, e); } } private void fetchContentInfo() throws ProxyCacheException { MyLog.d(LOG_TAG, "Read content info from " + url); Response response = null; InputStream inputStream = null; try { response = openConnection(0, 20000); length = Integer.valueOf(response.header("Content-Length", "-1")); mime = response.header("Content-Type"); inputStream = response.body().byteStream(); MyLog.i(LOG_TAG, "Content info for `" + url + "`: mime: " + mime + ", content-length: " + length); } catch (IOException e) { MyLog.e(LOG_TAG, "Error fetching info from " + url, e); } finally { ProxyCacheUtils.close(inputStream); if (response != null) { requestCall.cancel(); } } } private Response openConnection(int offset, int timeout) throws IOException, ProxyCacheException { boolean redirected; int redirectCount = 0; String url = this.url; Request request = null; //do { MyLog.d(LOG_TAG, "Open okHttpClient " + (offset > 0 ? " with offset " + offset : "") + " to " + url);// okHttpClient = (HttpURLConnection) new URL(url).openConnection(); Request.Builder builder = new Request.Builder(); builder.url(url); //flac if(headers != null) { //设置请求头 for (Map.Entry<String, String> entry : headers.entrySet()) { MyLog.i(LOG_TAG, "请求头信息 key:" + entry.getKey() +" Value" + entry.getValue());// okHttpClient.setRequestProperty(entry.getKey(), entry.getValue()); builder.addHeader(entry.getKey(), entry.getValue()); } } if (offset > 0) { builder.addHeader("Range", "bytes=" + offset + "-"); } request = builder.build(); requestCall = okHttpClient.newCall(request); //} while (redirected); return requestCall.execute(); } public synchronized String getMime() throws ProxyCacheException { if (TextUtils.isEmpty(mime)) { fetchContentInfo(); } return mime; } public String getUrl() { return url; } @Override public String toString() { return "HttpUrlSource{url='" + url + "}"; }}

下载地址:Android视频音频缓存框架AndroidVideoCache

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章