Commit cac98eccb272cfb50216dcd2bb9d358e54dae2a7
Merge branch 'master' of bj.gitlab.cnlive.com:cnlive-team/newModuleStrike
Showing
17 changed files
with
274 additions
and
86 deletions
.idea/inspectionProfiles/Project_Default.xml
0 → 100644
| 1 | +<component name="InspectionProjectProfileManager"> | |
| 2 | + <profile version="1.0"> | |
| 3 | + <option name="myName" value="Project Default" /> | |
| 4 | + <inspection_tool class="AndroidLintLockedOrientationActivity" enabled="false" level="ERROR" enabled_by_default="false" /> | |
| 5 | + <inspection_tool class="AndroidLintSourceLockedOrientationActivity" enabled="false" level="ERROR" enabled_by_default="false" /> | |
| 6 | + </profile> | |
| 7 | +</component> | |
| 0 | 8 | \ No newline at end of file | ... | ... |
app/strike/src/main/AndroidManifest.xml
| ... | ... | @@ -34,20 +34,20 @@ |
| 34 | 34 | </provider> |
| 35 | 35 | <activity |
| 36 | 36 | android:name="com.cnlive.strike.demo.activity.tiktok.TikTokViewPager2Activity" |
| 37 | - android:screenOrientation="fullSensor" /> | |
| 37 | + android:screenOrientation="portrait" /> | |
| 38 | 38 | <activity |
| 39 | 39 | android:name="com.cnlive.strike.demo.activity.tiktok.TikTokRecycleActivity" |
| 40 | - android:screenOrientation="fullSensor" /> | |
| 40 | + android:screenOrientation="portrait" /> | |
| 41 | 41 | <activity |
| 42 | 42 | android:name="com.cnlive.strike.demo.activity.tiktok.DemoTikTokActivity" |
| 43 | - android:screenOrientation="fullSensor" /> | |
| 43 | + android:screenOrientation="portrait" /> | |
| 44 | 44 | <activity |
| 45 | 45 | android:name="com.cnlive.strike.demo.activity.tiktok.TikTokVerticalViewPagerActivity" |
| 46 | - android:screenOrientation="fullSensor" /> | |
| 46 | + android:screenOrientation="portrait"/> | |
| 47 | 47 | <activity |
| 48 | 48 | android:name="com.cnlive.strike.demo.activity.ExoPlayerActivity" |
| 49 | 49 | android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" |
| 50 | - android:screenOrientation="fullSensor" /> | |
| 50 | + android:screenOrientation="portrait" /> | |
| 51 | 51 | <activity android:name="com.cnlive.strike.demo.activity.CNplayerActivity" /> |
| 52 | 52 | <activity android:name="com.cnlive.strike.demo.activity.DemoAnimActivity" /> |
| 53 | 53 | <activity | ... | ... |
app/strike/src/main/java/com/cnlive/strike/DemoApplication.java
| ... | ... | @@ -101,7 +101,7 @@ public class DemoApplication extends BaseApplication { |
| 101 | 101 | // .setPlayerFactory(ThunderMediaPlayerFactory.create()) |
| 102 | 102 | .setPlayerFactory(ExoMediaPlayerFactory.create()) |
| 103 | 103 | .setRenderViewFactory(TextureRenderViewFactory.create()) |
| 104 | - .setEnableOrientation(true) | |
| 104 | + .setEnableOrientation(false) | |
| 105 | 105 | // .setEnableAudioFocus(false) |
| 106 | 106 | // .setScreenScaleType(VideoView.SCREEN_SCALE_MATCH_PARENT) |
| 107 | 107 | // .setAdaptCutout(false) | ... | ... |
app/strike/src/main/java/com/cnlive/strike/demo/activity/ExoPlayerActivity.java
| ... | ... | @@ -18,10 +18,13 @@ import com.google.android.exoplayer2.source.hls.HlsMediaSource; |
| 18 | 18 | import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; |
| 19 | 19 | import com.google.android.exoplayer2.util.Util; |
| 20 | 20 | import com.google.android.exoplayer2.video.VideoListener; |
| 21 | +import com.libs.video.util.cache.PreloadManager; | |
| 21 | 22 | import com.libs.video.util.cache.ProxyVideoCacheManager; |
| 22 | 23 | import com.libs.video.video.exoplayer.component.DefaultErrorView; |
| 23 | 24 | import com.libs.video.video.exoplayer.component.DefaultYoukuPrepareView; |
| 24 | 25 | import com.libs.video.video.exoplayer.play.CNVideoView; |
| 26 | +import com.libs.video.video.exoplayer.playerCore.exoplayer.ExoMediaSourceHelper; | |
| 27 | +import com.libs.video.video.exoplayer.util.PlayCacheUtils; | |
| 25 | 28 | import com.libs.video.video.test.CNLiveVideoView; |
| 26 | 29 | import com.libs.video.video.test.VideoPlayer; |
| 27 | 30 | import com.libs.video.video.exoplayer.component.DefaultAdControlView; |
| ... | ... | @@ -44,6 +47,7 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl |
| 44 | 47 | private static final String URL_AD = "https://gslb.miaopai.com/stream/IR3oMYDhrON5huCmf7sHCfnU5YKEkgO2.mp4"; |
| 45 | 48 | |
| 46 | 49 | private StandardVideoController mController; |
| 50 | + private PreloadManager mPreloadManager; | |
| 47 | 51 | |
| 48 | 52 | @Override |
| 49 | 53 | protected int getBindLayoutId() { |
| ... | ... | @@ -82,7 +86,6 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl |
| 82 | 86 | player.prepare(hlsMediaSource); |
| 83 | 87 | |
| 84 | 88 | |
| 85 | - | |
| 86 | 89 | mController = new StandardVideoController(this); |
| 87 | 90 | DefaultAdControlView adControlView = new DefaultAdControlView(this); |
| 88 | 91 | adControlView.setListener(new DefaultAdControlView.AdControlListener() { |
| ... | ... | @@ -96,15 +99,13 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl |
| 96 | 99 | playVideo(); |
| 97 | 100 | } |
| 98 | 101 | }); |
| 99 | - DefaultErrorView errorView=new DefaultErrorView(this); | |
| 100 | - mController.addControlComponent(adControlView,new DefaultYoukuPrepareView(me),errorView); | |
| 102 | + DefaultErrorView errorView = new DefaultErrorView(this); | |
| 103 | + mController.addControlComponent(adControlView, new DefaultYoukuPrepareView(me), errorView); | |
| 101 | 104 | //直播 |
| 102 | - HttpProxyCacheServer cacheServer = ProxyVideoCacheManager.getProxy(this); | |
| 103 | - String proxyUrl = cacheServer.getProxyUrl(URL_AD); | |
| 104 | - binding.playerView.setUrl(proxyUrl); | |
| 105 | -// binding.playerView.setUrl("http://ffyl.vods2.cnlive.com/223/vod/2018/1120/223_88c98ab1395f4762b703fbdd9d59d2e5/ff80808166c2a45201672f14a9933131_800.m3u8"); | |
| 105 | +// binding.playerView.setUrl(proxyUrl); | |
| 106 | + binding.playerView.setUrl("http://ffyl.vods2.cnlive.com/223/vod/2018/1120/223_88c98ab1395f4762b703fbdd9d59d2e5/ff80808166c2a45201672f14a9933131_800.m3u8", true); | |
| 106 | 107 | binding.playerView.setVideoController(mController); |
| 107 | - binding.playerView.setScreenScaleType(CNVideoView.SCREEN_SCALE_16_9); | |
| 108 | +// binding.playerView.setScreenScaleType(CNVideoView.SCREEN_SCALE_16_9); | |
| 108 | 109 | binding.playerView.start(); |
| 109 | 110 | //监听播放结束 |
| 110 | 111 | // binding.playerView.addOnStateChangeListener(new CNVideoView.SimpleOnStateChangeListener() { |
| ... | ... | @@ -154,7 +155,7 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl |
| 154 | 155 | private void playVideo() { |
| 155 | 156 | binding.playerView.release(); |
| 156 | 157 | mController.removeAllControlComponent(); |
| 157 | - mController.addDefaultControlComponent("正片", true); | |
| 158 | + mController.addDefaultControlComponent("正片", false); | |
| 158 | 159 | //重新设置数据 |
| 159 | 160 | // List<String> list = new ArrayList<>(); |
| 160 | 161 | // list.add("http://sbslive.cnrmobile.com/storage/storage4/76/23/10/14de52115893fb5371b7e064f910ab7b.3gp"); |
| ... | ... | @@ -162,8 +163,8 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl |
| 162 | 163 | // list.add("http://ffyl.vods2.cnlive.com/223/vod/2018/1120/223_88c98ab1395f4762b703fbdd9d59d2e5/ff80808166c2a45201672f14a9933131_800.m3u8"); |
| 163 | 164 | // list.add("http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8"); |
| 164 | 165 | // binding.playerView.setDataSource(list); |
| 165 | - binding.playerView.setUrl("rtmp://tyzg.rtmps2.cnlive.com/live-tyzg-577/577_999"); | |
| 166 | - | |
| 166 | + binding.playerView.setUrl("https://qq.com-ok-qq.com/20191005/24249_f5e36323/index.m3u8", true); | |
| 167 | +// binding.playerView.setUrl("rtmp://tyzg.rtmps2.cnlive.com/live-tyzg-577/577_999"); | |
| 167 | 168 | //开始播放 |
| 168 | 169 | binding.playerView.start(); |
| 169 | 170 | } |
| ... | ... | @@ -187,4 +188,6 @@ public class ExoPlayerActivity extends BaseActivity implements VideoListener, Pl |
| 187 | 188 | // }); |
| 188 | 189 | } |
| 189 | 190 | |
| 191 | + | |
| 192 | + | |
| 190 | 193 | } | ... | ... |
cloud/video/src/main/java/com/danikula/videocache/StorageUtils.java
| ... | ... | @@ -37,7 +37,7 @@ public final class StorageUtils { |
| 37 | 37 | * <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or |
| 38 | 38 | * on device's file system depending incoming parameters. |
| 39 | 39 | * |
| 40 | - * @param context Application context | |
| 40 | + * @param context Application context | |
| 41 | 41 | * @return Cache {@link File directory}.<br /> |
| 42 | 42 | * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and |
| 43 | 43 | * {@link Context#getCacheDir() Context.getCacheDir()} returns null). |
| ... | ... | @@ -58,6 +58,26 @@ public final class StorageUtils { |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 60 | /** |
| 61 | + * 获取缓存路径 | |
| 62 | + * | |
| 63 | + * @param context | |
| 64 | + * @return | |
| 65 | + */ | |
| 66 | + public static String getCacheDirectoryPath(Context context) { | |
| 67 | + String appCacheDir = null; | |
| 68 | + if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { | |
| 69 | + appCacheDir = context.getExternalCacheDir().getAbsolutePath(); | |
| 70 | + } | |
| 71 | + if (appCacheDir == null) { | |
| 72 | + appCacheDir = context.getCacheDir().getAbsolutePath(); | |
| 73 | + } | |
| 74 | + if (appCacheDir == null) { | |
| 75 | + appCacheDir = "/data/data/" + context.getPackageName() + "/cache/"; | |
| 76 | + } | |
| 77 | + return appCacheDir; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 61 | 81 | * delete directory |
| 62 | 82 | */ |
| 63 | 83 | public static boolean deleteFiles(File root) { | ... | ... |
cloud/video/src/main/java/com/libs/video/util/cache/ProxyVideoCacheManager.java
| ... | ... | @@ -20,7 +20,7 @@ public class ProxyVideoCacheManager { |
| 20 | 20 | |
| 21 | 21 | private static HttpProxyCacheServer newProxy(Context context) { |
| 22 | 22 | return new HttpProxyCacheServer.Builder(context) |
| 23 | - .maxCacheSize(512 * 1024 * 1024) // 512MB for cache | |
| 23 | + .maxCacheSize(1024 * 1024 * 1024) // 512MB for cache | |
| 24 | 24 | //缓存路径,不设置默认在sd_card/Android/data/[app_package_name]/cache中 |
| 25 | 25 | // .cacheDirectory() |
| 26 | 26 | .build(); | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/PlayErrorException.java
| ... | ... | @@ -5,8 +5,6 @@ import android.text.TextUtils; |
| 5 | 5 | |
| 6 | 6 | import androidx.annotation.IntDef; |
| 7 | 7 | |
| 8 | -import com.cnlive.core.libs.base.util.StatusBarConfig; | |
| 9 | - | |
| 10 | 8 | import java.lang.annotation.Retention; |
| 11 | 9 | import java.lang.annotation.RetentionPolicy; |
| 12 | 10 | |
| ... | ... | @@ -19,26 +17,20 @@ public class PlayErrorException extends Exception { |
| 19 | 17 | public static final int TYPE_OUT_OF_MEMORY = 2;//内存溢出 |
| 20 | 18 | public static final int TYPE_UNEXPECTED_ERROR = 3;//未知错误 |
| 21 | 19 | public static final int TYPE_RENDERER_ERROR = 4;//渲染异常 |
| 22 | - public static final int TYPE_MediaPlayer_IOException = 5; | |
| 23 | - public static final int TYPE_MediaPlayer_IllegalArgumentException = 6; | |
| 24 | - public static final int TYPE_MediaPlayer_SecurityException = 7; | |
| 25 | - public static final int TYPE_MediaPlayer_IllegalStateException = 8; | |
| 26 | - public static final int TYPE_MediaPlayer_unknownException = 9; | |
| 27 | - public static final int TYPE_MediaPlayer_ON_ERROR = 10; | |
| 28 | - | |
| 29 | - | |
| 20 | + public static final int TYPE_IllegalArgumentException = 5; | |
| 21 | + public static final int TYPE_SecurityException = 6; | |
| 22 | + public static final int TYPE_IllegalStateException = 7; | |
| 23 | + public static final int TYPE_TIMED_OUT_ERROR = 9;//播放超时错误 | |
| 24 | + public static final int TYPE_MEDIA_UNSUPPORTED_ERROR = 10;//不支持的媒体类型 | |
| 25 | + public static final int TYPE_MEDIA_SERVER_DIED_ERROR = 11;//媒体服务器挂机(应用必须释放对象,然后开启新的实例) | |
| 26 | + public static final int TYPE_OTHER_ERROR = 12;//其他错误 | |
| 30 | 27 | private int errorType;//错误类型 |
| 31 | 28 | private String errorMsg;//错误信息 |
| 32 | 29 | |
| 33 | 30 | |
| 34 | - private MediaPlayer mediaPlayer; | |
| 35 | - private int mediaPlayer_what; | |
| 36 | - private int mediaPlayer_extra; | |
| 37 | - | |
| 38 | - | |
| 39 | 31 | @IntDef({TYPE_NETWORK_ERROR, TYPE_SOURCE_ERROR, TYPE_OUT_OF_MEMORY, TYPE_UNEXPECTED_ERROR, TYPE_RENDERER_ERROR, |
| 40 | - TYPE_MediaPlayer_IOException, TYPE_MediaPlayer_IllegalArgumentException, TYPE_MediaPlayer_SecurityException, | |
| 41 | - TYPE_MediaPlayer_IllegalStateException, TYPE_MediaPlayer_unknownException, TYPE_MediaPlayer_ON_ERROR}) | |
| 32 | + TYPE_IllegalArgumentException, TYPE_SecurityException, TYPE_IllegalStateException, | |
| 33 | + TYPE_TIMED_OUT_ERROR,TYPE_MEDIA_UNSUPPORTED_ERROR,TYPE_MEDIA_SERVER_DIED_ERROR,TYPE_OTHER_ERROR}) | |
| 42 | 34 | @Retention(RetentionPolicy.SOURCE) |
| 43 | 35 | public @interface Type { |
| 44 | 36 | } |
| ... | ... | @@ -70,27 +62,4 @@ public class PlayErrorException extends Exception { |
| 70 | 62 | this.errorMsg = errorMsg; |
| 71 | 63 | } |
| 72 | 64 | |
| 73 | - public MediaPlayer getMediaPlayer() { | |
| 74 | - return mediaPlayer; | |
| 75 | - } | |
| 76 | - | |
| 77 | - public void setMediaPlayer(MediaPlayer mediaPlayer) { | |
| 78 | - this.mediaPlayer = mediaPlayer; | |
| 79 | - } | |
| 80 | - | |
| 81 | - public int getMediaPlayer_what() { | |
| 82 | - return mediaPlayer_what; | |
| 83 | - } | |
| 84 | - | |
| 85 | - public void setMediaPlayer_what(int mediaPlayer_what) { | |
| 86 | - this.mediaPlayer_what = mediaPlayer_what; | |
| 87 | - } | |
| 88 | - | |
| 89 | - public int getMediaPlayer_extra() { | |
| 90 | - return mediaPlayer_extra; | |
| 91 | - } | |
| 92 | - | |
| 93 | - public void setMediaPlayer_extra(int mediaPlayer_extra) { | |
| 94 | - this.mediaPlayer_extra = mediaPlayer_extra; | |
| 95 | - } | |
| 96 | 65 | } | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/DebugInfoView.java
| ... | ... | @@ -13,7 +13,7 @@ import android.widget.TextView; |
| 13 | 13 | import com.libs.video.video.exoplayer.PlayErrorException; |
| 14 | 14 | import com.libs.video.video.exoplayer.controller.ControlWrapper; |
| 15 | 15 | import com.libs.video.video.exoplayer.controller.IControlComponent; |
| 16 | -import com.libs.video.video.exoplayer.play.AndroidMediaPlayerFactory; | |
| 16 | +import com.libs.video.video.exoplayer.playerCore.mediaplayer.AndroidMediaPlayerFactory; | |
| 17 | 17 | import com.libs.video.video.exoplayer.playerCore.exoplayer.ExoMediaPlayerFactory; |
| 18 | 18 | import com.libs.video.video.exoplayer.util.PlayerUtils; |
| 19 | 19 | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/MediaPlayerControl.java
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/AbstractPlayer.java
| 1 | 1 | package com.libs.video.video.exoplayer.play; |
| 2 | 2 | |
| 3 | +import android.content.Context; | |
| 3 | 4 | import android.content.res.AssetFileDescriptor; |
| 4 | 5 | import android.view.Surface; |
| 5 | 6 | import android.view.SurfaceHolder; |
| ... | ... | @@ -53,11 +54,29 @@ public abstract class AbstractPlayer { |
| 53 | 54 | */ |
| 54 | 55 | public abstract void setDataSource(String path, Map<String, String> headers); |
| 55 | 56 | |
| 57 | + | |
| 58 | + public abstract void setDataSource(String path, Map<String, String> headers, boolean isCache); | |
| 59 | + | |
| 56 | 60 | /** |
| 57 | 61 | * 用于播放raw和asset里面的视频文件 |
| 58 | 62 | */ |
| 59 | 63 | public abstract void setDataSource(AssetFileDescriptor fd); |
| 60 | 64 | |
| 65 | +// /** | |
| 66 | +// * 清除全部视频缓存 | |
| 67 | +// * | |
| 68 | +// * @param context | |
| 69 | +// */ | |
| 70 | +// public abstract void clearAllCache(Context context); | |
| 71 | +// | |
| 72 | +// /** | |
| 73 | +// * 根据url清除指定视频缓存 | |
| 74 | +// * | |
| 75 | +// * @param context | |
| 76 | +// * @param url | |
| 77 | +// */ | |
| 78 | +// public abstract void clearDefaultCache(Context context, String url); | |
| 79 | + | |
| 61 | 80 | /** |
| 62 | 81 | * 播放 |
| 63 | 82 | */ | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/CNVideoView.java
| ... | ... | @@ -128,6 +128,8 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 128 | 128 | */ |
| 129 | 129 | private int mPlayerBackgroundColor; |
| 130 | 130 | |
| 131 | + private boolean isCache;//是否边缓存边播放 | |
| 132 | + | |
| 131 | 133 | // private List<String> dataSource; |
| 132 | 134 | // private int curentPlayIndex; |
| 133 | 135 | |
| ... | ... | @@ -237,7 +239,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 237 | 239 | if (mProgressManager != null) { |
| 238 | 240 | mCurrentPosition = mProgressManager.getSavedProgress(mUrl); |
| 239 | 241 | } |
| 240 | - initPlayer(); | |
| 242 | + initPlayer(); | |
| 241 | 243 | //添加渲染视图 |
| 242 | 244 | addDisplay(); |
| 243 | 245 | startPrepare(false); |
| ... | ... | @@ -272,7 +274,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 272 | 274 | * 初始化播放器 |
| 273 | 275 | */ |
| 274 | 276 | protected void initPlayer() { |
| 275 | - if (null==mMediaPlayer){ | |
| 277 | + if (null == mMediaPlayer) { | |
| 276 | 278 | //初始化播放器 |
| 277 | 279 | mMediaPlayer = mPlayerFactory.createPlayer(getContext()); |
| 278 | 280 | } |
| ... | ... | @@ -341,7 +343,7 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 341 | 343 | mMediaPlayer.setDataSource(mAssetFileDescriptor); |
| 342 | 344 | return true; |
| 343 | 345 | } else if (!TextUtils.isEmpty(mUrl)) { |
| 344 | - mMediaPlayer.setDataSource(mUrl, mHeaders); | |
| 346 | + mMediaPlayer.setDataSource(mUrl, mHeaders, isCache); | |
| 345 | 347 | return true; |
| 346 | 348 | } |
| 347 | 349 | return false; |
| ... | ... | @@ -657,13 +659,24 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 657 | 659 | /** |
| 658 | 660 | * 设置视频地址 |
| 659 | 661 | */ |
| 660 | - public void setUrl(String url) { | |
| 662 | + public void setUrl(String url, boolean isCache) { | |
| 663 | + this.isCache = isCache; | |
| 661 | 664 | // dataSource.clear(); |
| 662 | 665 | // dataSource.add(url); |
| 663 | 666 | // curentPlayIndex = 0; |
| 664 | 667 | setUrl(url, null); |
| 665 | 668 | } |
| 666 | 669 | |
| 670 | + /** | |
| 671 | + * 设置视频地址 | |
| 672 | + */ | |
| 673 | + public void setUrl(String url) { | |
| 674 | + this.isCache = false; | |
| 675 | +// dataSource.clear(); | |
| 676 | +// dataSource.add(url); | |
| 677 | +// curentPlayIndex = 0; | |
| 678 | + setUrl(url, null); | |
| 679 | + } | |
| 667 | 680 | // public void setDataSource(List<String> url) { |
| 668 | 681 | // dataSource.clear(); |
| 669 | 682 | // dataSource.addAll(url); |
| ... | ... | @@ -944,14 +957,14 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 944 | 957 | * 设置控制器,传null表示移除控制器 |
| 945 | 958 | */ |
| 946 | 959 | public void setVideoController(@Nullable BaseVideoController mediaController) { |
| 947 | - if (null==mMediaPlayer){ | |
| 960 | + if (null == mMediaPlayer) { | |
| 948 | 961 | //初始化播放器 |
| 949 | 962 | mMediaPlayer = mPlayerFactory.createPlayer(getContext()); |
| 950 | 963 | } |
| 951 | 964 | mPlayerContainer.removeView(mVideoController); |
| 952 | 965 | mVideoController = mediaController; |
| 953 | 966 | if (mediaController != null) { |
| 954 | - mediaController.setMediaPlayer(this,mMediaPlayer); | |
| 967 | + mediaController.setMediaPlayer(this, mMediaPlayer); | |
| 955 | 968 | LayoutParams params = new LayoutParams( |
| 956 | 969 | ViewGroup.LayoutParams.MATCH_PARENT, |
| 957 | 970 | ViewGroup.LayoutParams.MATCH_PARENT); |
| ... | ... | @@ -1150,8 +1163,9 @@ public class CNVideoView<P extends AbstractPlayer> extends FrameLayout |
| 1150 | 1163 | /** |
| 1151 | 1164 | * 视频缩放类型 |
| 1152 | 1165 | */ |
| 1153 | - @IntDef({SCREEN_SCALE_DEFAULT,SCREEN_SCALE_16_9,SCREEN_SCALE_4_3,SCREEN_SCALE_MATCH_PARENT,SCREEN_SCALE_ORIGINAL,SCREEN_SCALE_CENTER_CROP}) | |
| 1166 | + @IntDef({SCREEN_SCALE_DEFAULT, SCREEN_SCALE_16_9, SCREEN_SCALE_4_3, SCREEN_SCALE_MATCH_PARENT, SCREEN_SCALE_ORIGINAL, SCREEN_SCALE_CENTER_CROP}) | |
| 1154 | 1167 | @Retention(RetentionPolicy.SOURCE) |
| 1155 | 1168 | public @interface screenScalType { |
| 1156 | 1169 | } |
| 1170 | + | |
| 1157 | 1171 | } | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/VideoViewConfig.java
| ... | ... | @@ -2,6 +2,7 @@ package com.libs.video.video.exoplayer.play; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | 4 | |
| 5 | +import com.libs.video.video.exoplayer.playerCore.mediaplayer.AndroidMediaPlayerFactory; | |
| 5 | 6 | import com.libs.video.video.exoplayer.render.RenderViewFactory; |
| 6 | 7 | import com.libs.video.video.exoplayer.render.texture.TextureRenderViewFactory; |
| 7 | 8 | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/exoplayer/ExoMediaPlayer.java
| ... | ... | @@ -31,6 +31,7 @@ import com.google.android.exoplayer2.video.VideoListener; |
| 31 | 31 | import com.libs.video.video.exoplayer.PlayErrorException; |
| 32 | 32 | import com.libs.video.video.exoplayer.play.AbstractPlayer; |
| 33 | 33 | import com.libs.video.video.exoplayer.play.VideoViewManager; |
| 34 | +import com.libs.video.video.exoplayer.util.PlayCacheUtils; | |
| 34 | 35 | |
| 35 | 36 | import java.util.Map; |
| 36 | 37 | |
| ... | ... | @@ -80,7 +81,6 @@ public class ExoMediaPlayer extends AbstractPlayer implements VideoListener, Pla |
| 80 | 81 | Clock.DEFAULT) |
| 81 | 82 | .build(); |
| 82 | 83 | setOptions(); |
| 83 | - | |
| 84 | 84 | //播放器日志 |
| 85 | 85 | if (VideoViewManager.getConfig().mIsEnableLog && mTrackSelector instanceof MappingTrackSelector) { |
| 86 | 86 | exoPlayer.addAnalyticsListener(new EventLogger((MappingTrackSelector) mTrackSelector, "ExoPlayer")); |
| ... | ... | @@ -114,10 +114,16 @@ public class ExoMediaPlayer extends AbstractPlayer implements VideoListener, Pla |
| 114 | 114 | } |
| 115 | 115 | |
| 116 | 116 | @Override |
| 117 | + public void setDataSource(String path, Map<String, String> headers, boolean isCache) { | |
| 118 | + mMediaSource = mMediaSourceHelper.getMediaSource(path, headers,isCache); | |
| 119 | + } | |
| 120 | + | |
| 121 | + @Override | |
| 117 | 122 | public void setDataSource(AssetFileDescriptor fd) { |
| 118 | 123 | //no support |
| 119 | 124 | } |
| 120 | 125 | |
| 126 | + | |
| 121 | 127 | @Override |
| 122 | 128 | public void start() { |
| 123 | 129 | if (exoPlayer == null) | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/exoplayer/ExoMediaSourceHelper.java
| ... | ... | @@ -4,6 +4,7 @@ import android.content.Context; |
| 4 | 4 | import android.net.Uri; |
| 5 | 5 | import android.text.TextUtils; |
| 6 | 6 | |
| 7 | +import com.danikula.videocache.StorageUtils; | |
| 7 | 8 | import com.google.android.exoplayer2.C; |
| 8 | 9 | import com.google.android.exoplayer2.database.ExoDatabaseProvider; |
| 9 | 10 | import com.google.android.exoplayer2.ext.rtmp.RtmpDataSourceFactory; |
| ... | ... | @@ -36,6 +37,8 @@ public final class ExoMediaSourceHelper { |
| 36 | 37 | private Context mAppContext; |
| 37 | 38 | private HttpDataSource.Factory mHttpDataSourceFactory; |
| 38 | 39 | private Cache mCache; |
| 40 | + private final int CACHE_SIZE = 1024;//缓存大小1G | |
| 41 | + public static final String CACHE_DIR = "exo-video-cache"; | |
| 39 | 42 | |
| 40 | 43 | private ExoMediaSourceHelper(Context context) { |
| 41 | 44 | mAppContext = context.getApplicationContext(); |
| ... | ... | @@ -117,11 +120,15 @@ public final class ExoMediaSourceHelper { |
| 117 | 120 | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR); |
| 118 | 121 | } |
| 119 | 122 | |
| 120 | - private Cache newCache() { | |
| 121 | - return new SimpleCache( | |
| 122 | - new File(mAppContext.getExternalCacheDir(), "exo-video-cache"),//缓存目录 | |
| 123 | - new LeastRecentlyUsedCacheEvictor(512 * 1024 * 1024),//缓存大小,默认512M,使用LRU算法实现 | |
| 124 | - new ExoDatabaseProvider(mAppContext)); | |
| 123 | + public Cache newCache() { | |
| 124 | + if (null == mCache) { | |
| 125 | + return new SimpleCache( | |
| 126 | + new File(StorageUtils.getCacheDirectoryPath(mAppContext), CACHE_DIR),//缓存目录 | |
| 127 | + new LeastRecentlyUsedCacheEvictor(CACHE_SIZE * 1024 * 1024),//缓存大小,默认512M,使用LRU算法实现 | |
| 128 | + new ExoDatabaseProvider(mAppContext)); | |
| 129 | + } else { | |
| 130 | + return mCache; | |
| 131 | + } | |
| 125 | 132 | } |
| 126 | 133 | |
| 127 | 134 | /** | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/AndroidMediaPlayer.java renamed to cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/mediaplayer/AndroidMediaPlayer.java
| 1 | -package com.libs.video.video.exoplayer.play; | |
| 1 | +package com.libs.video.video.exoplayer.playerCore.mediaplayer; | |
| 2 | 2 | |
| 3 | 3 | import android.content.Context; |
| 4 | 4 | import android.content.res.AssetFileDescriptor; |
| ... | ... | @@ -6,10 +6,16 @@ import android.media.AudioManager; |
| 6 | 6 | import android.media.MediaPlayer; |
| 7 | 7 | import android.net.Uri; |
| 8 | 8 | import android.os.Build; |
| 9 | +import android.text.TextUtils; | |
| 9 | 10 | import android.view.Surface; |
| 10 | 11 | import android.view.SurfaceHolder; |
| 11 | 12 | |
| 13 | +import com.danikula.videocache.HttpProxyCacheServer; | |
| 14 | +import com.danikula.videocache.StorageUtils; | |
| 15 | +import com.libs.video.util.cache.ProxyVideoCacheManager; | |
| 12 | 16 | import com.libs.video.video.exoplayer.PlayErrorException; |
| 17 | +import com.libs.video.video.exoplayer.play.AbstractPlayer; | |
| 18 | +import com.libs.video.video.exoplayer.util.PlayCacheUtils; | |
| 13 | 19 | |
| 14 | 20 | import java.io.IOException; |
| 15 | 21 | import java.util.Map; |
| ... | ... | @@ -48,6 +54,20 @@ public class AndroidMediaPlayer extends AbstractPlayer { |
| 48 | 54 | } |
| 49 | 55 | |
| 50 | 56 | @Override |
| 57 | + public void setDataSource(String path, Map<String, String> headers, boolean isCache) { | |
| 58 | + try { | |
| 59 | + if (isCache) { | |
| 60 | + mMediaPlayer.setDataSource(mAppContext, Uri.parse(PlayCacheUtils.getCachePath(mAppContext,path)), headers); | |
| 61 | + } else { | |
| 62 | + //不缓存 | |
| 63 | + mMediaPlayer.setDataSource(mAppContext, Uri.parse(path), headers); | |
| 64 | + } | |
| 65 | + } catch (IOException e) { | |
| 66 | + e.printStackTrace(); | |
| 67 | + } | |
| 68 | + } | |
| 69 | + | |
| 70 | + @Override | |
| 51 | 71 | public void setDataSource(AssetFileDescriptor fd) { |
| 52 | 72 | try { |
| 53 | 73 | mMediaPlayer.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength()); |
| ... | ... | @@ -56,6 +76,7 @@ public class AndroidMediaPlayer extends AbstractPlayer { |
| 56 | 76 | } |
| 57 | 77 | } |
| 58 | 78 | |
| 79 | + | |
| 59 | 80 | /** |
| 60 | 81 | * 获取当前异常 |
| 61 | 82 | * |
| ... | ... | @@ -64,15 +85,16 @@ public class AndroidMediaPlayer extends AbstractPlayer { |
| 64 | 85 | private void getException(Exception e) { |
| 65 | 86 | PlayErrorException errorException = null; |
| 66 | 87 | if (e instanceof IOException) { |
| 67 | - errorException = new PlayErrorException(PlayErrorException.TYPE_MediaPlayer_IOException, e.getMessage()); | |
| 88 | + //资源错误 | |
| 89 | + errorException = new PlayErrorException(PlayErrorException.TYPE_SOURCE_ERROR, e.getMessage()); | |
| 68 | 90 | } else if (e instanceof IllegalArgumentException) { |
| 69 | - errorException = new PlayErrorException(PlayErrorException.TYPE_MediaPlayer_IllegalArgumentException, e.getMessage()); | |
| 91 | + errorException = new PlayErrorException(PlayErrorException.TYPE_IllegalArgumentException, e.getMessage()); | |
| 70 | 92 | } else if (e instanceof SecurityException) { |
| 71 | - errorException = new PlayErrorException(PlayErrorException.TYPE_MediaPlayer_SecurityException, e.getMessage()); | |
| 93 | + errorException = new PlayErrorException(PlayErrorException.TYPE_SecurityException, e.getMessage()); | |
| 72 | 94 | } else if (e instanceof IllegalStateException) { |
| 73 | - errorException = new PlayErrorException(PlayErrorException.TYPE_MediaPlayer_IllegalStateException, e.getMessage()); | |
| 95 | + errorException = new PlayErrorException(PlayErrorException.TYPE_IllegalStateException, e.getMessage()); | |
| 74 | 96 | } else { |
| 75 | - errorException = new PlayErrorException(PlayErrorException.TYPE_MediaPlayer_unknownException, e.getMessage()); | |
| 97 | + errorException = new PlayErrorException(PlayErrorException.TYPE_UNEXPECTED_ERROR, e.getMessage()); | |
| 76 | 98 | } |
| 77 | 99 | mPlayerEventListener.onError(errorException); |
| 78 | 100 | } |
| ... | ... | @@ -132,7 +154,7 @@ public class AndroidMediaPlayer extends AbstractPlayer { |
| 132 | 154 | try { |
| 133 | 155 | mMediaPlayer.seekTo((int) time); |
| 134 | 156 | } catch (IllegalStateException e) { |
| 135 | - mPlayerEventListener.onError(new PlayErrorException(PlayErrorException.TYPE_MediaPlayer_IllegalStateException, e.getMessage())); | |
| 157 | + mPlayerEventListener.onError(new PlayErrorException(PlayErrorException.TYPE_IllegalStateException, e.getMessage())); | |
| 136 | 158 | |
| 137 | 159 | } |
| 138 | 160 | } |
| ... | ... | @@ -226,10 +248,28 @@ public class AndroidMediaPlayer extends AbstractPlayer { |
| 226 | 248 | @Override |
| 227 | 249 | public boolean onError(MediaPlayer mp, int what, int extra) { |
| 228 | 250 | PlayErrorException errorException = new PlayErrorException(); |
| 229 | - errorException.setErrorType(PlayErrorException.TYPE_MediaPlayer_ON_ERROR); | |
| 230 | - errorException.setMediaPlayer(mp); | |
| 231 | - errorException.setMediaPlayer_what(what); | |
| 232 | - errorException.setMediaPlayer_extra(extra); | |
| 251 | + switch (what) { | |
| 252 | + //播放超时错误 | |
| 253 | + case MediaPlayer.MEDIA_ERROR_TIMED_OUT: | |
| 254 | + errorException.setErrorType(PlayErrorException.TYPE_TIMED_OUT_ERROR); | |
| 255 | + errorException.setErrorMsg("播放超时错误"); | |
| 256 | + break; | |
| 257 | + //不支持的媒体类型 | |
| 258 | + case MediaPlayer.MEDIA_ERROR_UNSUPPORTED: | |
| 259 | + errorException.setErrorType(PlayErrorException.TYPE_MEDIA_UNSUPPORTED_ERROR); | |
| 260 | + errorException.setErrorMsg("不支持的媒体类型"); | |
| 261 | + break; | |
| 262 | + //媒体服务器挂机(应用必须释放对象,然后开启新的实例) | |
| 263 | + case MediaPlayer.MEDIA_ERROR_SERVER_DIED: | |
| 264 | + errorException.setErrorType(PlayErrorException.TYPE_MEDIA_SERVER_DIED_ERROR); | |
| 265 | + errorException.setErrorMsg("媒体服务器挂机(应用必须释放对象,然后开启新的实例)"); | |
| 266 | + break; | |
| 267 | + default: | |
| 268 | + errorException.setErrorType(PlayErrorException.TYPE_OTHER_ERROR); | |
| 269 | + errorException.setErrorMsg("其他错误:" + what); | |
| 270 | + break; | |
| 271 | + } | |
| 272 | + | |
| 233 | 273 | mPlayerEventListener.onError(errorException); |
| 234 | 274 | return true; |
| 235 | 275 | } | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/AndroidMediaPlayerFactory.java renamed to cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/mediaplayer/AndroidMediaPlayerFactory.java
| 1 | -package com.libs.video.video.exoplayer.play; | |
| 1 | +package com.libs.video.video.exoplayer.playerCore.mediaplayer; | |
| 2 | 2 | |
| 3 | 3 | import android.content.Context; |
| 4 | 4 | |
| 5 | +import com.libs.video.video.exoplayer.play.PlayerFactory; | |
| 6 | + | |
| 5 | 7 | public class AndroidMediaPlayerFactory extends PlayerFactory<AndroidMediaPlayer> { |
| 6 | 8 | |
| 7 | 9 | public static AndroidMediaPlayerFactory create() { | ... | ... |
cloud/video/src/main/java/com/libs/video/video/exoplayer/util/PlayCacheUtils.java
0 → 100644
| 1 | +package com.libs.video.video.exoplayer.util; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.text.TextUtils; | |
| 5 | + | |
| 6 | +import com.danikula.videocache.HttpProxyCacheServer; | |
| 7 | +import com.danikula.videocache.StorageUtils; | |
| 8 | +import com.libs.video.util.cache.ProxyVideoCacheManager; | |
| 9 | +import com.libs.video.video.exoplayer.playerCore.exoplayer.ExoMediaPlayerFactory; | |
| 10 | +import com.libs.video.video.exoplayer.playerCore.exoplayer.ExoMediaSourceHelper; | |
| 11 | +import com.libs.video.video.exoplayer.playerCore.mediaplayer.AndroidMediaPlayerFactory; | |
| 12 | + | |
| 13 | +import java.io.File; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 播放缓存工具 | |
| 17 | + */ | |
| 18 | +public class PlayCacheUtils { | |
| 19 | + public static String getCachePath(Context mAppContext, String path) { | |
| 20 | + String result = ""; | |
| 21 | + if (null == mAppContext || TextUtils.isEmpty(path)) { | |
| 22 | + return result; | |
| 23 | + } | |
| 24 | + if (path.contains("m3u8")) { | |
| 25 | + result = path; | |
| 26 | + } else if (null != mAppContext && !TextUtils.isDigitsOnly(path) && !path.contains(StorageUtils.getCacheDirectoryPath(mAppContext))) { | |
| 27 | + HttpProxyCacheServer cacheServer = ProxyVideoCacheManager.getProxy(mAppContext); | |
| 28 | + if (!cacheServer.isCached(path)) { | |
| 29 | + String proxyUrl = cacheServer.getProxyUrl(path); | |
| 30 | + result = proxyUrl; | |
| 31 | + } | |
| 32 | + } | |
| 33 | + return result; | |
| 34 | + } | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 目前exoplayer是全部删除 | |
| 38 | + * | |
| 39 | + * @param context | |
| 40 | + * @param url | |
| 41 | + */ | |
| 42 | + public void clearDefaultCache(Context context, String url) { | |
| 43 | + //获取当前播放核心 | |
| 44 | + Object object = PlayerFactoryUtils.getCurrentPlayerFactory(); | |
| 45 | + if (null != object) { | |
| 46 | + if (object instanceof ExoMediaPlayerFactory) { | |
| 47 | + File file = new File(StorageUtils.getCacheDirectoryPath(context), ExoMediaSourceHelper.CACHE_DIR);//缓存目录 | |
| 48 | + if (null == file) { | |
| 49 | + return; | |
| 50 | + } | |
| 51 | + if (file.exists()) { | |
| 52 | + deleteFile(file); | |
| 53 | + } | |
| 54 | + } else if (object instanceof AndroidMediaPlayerFactory) { | |
| 55 | + ProxyVideoCacheManager.clearDefaultCache(context, url); | |
| 56 | + } | |
| 57 | + } | |
| 58 | + } | |
| 59 | + | |
| 60 | + public static void clearAllCache(Context context) { | |
| 61 | + //获取当前播放核心 | |
| 62 | +// Object object = PlayerFactoryUtils.getCurrentPlayerFactory(); | |
| 63 | +// if (null != object) { | |
| 64 | +// if (object instanceof ExoMediaPlayerFactory) { | |
| 65 | + File file = new File(StorageUtils.getCacheDirectoryPath(context), ExoMediaSourceHelper.CACHE_DIR);//缓存目录 | |
| 66 | + if (null == file) { | |
| 67 | + return; | |
| 68 | + } | |
| 69 | + if (file.exists()) { | |
| 70 | + deleteFile(file); | |
| 71 | + } | |
| 72 | +// } else if (object instanceof AndroidMediaPlayerFactory) { | |
| 73 | + ProxyVideoCacheManager.clearAllCache(context); | |
| 74 | +// } | |
| 75 | +// } | |
| 76 | + | |
| 77 | + | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * 删除文件 | |
| 82 | + * | |
| 83 | + * @param file | |
| 84 | + */ | |
| 85 | + private static void deleteFile(File file) { | |
| 86 | + if (file.exists()) { // 判断文件是否存在 | |
| 87 | + if (file.isFile()) { // 判断是否是文件 | |
| 88 | + file.delete(); // delete()方法 你应该知道 是删除的意思; | |
| 89 | + } else if (file.isDirectory()) { // 否则如果它是一个目录 | |
| 90 | + File files[] = file.listFiles(); // 声明目录下所有的文件 files[]; | |
| 91 | + for (File file1 : files) { // 遍历目录下所有的文件 | |
| 92 | + deleteFile(file1); // 把每个文件 用这个方法进行迭代 | |
| 93 | + } | |
| 94 | + } | |
| 95 | + file.delete(); | |
| 96 | + } else { | |
| 97 | + | |
| 98 | + } | |
| 99 | + } | |
| 100 | + | |
| 101 | +} | ... | ... |