From 293b17f8715dd41d5435a5e9c76b731a9ef5dffc Mon Sep 17 00:00:00 2001 From: guoshuyu Date: Mon, 21 May 2018 15:54:19 +0800 Subject: [PATCH] cache logic --- .../gsyvideoplayer/GSYApplication.java | 3 +- .../exo/DetailExoListPlayer.java | 3 - .../gsyvideoplayer/GSYVideoBaseManager.java | 38 ++++---- .../gsyvideoplayer/cache/CacheFactory.java | 6 +- .../cache/ExoPlayerCacheManager.java | 59 ++++++++++++ .../gsyvideoplayer/cache/ICacheManager.java | 4 +- .../cache/ProxyCacheManager.java | 21 ++++- .../video/base/GSYVideoControlView.java | 22 +++-- .../video/base/GSYVideoView.java | 8 +- .../video/base/GSYVideoViewBridge.java | 4 +- .../ijk/media/exo2/ExoSourceManager.java | 93 +++++++++++++++++-- 11 files changed, 211 insertions(+), 50 deletions(-) create mode 100644 gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ExoPlayerCacheManager.java diff --git a/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java b/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java index 6ea20b3..d5f3d62 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java +++ b/app/src/main/java/com/example/gsyvideoplayer/GSYApplication.java @@ -3,6 +3,7 @@ package com.example.gsyvideoplayer; import android.app.Application; import com.shuyu.gsyvideoplayer.GSYVideoManager; +import com.shuyu.gsyvideoplayer.player.IJKPlayerManager; import com.shuyu.gsyvideoplayer.utils.GSYVideoType; //import com.squareup.leakcanary.LeakCanary; @@ -37,7 +38,7 @@ public class GSYApplication extends Application { //GSYVideoType.setRenderType(GSYVideoType.SUFRACE); //GSYVideoType.setRenderType(GSYVideoType.GLSURFACE); - //GSYVideoManager.instance().setLogLevel(IjkMediaPlayer.IJK_LOG_SILENT); + //IJKPlayerManager.setLogLevel(IjkMediaPlayer.IJK_LOG_SILENT); //GSYVideoType.setShowType(GSYVideoType.SCREEN_MATCH_FULL); } diff --git a/app/src/main/java/com/example/gsyvideoplayer/exo/DetailExoListPlayer.java b/app/src/main/java/com/example/gsyvideoplayer/exo/DetailExoListPlayer.java index 6c197a8..c6eda2e 100644 --- a/app/src/main/java/com/example/gsyvideoplayer/exo/DetailExoListPlayer.java +++ b/app/src/main/java/com/example/gsyvideoplayer/exo/DetailExoListPlayer.java @@ -40,9 +40,6 @@ public class DetailExoListPlayer extends GSYBaseActivityDetail header, File cachePath) { + if (!(mediaPlayer instanceof IjkExo2MediaPlayer)) { + throw new UnsupportedOperationException("ExoPlayerCacheManager only support IjkExo2MediaPlayer"); + } + IjkExo2MediaPlayer exoPlayer = ((IjkExo2MediaPlayer) mediaPlayer); + mExoSourceManager = exoPlayer.getExoHelper(); + //通过自己的内部缓存机制 + exoPlayer.setCache(true); + exoPlayer.setCacheDir(cachePath); + exoPlayer.setDataSource(context, Uri.parse(url), header); + } + + @Override + public void clearCache(Context context, File cachePath, String url) { + ExoSourceManager.clearCache(context, cachePath, url); + } + + @Override + public void release() { + mExoSourceManager = null; + } + + @Override + public boolean hadCached() { + return mExoSourceManager != null && mExoSourceManager.hadCached(); + } + + @Override + public boolean cachePreview(Context context, File cacheDir, String url) { + return ExoSourceManager.cachePreView(context, cacheDir, url); + } + + @Override + public void setCacheAvailableListener(ICacheAvailableListener cacheAvailableListener) { + + } +} diff --git a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ICacheManager.java b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ICacheManager.java index 0bd6523..ba652e8 100644 --- a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ICacheManager.java +++ b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ICacheManager.java @@ -15,12 +15,14 @@ public interface ICacheManager { void doCacheLogic(Context context, IMediaPlayer mediaPlayer, String url, Map header, File cachePath); - void clearCache(Context context, String url); + void clearCache(Context context, File cachePath, String url); void release(); boolean hadCached(); + boolean cachePreview(Context context, File cacheDir, String url); + void setCacheAvailableListener(ICacheAvailableListener cacheAvailableListener); interface ICacheAvailableListener { diff --git a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ProxyCacheManager.java b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ProxyCacheManager.java index cd6af7d..cc92494 100644 --- a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ProxyCacheManager.java +++ b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/cache/ProxyCacheManager.java @@ -84,7 +84,7 @@ public class ProxyCacheManager implements ICacheManager, CacheListener { } @Override - public void clearCache(Context context, String url) { + public void clearCache(Context context, File cachePath, String url) { if (TextUtils.isEmpty(url)) { String path = StorageUtils.getIndividualCacheDirectory (context.getApplicationContext()).getAbsolutePath(); @@ -92,9 +92,9 @@ public class ProxyCacheManager implements ICacheManager, CacheListener { } else { Md5FileNameGenerator md5FileNameGenerator = new Md5FileNameGenerator(); String name = md5FileNameGenerator.generate(url); - if (mCacheDir != null) { - String tmpPath = mCacheDir.getAbsolutePath() + File.separator + name + ".download"; - String path = mCacheDir.getAbsolutePath() + File.separator + name ; + if (cachePath != null) { + String tmpPath = cachePath.getAbsolutePath() + File.separator + name + ".download"; + String path = cachePath.getAbsolutePath() + File.separator + name; CommonUtil.deleteFile(tmpPath); CommonUtil.deleteFile(path); } else { @@ -121,6 +121,16 @@ public class ProxyCacheManager implements ICacheManager, CacheListener { } } + @Override + public boolean cachePreview(Context context, File cacheDir, String url) { + HttpProxyCacheServer proxy = getProxy(context.getApplicationContext(), cacheDir); + if (proxy != null) { + //此处转换了url,然后再赋值给mUrl。 + url = proxy.getProxyUrl(url); + } + return (!url.startsWith("http")); + } + @Override public boolean hadCached() { return mCacheFile; @@ -157,6 +167,7 @@ public class ProxyCacheManager implements ICacheManager, CacheListener { return new HttpProxyCacheServer.Builder(context.getApplicationContext()) .headerInjector(new UserAgentHeadersInjector()).build(); } + /** * for android video cache header */ @@ -209,6 +220,6 @@ public class ProxyCacheManager implements ICacheManager, CacheListener { ProxyCacheManager.instance().newProxy(context, file)) : proxy; } } - + } diff --git a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoControlView.java b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoControlView.java index ac5c912..0365e2a 100644 --- a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoControlView.java +++ b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoControlView.java @@ -899,17 +899,27 @@ public abstract class GSYVideoControlView extends GSYVideoView implements View.O secProgress = getGSYVideoManager().getBufferedPercentage(); } if (secProgress > 94) secProgress = 100; - if (secProgress != 0 && !getGSYVideoManager().isCacheFile()) { - mProgressBar.setSecondaryProgress(secProgress); - } + setSecondaryProgress(secProgress); mTotalTimeTextView.setText(CommonUtil.stringForTime(totalTime)); if (currentTime > 0) mCurrentTimeTextView.setText(CommonUtil.stringForTime(currentTime)); if (mBottomProgressBar != null) { if (progress != 0) mBottomProgressBar.setProgress(progress); - if (secProgress != 0 && !getGSYVideoManager().isCacheFile()) + setSecondaryProgress(secProgress); + } + } + + protected void setSecondaryProgress(int secProgress) { + if (mProgressBar != null ) { + if (secProgress != 0 && !getGSYVideoManager().isCacheFile()) { + mProgressBar.setSecondaryProgress(secProgress); + } + } + if (mBottomProgressBar != null) { + if (secProgress != 0 && !getGSYVideoManager().isCacheFile()) { mBottomProgressBar.setSecondaryProgress(secProgress); + } } } @@ -1005,8 +1015,8 @@ public abstract class GSYVideoControlView extends GSYVideoView implements View.O protected boolean isShowNetConfirm() { - return !mUrl.startsWith("file") && !mUrl.startsWith("android.resource") && !CommonUtil.isWifiConnected(getContext()) - && mNeedShowWifiTip && !getGSYVideoManager().isCacheFile(); + return !mOriginUrl.startsWith("file") && !mOriginUrl.startsWith("android.resource") && !CommonUtil.isWifiConnected(getContext()) + && mNeedShowWifiTip && !getGSYVideoManager().cachePreview(mContext.getApplicationContext(), mCachePath, mOriginUrl); } private class ProgressTimerTask extends TimerTask { diff --git a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoView.java b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoView.java index 79243a1..499c222 100644 --- a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoView.java +++ b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoView.java @@ -681,15 +681,13 @@ public abstract class GSYVideoView extends GSYTextureRenderView implements GSYMe * 清除当前缓存 */ public void clearCurrentCache() { - //只有都为true时,才是缓存文件 if (getGSYVideoManager().isCacheFile() && mCache) { //是否为缓存文件 - Debuger.printfError(" mCacheFile Local Error " + mUrl); - //可能是因为缓存文件除了问题 - CommonUtil.deleteFile(mUrl.replace("file://", "")); + Debuger.printfError("Play Error " + mUrl); mUrl = mOriginUrl; + getGSYVideoManager().clearCache(mContext, mCachePath, mOriginUrl); } else if (mUrl.contains("127.0.0.1")) { - getGSYVideoManager().clearCache(getContext(), mOriginUrl); + getGSYVideoManager().clearCache(getContext(), mCachePath, mOriginUrl); } } diff --git a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoViewBridge.java b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoViewBridge.java index 17cc009..6b5bf98 100644 --- a/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoViewBridge.java +++ b/gsyVideoPlayer-java/src/main/java/com/shuyu/gsyvideoplayer/video/base/GSYVideoViewBridge.java @@ -61,6 +61,8 @@ public interface GSYVideoViewBridge { boolean isCacheFile(); - void clearCache(Context context, String url); + boolean cachePreview(Context context, File cacheDir, String url); + + void clearCache(Context context, File clearCache, String url); } diff --git a/gsyvideoplayer-exo2/src/main/java/tv/danmaku/ijk/media/exo2/ExoSourceManager.java b/gsyvideoplayer-exo2/src/main/java/tv/danmaku/ijk/media/exo2/ExoSourceManager.java index bd8e9e9..c015b86 100644 --- a/gsyvideoplayer-exo2/src/main/java/tv/danmaku/ijk/media/exo2/ExoSourceManager.java +++ b/gsyvideoplayer-exo2/src/main/java/tv/danmaku/ijk/media/exo2/ExoSourceManager.java @@ -3,6 +3,7 @@ package tv.danmaku.ijk.media.exo2; import android.content.Context; import android.net.Uri; import android.support.annotation.Nullable; +import android.text.TextUtils; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ext.rtmp.RtmpDataSourceFactory; @@ -22,12 +23,15 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.upstream.cache.Cache; import com.google.android.exoplayer2.upstream.cache.CacheDataSource; import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory; +import com.google.android.exoplayer2.upstream.cache.CacheSpan; +import com.google.android.exoplayer2.upstream.cache.CacheUtil; import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor; import com.google.android.exoplayer2.upstream.cache.SimpleCache; import com.google.android.exoplayer2.util.Util; import java.io.File; import java.util.Map; +import java.util.NavigableSet; /** * Created by guoshuyu on 2018/5/18. @@ -37,14 +41,20 @@ public class ExoSourceManager { private static final String TAG = "ExoSourceManager"; + private static final long DEFAULT_MAX_SIZE = 512 * 1024 * 1024; + public static final int TYPE_RTMP = 4; - protected Context mAppContext; + protected static Cache mCache; - protected Cache mCache; + protected Context mAppContext; protected Map mMapHeadData; + protected String mDataSource; + + private boolean isCached = false; + public static ExoSourceManager newInstance(Context context, @Nullable Map mapHeadData) { return new ExoSourceManager(context, mapHeadData); } @@ -55,6 +65,7 @@ public class ExoSourceManager { } public MediaSource getMediaSource(String dataSource, boolean preview, boolean cacheEnable, boolean isLooping, File cacheDir) { + mDataSource = dataSource; Uri contentUri = Uri.parse(dataSource); int contentType = inferContentType(dataSource); MediaSource mediaSource; @@ -109,11 +120,10 @@ public class ExoSourceManager { } } - /** * 本地缓存目录 */ - public Cache getCache(Context context, File cacheDir) { + public static synchronized Cache getCacheSingleInstance(Context context, File cacheDir) { String dirs = context.getCacheDir().getAbsolutePath(); if (cacheDir != null) { dirs = cacheDir.getAbsolutePath(); @@ -122,13 +132,14 @@ public class ExoSourceManager { String path = dirs + File.separator + "exo"; boolean isLocked = SimpleCache.isCacheFolderLocked(new File(path)); if (!isLocked) { - mCache = new SimpleCache(new File(path), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 100)); + mCache = new SimpleCache(new File(path), new LeastRecentlyUsedCacheEvictor(DEFAULT_MAX_SIZE)); } } return mCache; } public void release() { + isCached = false; if (mCache != null) { try { mCache.release(); @@ -139,17 +150,53 @@ public class ExoSourceManager { } } + /** + * Cache需要release之后才能clear + * + * @param context + * @param cacheDir + * @param url + */ + public static void clearCache(Context context, File cacheDir, String url) { + try { + Cache cache = getCacheSingleInstance(context, cacheDir); + if (!TextUtils.isEmpty(url)) { + if (cache != null) { + CacheUtil.remove(cache, CacheUtil.generateKey(Uri.parse(url))); + } + } else { + if (cache != null) { + for (String key : cache.getKeys()) { + CacheUtil.remove(cache, key); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static boolean cachePreView(Context context, File cacheDir, String url) { + return resolveCacheState(getCacheSingleInstance(context, cacheDir), url); + } + + public boolean hadCached() { + return isCached; + } + /** * 获取SourceFactory,是否带Cache */ private DataSource.Factory getDataSourceFactoryCache(Context context, boolean cacheEnable, boolean preview, File cacheDir) { if (cacheEnable) { - Cache cache = getCache(context, cacheDir); - return new CacheDataSourceFactory(cache, getDataSourceFactory(context, preview), CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR); - } else { - return getDataSourceFactory(context, preview); + Cache cache = getCacheSingleInstance(context, cacheDir); + if (cache != null) { + isCached = resolveCacheState(cache, mDataSource); + return new CacheDataSourceFactory(cache, getDataSourceFactory(context, preview), CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR); + } } + return getDataSourceFactory(context, preview); } /** @@ -170,4 +217,32 @@ public class ExoSourceManager { } return dataSourceFactory; } + + /** + * 根据缓存块判断是否缓存成功 + * + * @param cache + */ + private static boolean resolveCacheState(Cache cache, String url) { + boolean isCache = true; + if (!TextUtils.isEmpty(url)) { + String key = CacheUtil.generateKey(Uri.parse(url)); + if (!TextUtils.isEmpty(key)) { + NavigableSet cachedSpans = cache.getCachedSpans(key); + if (cachedSpans.size() == 0) { + isCache = false; + } else { + long contentLength = cache.getContentLength(key); + long currentLength = 0; + for (CacheSpan cachedSpan : cachedSpans) { + currentLength += cache.getCachedLength(key, cachedSpan.position, cachedSpan.length); + } + isCache = currentLength >= contentLength; + } + } else { + isCache = false; + } + } + return isCache; + } } -- GitLab