Commit af53ca93dcfc093e9d9dd06573a2909d5f078e2e

Authored by 韩亚云
2 parents cd0d79d4 73f4bf09

Merge branch 'master' of bj.gitlab.cnlive.com:cnlive-team/newModuleStrike

Showing 25 changed files with 360 additions and 151 deletions
app/strike/src/main/java/com/cnlive/strike/demo/activity/tiktok/TikTokRecycleActivity.java
... ... @@ -13,6 +13,7 @@ import com.cnlive.strike.demo.util.DataUtil;
13 13 import com.libs.video.util.cache.PreloadManager;
14 14 import com.libs.video.video.exoplayer.controller.TikTokController;
15 15 import com.libs.video.video.exoplayer.play.CNVideoView;
  16 +import com.libs.video.video.exoplayer.render.TikTokRenderViewFactory;
16 17 import com.libs.video.video.exoplayer.util.L;
17 18 import com.libs.video.video.exoplayer.util.PlayerUtils;
18 19  
... ... @@ -53,6 +54,8 @@ public class TikTokRecycleActivity extends BaseActivity {
53 54 @Override
54 55 protected void initView() {
55 56 mVideoView = new CNVideoView(this);
  57 + //以下只能二选一,看你的需求
  58 +// mVideoView.setRenderViewFactory(TikTokRenderViewFactory.create());
56 59 mVideoView.setScreenScaleType(CNVideoView.SCREEN_SCALE_CENTER_CROP);
57 60 mVideoView.setLooping(true);
58 61 mController = new TikTokController(this);
... ...
app/strike/src/main/java/com/cnlive/strike/demo/activity/tiktok/TikTokVerticalViewPagerActivity.java
... ... @@ -14,6 +14,7 @@ import com.libs.video.util.cache.PreloadManager;
14 14 import com.libs.video.util.cache.ProxyVideoCacheManager;
15 15 import com.libs.video.video.exoplayer.controller.TikTokController;
16 16 import com.libs.video.video.exoplayer.play.CNVideoView;
  17 +import com.libs.video.video.exoplayer.render.TikTokRenderViewFactory;
17 18 import com.libs.video.video.exoplayer.util.L;
18 19 import com.libs.video.video.exoplayer.util.PlayerUtils;
19 20 import com.libs.video.video.exoplayer.widget.VerticalViewPager;
... ... @@ -84,6 +85,8 @@ public class TikTokVerticalViewPagerActivity extends BaseActivity {
84 85 private void initVideoView() {
85 86 mVideoView = new CNVideoView(this);
86 87 mVideoView.setLooping(true);
  88 + //以下只能二选一,看你的需求
  89 +// mVideoView.setRenderViewFactory(TikTokRenderViewFactory.create());
87 90 mVideoView.setScreenScaleType(CNVideoView.SCREEN_SCALE_CENTER_CROP);
88 91 mController = new TikTokController(this);
89 92 mVideoView.setVideoController(mController);
... ...
app/strike/src/main/java/com/cnlive/strike/demo/activity/tiktok/TikTokViewPager2Activity.java
... ... @@ -13,6 +13,7 @@ import com.libs.video.util.cache.PreloadManager;
13 13 import com.libs.video.util.cache.ProxyVideoCacheManager;
14 14 import com.libs.video.video.exoplayer.controller.TikTokController;
15 15 import com.libs.video.video.exoplayer.play.CNVideoView;
  16 +import com.libs.video.video.exoplayer.render.TikTokRenderViewFactory;
16 17 import com.libs.video.video.exoplayer.util.L;
17 18 import com.libs.video.video.exoplayer.util.PlayerUtils;
18 19 import com.libs.video.video.exoplayer.widget.VerticalViewPager;
... ... @@ -84,6 +85,8 @@ public class TikTokViewPager2Activity extends BaseActivity {
84 85 private void initVideoView() {
85 86 mVideoView = new CNVideoView(this);
86 87 mVideoView.setLooping(true);
  88 + //以下只能二选一,看你的需求
  89 +// mVideoView.setRenderViewFactory(TikTokRenderViewFactory.create());
87 90 mVideoView.setScreenScaleType(CNVideoView.SCREEN_SCALE_CENTER_CROP);
88 91  
89 92 mController = new TikTokController(this);
... ...
cloud/video/build.gradle
... ... @@ -9,6 +9,7 @@ dependencies {
9 9 api fileTree(include: ['*.jar'], dir: 'libs')
10 10 // api project(':lib_cnutil')
11 11 // api project(':lib_cnchat_tc')
  12 + //3.2.5
12 13 //友盟
13 14 implementation "com.umeng.umsdk:analytics:8.0.0"
14 15 implementation "com.umeng.umsdk:common:2.0.0"
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/DefaultCompleteView.java
... ... @@ -104,14 +104,12 @@ public class DefaultCompleteView extends FrameLayout implements IControlComponen
104 104 if (activity != null && mControlWrapper.hasCutout()) {
105 105 int orientation = activity.getRequestedOrientation();
106 106 int cutoutHeight = mControlWrapper.getCutoutHeight();
  107 + LayoutParams sflp = (LayoutParams) mStopFullscreen.getLayoutParams();
107 108 if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
108   - LayoutParams sflp = (LayoutParams) mStopFullscreen.getLayoutParams();
109 109 sflp.setMargins(0, 0, 0, 0);
110 110 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
111   - LayoutParams sflp = (LayoutParams) mStopFullscreen.getLayoutParams();
112 111 sflp.setMargins(cutoutHeight, 0, 0, 0);
113 112 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
114   - LayoutParams sflp = (LayoutParams) mStopFullscreen.getLayoutParams();
115 113 sflp.setMargins(0, 0, 0, 0);
116 114 }
117 115 }
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/DefaultTitleView.java
... ... @@ -35,7 +35,7 @@ public class DefaultTitleView extends FrameLayout implements IControlComponent {
35 35 private ControlWrapper mControlWrapper;
36 36  
37 37 private LinearLayout mTitleContainer;
38   - private MarqueeTextView mTitle;
  38 + private TextView mTitle;
39 39 private TextView mSysTime;//系统当前时间
40 40  
41 41 private BatteryReceiver mBatteryReceiver;
... ... @@ -121,8 +121,8 @@ public class DefaultTitleView extends FrameLayout implements IControlComponent {
121 121 }
122 122 } else {
123 123 if (getVisibility() == VISIBLE) {
  124 + setVisibility(GONE);
124 125 if (anim != null) {
125   - setVisibility(GONE);
126 126 startAnimation(anim);
127 127 }
128 128 }
... ... @@ -150,10 +150,10 @@ public class DefaultTitleView extends FrameLayout implements IControlComponent {
150 150 setVisibility(VISIBLE);
151 151 mSysTime.setText(PlayerUtils.getCurrentSystemTime());
152 152 }
153   - mTitle.setNeedFocus(true);
  153 + mTitle.setSelected(true);
154 154 } else {
155 155 setVisibility(GONE);
156   - mTitle.setNeedFocus(false);
  156 + mTitle.setSelected(false);
157 157 }
158 158  
159 159 Activity activity = PlayerUtils.scanForActivity(getContext());
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/component/MarqueeTextView.java deleted 100644 → 0
1   -package com.libs.video.video.exoplayer.component;
2   -
3   -import android.content.Context;
4   -import android.util.AttributeSet;
5   -import android.widget.TextView;
6   -
7   -/**
8   - * 实现跑马灯效果的TextView
9   - */
10   -public class MarqueeTextView extends TextView {
11   - private boolean mNeedFocus;
12   - public MarqueeTextView(Context context) {
13   - super(context);
14   - }
15   - public MarqueeTextView(Context context, AttributeSet attrs) {
16   - super(context, attrs);
17   - }
18   - public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
19   - super(context, attrs, defStyleAttr);
20   - }
21   - //返回textview是否处在选中的状态
22   - //而只有选中的textview才能够实现跑马灯效果
23   - @Override
24   - public boolean isFocused() {
25   - if (mNeedFocus) {
26   - return false;
27   - }
28   - return super.isFocused();
29   - }
30   -
31   - public void setNeedFocus(boolean needFocus) {
32   - mNeedFocus = needFocus;
33   - }
34   -}
35 0 \ No newline at end of file
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/BaseVideoController.java
... ... @@ -30,6 +30,14 @@ import androidx.annotation.Nullable;
30 30  
31 31 /**
32 32 * 控制器基类
  33 + * 此类集成各种事件的处理逻辑,包括
  34 + * 1.播放器状态改变: {@link #handlePlayerStateChanged(int)}
  35 + * 2.播放状态改变: {@link #handlePlayStateChanged(int)}
  36 + * 3.控制视图的显示和隐藏: {@link #handleVisibilityChanged(boolean, Animation)}
  37 + * 4.播放进度改变: {@link #handleSetProgress(int, int)}
  38 + * 5.锁定状态改变: {@link #handleLockStateChanged(boolean)}
  39 + * 6.设备方向监听: {@link #onOrientationChanged(int)}
  40 + * Created by dueeeke on 2017/4/12.
33 41 */
34 42 public abstract class BaseVideoController extends FrameLayout
35 43 implements IVideoController,
... ... @@ -253,7 +261,7 @@ public abstract class BaseVideoController extends FrameLayout
253 261 /**
254 262 * 隐藏播放视图Runnable
255 263 */
256   - public final Runnable mFadeOut = new Runnable() {
  264 + protected final Runnable mFadeOut = new Runnable() {
257 265 @Override
258 266 public void run() {
259 267 hide();
... ... @@ -294,7 +302,7 @@ public abstract class BaseVideoController extends FrameLayout
294 302 /**
295 303 * 刷新进度Runnable
296 304 */
297   - private Runnable mShowProgress = new Runnable() {
  305 + protected Runnable mShowProgress = new Runnable() {
298 306 @Override
299 307 public void run() {
300 308 int pos = setProgress();
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/ControlWrapper.java
... ... @@ -112,6 +112,10 @@ public class ControlWrapper implements MediaPlayerControl, IVideoController {
112 112 }
113 113  
114 114 @Override
  115 + public float getSpeed() {
  116 + return mPlayerControl.getSpeed();
  117 + }
  118 + @Override
115 119 public long getTcpSpeed() {
116 120 return mPlayerControl.getTcpSpeed();
117 121 }
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/GestureVideoController.java
... ... @@ -33,8 +33,7 @@ public abstract class GestureVideoController extends BaseVideoController impleme
33 33 private boolean mIsGestureEnabled = true;
34 34 private int mStreamVolume;
35 35 private float mBrightness;
36   - private int mPosition;
37   - private boolean mNeedSeek;
  36 + private int mSeekPosition;
38 37 private boolean mFirstTouch;
39 38 private boolean mChangePosition;
40 39 private boolean mChangeBrightness;
... ... @@ -228,8 +227,7 @@ public abstract class GestureVideoController extends BaseVideoController impleme
228 227 ((IGestureComponent) component).onPositionChange(position, currentPosition, duration);
229 228 }
230 229 }
231   - mPosition = position;
232   - mNeedSeek = true;
  230 + mSeekPosition = position;
233 231 }
234 232  
235 233 protected void slideToChangeBrightness(float deltaY) {
... ... @@ -274,22 +272,35 @@ public abstract class GestureVideoController extends BaseVideoController impleme
274 272  
275 273 @Override
276 274 public boolean onTouchEvent(MotionEvent event) {
277   - boolean detectedUp = event.getAction() == MotionEvent.ACTION_UP;
278   - if (!mGestureDetector.onTouchEvent(event) && detectedUp) {
279   - for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) {
280   - IControlComponent component = next.getKey();
281   - if (component instanceof IGestureComponent) {
282   - ((IGestureComponent) component).onStopSlide();
283   - }
284   - }
285   - if (mNeedSeek) {
286   - mControlWrapper.seekTo(mPosition);
287   - mNeedSeek = false;
  275 + //滑动结束时事件处理
  276 + if (!mGestureDetector.onTouchEvent(event)) {
  277 + int action = event.getAction();
  278 + switch (action) {
  279 + case MotionEvent.ACTION_UP:
  280 + stopSlide();
  281 + if (mSeekPosition > 0) {
  282 + mControlWrapper.seekTo(mSeekPosition);
  283 + mSeekPosition = 0;
  284 + }
  285 + break;
  286 + case MotionEvent.ACTION_CANCEL:
  287 + stopSlide();
  288 + mSeekPosition = 0;
  289 + break;
288 290 }
289 291 }
290 292 return super.onTouchEvent(event);
291 293 }
292 294  
  295 + private void stopSlide() {
  296 + for (Map.Entry<IControlComponent, Boolean> next : mControlComponents.entrySet()) {
  297 + IControlComponent component = next.getKey();
  298 + if (component instanceof IGestureComponent) {
  299 + ((IGestureComponent) component).onStopSlide();
  300 + }
  301 + }
  302 + }
  303 +
293 304 @Override
294 305 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
295 306 return false;
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/MediaPlayerControl.java
... ... @@ -38,6 +38,8 @@ public interface MediaPlayerControl {
38 38  
39 39 void setSpeed(float speed);
40 40  
  41 + float getSpeed();
  42 +
41 43 long getTcpSpeed();
42 44  
43 45 void replay(boolean resetPosition);
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/controller/StandardVideoController.java
... ... @@ -32,6 +32,8 @@ import androidx.annotation.Nullable;
32 32  
33 33 /**
34 34 * 直播/点播控制器
  35 + * 注意:此控制器仅做一个参考,如果想定制ui,你可以直接继承GestureVideoController或者BaseVideoController实现
  36 + * 你自己的控制器
35 37 */
36 38  
37 39 public class StandardVideoController extends GestureVideoController implements View.OnClickListener, AbstractPlayer.PlayerEventListener {
... ... @@ -207,7 +209,7 @@ public class StandardVideoController extends GestureVideoController implements V
207 209  
208 210 @Override
209 211 public void onError(PlayErrorException playErrorException) {
210   - Log.e("测试", "onError: " );
  212 + Log.e("测试", "onError: ");
211 213 }
212 214  
213 215 @Override
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/AbstractPlayer.java
... ... @@ -163,6 +163,11 @@ public abstract class AbstractPlayer {
163 163 public abstract void setSpeed(float speed);
164 164  
165 165 /**
  166 + * 获取播放速度
  167 + */
  168 + public abstract float getSpeed();
  169 +
  170 + /**
166 171 * 获取当前缓冲的网速
167 172 */
168 173 public abstract long getTcpSpeed();
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/CNVideoView.java
... ... @@ -656,6 +656,14 @@ public class CNVideoView&lt;P extends AbstractPlayer&gt; extends FrameLayout
656 656 }
657 657 }
658 658  
  659 + @Override
  660 + public float getSpeed() {
  661 + if (isInPlaybackState()) {
  662 + return mMediaPlayer.getSpeed();
  663 + }
  664 + return 1f;
  665 + }
  666 +
659 667 /**
660 668 * 设置视频地址
661 669 */
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/PlayerFactory.java
... ... @@ -3,9 +3,10 @@ package com.libs.video.video.exoplayer.play;
3 3 import android.content.Context;
4 4  
5 5 /**
6   - * 创建播放器核心
7   - *
8   - * @param <P>
  6 + * 此接口使用方法:
  7 + * 1.继承{@link AbstractPlayer}扩展自己的播放器。
  8 + * 2.继承此接口并实现${@link #createPlayer(Context)},返回步骤1中的播放器。
  9 + * 可参照{@link com.libs.video.video.exoplayer.playerCore.mediaplayer.AndroidMediaPlayer}和{@link com.libs.video.video.exoplayer.playerCore.mediaplayer.AndroidMediaPlayerFactory}的实现。
9 10 */
10 11 public abstract class PlayerFactory<P extends AbstractPlayer> {
11 12  
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/ProgressManager.java
1 1 package com.libs.video.video.exoplayer.play;
2 2  
3 3 /**
4   - * 进度管理
  4 + * 播放进度管理器,继承此接口实现自己的进度管理器。
5 5 */
6 6 public abstract class ProgressManager {
7 7  
  8 + /**
  9 + * 此方法用于实现保存进度的逻辑
  10 + * @param url 播放地址
  11 + * @param progress 播放进度
  12 + */
8 13 public abstract void saveProgress(String url, long progress);
9 14  
  15 + /**
  16 + * 此方法用于实现获取保存的进度的逻辑
  17 + * @param url 播放地址
  18 + * @return 保存的播放进度
  19 + */
10 20 public abstract long getSavedProgress(String url);
11 21  
12 22 }
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/play/VideoViewConfig.java
... ... @@ -23,8 +23,6 @@ public class VideoViewConfig {
23 23  
24 24 public final boolean mEnableAudioFocus;
25 25  
26   - public final boolean mEnableParallelPlay;
27   -
28 26 public final boolean mIsEnableLog;
29 27  
30 28 public final ProgressManager mProgressManager;
... ... @@ -43,7 +41,6 @@ public class VideoViewConfig {
43 41 mPlayOnMobileNetwork = builder.mPlayOnMobileNetwork;
44 42 mEnableAudioFocus = builder.mEnableAudioFocus;
45 43 mProgressManager = builder.mProgressManager;
46   - mEnableParallelPlay = builder.mEnableParallelPlay;
47 44 mScreenScaleType = builder.mScreenScaleType;
48 45 if (builder.mPlayerFactory == null) {
49 46 //默认为AndroidMediaPlayer
... ... @@ -67,7 +64,6 @@ public class VideoViewConfig {
67 64 private boolean mPlayOnMobileNetwork;
68 65 private boolean mEnableOrientation;
69 66 private boolean mEnableAudioFocus = true;
70   - private boolean mEnableParallelPlay;
71 67 private ProgressManager mProgressManager;
72 68 private PlayerFactory mPlayerFactory;
73 69 private int mScreenScaleType;
... ... @@ -107,16 +103,6 @@ public class VideoViewConfig {
107 103 }
108 104  
109 105 /**
110   - * 支持多开
111   - * @deprecated 此api已经无效,你需要自己去控制同时只有一个VideoView在播放的效果
112   - */
113   - @Deprecated
114   - public Builder setEnableParallelPlay(boolean enableParallelPlay) {
115   - mEnableParallelPlay = enableParallelPlay;
116   - return this;
117   - }
118   -
119   - /**
120 106 * 是否打印日志
121 107 */
122 108 public Builder setLogEnabled(boolean enableLog) {
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/exoplayer/ExoMediaPlayer.java
... ... @@ -332,6 +332,13 @@ public class ExoMediaPlayer extends AbstractPlayer implements VideoListener, Pla
332 332 }
333 333 }
334 334  
  335 + @Override
  336 + public float getSpeed() {
  337 + if (mSpeedPlaybackParameters != null) {
  338 + return mSpeedPlaybackParameters.speed;
  339 + }
  340 + return 1f;
  341 + }
335 342 /**
336 343 * 不支持
337 344 *
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/mediaplayer/AndroidMediaPlayer.java
... ... @@ -20,6 +20,11 @@ import com.libs.video.video.exoplayer.util.PlayCacheUtils;
20 20 import java.io.IOException;
21 21 import java.util.Map;
22 22  
  23 +import static com.libs.video.video.exoplayer.PlayErrorException.TYPE_UNEXPECTED_ERROR;
  24 +
  25 +/**
  26 + * 封装系统的MediaPlayer,不推荐,系统的MediaPlayer兼容性较差,建议使用ExoPlayer
  27 + */
23 28 public class AndroidMediaPlayer extends AbstractPlayer {
24 29  
25 30 protected MediaPlayer mMediaPlayer;
... ... @@ -57,7 +62,7 @@ public class AndroidMediaPlayer extends AbstractPlayer {
57 62 public void setDataSource(String path, Map<String, String> headers, boolean isCache) {
58 63 try {
59 64 if (isCache) {
60   - mMediaPlayer.setDataSource(mAppContext, Uri.parse(PlayCacheUtils.getCachePath(mAppContext,path)), headers);
  65 + mMediaPlayer.setDataSource(mAppContext, Uri.parse(PlayCacheUtils.getCachePath(mAppContext, path)), headers);
61 66 } else {
62 67 //不缓存
63 68 mMediaPlayer.setDataSource(mAppContext, Uri.parse(path), headers);
... ... @@ -94,7 +99,7 @@ public class AndroidMediaPlayer extends AbstractPlayer {
94 99 } else if (e instanceof IllegalStateException) {
95 100 errorException = new PlayErrorException(PlayErrorException.TYPE_IllegalStateException, e.getMessage());
96 101 } else {
97   - errorException = new PlayErrorException(PlayErrorException.TYPE_UNEXPECTED_ERROR, e.getMessage());
  102 + errorException = new PlayErrorException(TYPE_UNEXPECTED_ERROR, e.getMessage());
98 103 }
99 104 mPlayerEventListener.onError(errorException);
100 105 }
... ... @@ -239,6 +244,19 @@ public class AndroidMediaPlayer extends AbstractPlayer {
239 244 }
240 245  
241 246 @Override
  247 + public float getSpeed() {
  248 + // only support above Android M
  249 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  250 + try {
  251 + return mMediaPlayer.getPlaybackParams().getSpeed();
  252 + } catch (Exception e) {
  253 + mPlayerEventListener.onError(new PlayErrorException(TYPE_UNEXPECTED_ERROR,e.getMessage()));
  254 + }
  255 + }
  256 + return 1f;
  257 + }
  258 +
  259 + @Override
242 260 public long getTcpSpeed() {
243 261 // no support
244 262 return 0;
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/playerCore/mediaplayer/AndroidMediaPlayerFactory.java
... ... @@ -3,7 +3,9 @@ package com.libs.video.video.exoplayer.playerCore.mediaplayer;
3 3 import android.content.Context;
4 4  
5 5 import com.libs.video.video.exoplayer.play.PlayerFactory;
6   -
  6 +/**
  7 + * 创建{@link AndroidMediaPlayer}的工厂类,不推荐,系统的MediaPlayer兼容性较差,建议使用ExoPlayer
  8 + */
7 9 public class AndroidMediaPlayerFactory extends PlayerFactory<AndroidMediaPlayer> {
8 10  
9 11 public static AndroidMediaPlayerFactory create() {
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/render/MeasureHelper.java
... ... @@ -9,7 +9,6 @@ import com.libs.video.video.exoplayer.play.CNVideoView;
9 9 * 测量工具
10 10 */
11 11 public class MeasureHelper {
12   -
13 12 private int mVideoWidth;
14 13  
15 14 private int mVideoHeight;
... ... @@ -22,7 +21,6 @@ public class MeasureHelper {
22 21 mVideoRotationDegree = videoRotationDegree;
23 22 }
24 23  
25   -
26 24 public void setVideoSize(int width, int height) {
27 25 mVideoWidth = width;
28 26 mVideoHeight = height;
... ... @@ -32,6 +30,9 @@ public class MeasureHelper {
32 30 mCurrentScreenScale = screenScale;
33 31 }
34 32  
  33 + /**
  34 + * 注意:VideoView的宽高一定要定死,否者以下算法不成立
  35 + */
35 36 public int[] doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
36 37 if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) { // 软解码时处理旋转信息,交换宽高
37 38 widthMeasureSpec = widthMeasureSpec + heightMeasureSpec;
... ... @@ -39,11 +40,23 @@ public class MeasureHelper {
39 40 widthMeasureSpec = widthMeasureSpec - heightMeasureSpec;
40 41 }
41 42  
42   - int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
43   - int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
  43 + int width = View.MeasureSpec.getSize(widthMeasureSpec);
  44 + int height = View.MeasureSpec.getSize(heightMeasureSpec);
  45 +
  46 + if (mVideoHeight == 0 || mVideoWidth == 0) {
  47 + return new int[]{width, height};
  48 + }
44 49  
45 50 //如果设置了比例
46 51 switch (mCurrentScreenScale) {
  52 + case CNVideoView.SCREEN_SCALE_DEFAULT:
  53 + default:
  54 + if (mVideoWidth * height < width * mVideoHeight) {
  55 + width = height * mVideoWidth / mVideoHeight;
  56 + } else if (mVideoWidth * height > width * mVideoHeight) {
  57 + height = width * mVideoHeight / mVideoWidth;
  58 + }
  59 + break;
47 60 case CNVideoView.SCREEN_SCALE_ORIGINAL:
48 61 width = mVideoWidth;
49 62 height = mVideoHeight;
... ... @@ -61,80 +74,146 @@ public class MeasureHelper {
61 74 } else {
62 75 width = height / 3 * 4;
63 76 }
64   -// Log.d("@@@@", "onMeasure 4:3 : width" + width + " height:" + height);
65 77 break;
66 78 case CNVideoView.SCREEN_SCALE_MATCH_PARENT:
67 79 width = widthMeasureSpec;
68 80 height = heightMeasureSpec;
69 81 break;
70 82 case CNVideoView.SCREEN_SCALE_CENTER_CROP:
71   - if (mVideoWidth > 0 && mVideoHeight > 0) {
72   - if (mVideoWidth * height > width * mVideoHeight) {
73   - width = height * mVideoWidth / mVideoHeight;
74   - } else {
75   - height = width * mVideoHeight / mVideoWidth;
76   - }
77   - }
78   - break;
79   - case CNVideoView.SCREEN_SCALE_DEFAULT:
80   - default:
81   - if (mVideoWidth > 0 && mVideoHeight > 0) {
82   -
83   - int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
84   - int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
85   - int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
86   - int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
87   -
88   - if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
89   - // the size is fixed
90   - width = widthSpecSize;
91   - height = heightSpecSize;
92   -
93   - // for compatibility, we adjust size based on aspect ratio
94   - if (mVideoWidth * height < width * mVideoHeight) {
95   - //Log.i("@@@", "image too wide, correcting");
96   - width = height * mVideoWidth / mVideoHeight;
97   - } else if (mVideoWidth * height > width * mVideoHeight) {
98   - //Log.i("@@@", "image too tall, correcting");
99   - height = width * mVideoHeight / mVideoWidth;
100   - }
101   - } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
102   - // only the width is fixed, adjust the height to match aspect ratio if possible
103   - width = widthSpecSize;
104   - height = width * mVideoHeight / mVideoWidth;
105   - if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
106   - // couldn't match aspect ratio within the constraints
107   - height = heightSpecSize;
108   - }
109   - } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
110   - // only the height is fixed, adjust the width to match aspect ratio if possible
111   - height = heightSpecSize;
112   - width = height * mVideoWidth / mVideoHeight;
113   - if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
114   - // couldn't match aspect ratio within the constraints
115   - width = widthSpecSize;
116   - }
117   - } else {
118   - // neither the width nor the height are fixed, try to use actual video size
119   - width = mVideoWidth;
120   - height = mVideoHeight;
121   - if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
122   - // too tall, decrease both width and height
123   - height = heightSpecSize;
124   - width = height * mVideoWidth / mVideoHeight;
125   - }
126   - if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
127   - // too wide, decrease both width and height
128   - width = widthSpecSize;
129   - height = width * mVideoHeight / mVideoWidth;
130   - }
131   - }
  83 + if (mVideoWidth * height > width * mVideoHeight) {
  84 + width = height * mVideoWidth / mVideoHeight;
132 85 } else {
133   - // no size yet, just adopt the given spec sizes
  86 + height = width * mVideoHeight / mVideoWidth;
134 87 }
135 88 break;
136 89 }
137   -
138 90 return new int[]{width, height};
139 91 }
  92 +// private int mVideoWidth;
  93 +//
  94 +// private int mVideoHeight;
  95 +//
  96 +// private int mCurrentScreenScale;
  97 +//
  98 +// private int mVideoRotationDegree;
  99 +//
  100 +// public void setVideoRotation(int videoRotationDegree) {
  101 +// mVideoRotationDegree = videoRotationDegree;
  102 +// }
  103 +//
  104 +//
  105 +// public void setVideoSize(int width, int height) {
  106 +// mVideoWidth = width;
  107 +// mVideoHeight = height;
  108 +// }
  109 +//
  110 +// public void setScreenScale(int screenScale) {
  111 +// mCurrentScreenScale = screenScale;
  112 +// }
  113 +//
  114 +// public int[] doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  115 +// if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) { // 软解码时处理旋转信息,交换宽高
  116 +// widthMeasureSpec = widthMeasureSpec + heightMeasureSpec;
  117 +// heightMeasureSpec = widthMeasureSpec - heightMeasureSpec;
  118 +// widthMeasureSpec = widthMeasureSpec - heightMeasureSpec;
  119 +// }
  120 +//
  121 +// int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
  122 +// int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
  123 +//
  124 +// //如果设置了比例
  125 +// switch (mCurrentScreenScale) {
  126 +// case CNVideoView.SCREEN_SCALE_ORIGINAL:
  127 +// width = mVideoWidth;
  128 +// height = mVideoHeight;
  129 +// break;
  130 +// case CNVideoView.SCREEN_SCALE_16_9:
  131 +// if (height > width / 16 * 9) {
  132 +// height = width / 16 * 9;
  133 +// } else {
  134 +// width = height / 9 * 16;
  135 +// }
  136 +// break;
  137 +// case CNVideoView.SCREEN_SCALE_4_3:
  138 +// if (height > width / 4 * 3) {
  139 +// height = width / 4 * 3;
  140 +// } else {
  141 +// width = height / 3 * 4;
  142 +// }
  143 +//// Log.d("@@@@", "onMeasure 4:3 : width" + width + " height:" + height);
  144 +// break;
  145 +// case CNVideoView.SCREEN_SCALE_MATCH_PARENT:
  146 +// width = widthMeasureSpec;
  147 +// height = heightMeasureSpec;
  148 +// break;
  149 +// case CNVideoView.SCREEN_SCALE_CENTER_CROP:
  150 +// if (mVideoWidth > 0 && mVideoHeight > 0) {
  151 +// if (mVideoWidth * height > width * mVideoHeight) {
  152 +// width = height * mVideoWidth / mVideoHeight;
  153 +// } else {
  154 +// height = width * mVideoHeight / mVideoWidth;
  155 +// }
  156 +// }
  157 +// break;
  158 +// case CNVideoView.SCREEN_SCALE_DEFAULT:
  159 +// default:
  160 +// if (mVideoWidth > 0 && mVideoHeight > 0) {
  161 +//
  162 +// int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
  163 +// int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
  164 +// int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
  165 +// int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
  166 +//
  167 +// if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
  168 +// // the size is fixed
  169 +// width = widthSpecSize;
  170 +// height = heightSpecSize;
  171 +//
  172 +// // for compatibility, we adjust size based on aspect ratio
  173 +// if (mVideoWidth * height < width * mVideoHeight) {
  174 +// //Log.i("@@@", "image too wide, correcting");
  175 +// width = height * mVideoWidth / mVideoHeight;
  176 +// } else if (mVideoWidth * height > width * mVideoHeight) {
  177 +// //Log.i("@@@", "image too tall, correcting");
  178 +// height = width * mVideoHeight / mVideoWidth;
  179 +// }
  180 +// } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
  181 +// // only the width is fixed, adjust the height to match aspect ratio if possible
  182 +// width = widthSpecSize;
  183 +// height = width * mVideoHeight / mVideoWidth;
  184 +// if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
  185 +// // couldn't match aspect ratio within the constraints
  186 +// height = heightSpecSize;
  187 +// }
  188 +// } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
  189 +// // only the height is fixed, adjust the width to match aspect ratio if possible
  190 +// height = heightSpecSize;
  191 +// width = height * mVideoWidth / mVideoHeight;
  192 +// if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
  193 +// // couldn't match aspect ratio within the constraints
  194 +// width = widthSpecSize;
  195 +// }
  196 +// } else {
  197 +// // neither the width nor the height are fixed, try to use actual video size
  198 +// width = mVideoWidth;
  199 +// height = mVideoHeight;
  200 +// if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
  201 +// // too tall, decrease both width and height
  202 +// height = heightSpecSize;
  203 +// width = height * mVideoWidth / mVideoHeight;
  204 +// }
  205 +// if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
  206 +// // too wide, decrease both width and height
  207 +// width = widthSpecSize;
  208 +// height = width * mVideoHeight / mVideoWidth;
  209 +// }
  210 +// }
  211 +// } else {
  212 +// // no size yet, just adopt the given spec sizes
  213 +// }
  214 +// break;
  215 +// }
  216 +//
  217 +// return new int[]{width, height};
  218 +// }
140 219 }
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/render/RenderViewFactory.java
... ... @@ -2,8 +2,16 @@ package com.libs.video.video.exoplayer.render;
2 2  
3 3 import android.content.Context;
4 4  
  5 +/**
  6 + * 此接口用于扩展自己的渲染View。使用方法如下:
  7 + * 1.继承IRenderView实现自己的渲染View。
  8 + * 2.重写createRenderView返回步骤1的渲染View。
  9 + * 可参考{@link com.libs.video.video.exoplayer.render.texture.TextureRenderView}
  10 + * 和
  11 + * {@link com.libs.video.video.exoplayer.render.texture.TextureRenderViewFactory}的实现。
  12 + */
5 13 public abstract class RenderViewFactory {
6 14  
7 15 public abstract IRenderView createRenderView(Context context);
8 16  
9 17 -}
  18 +}
10 19 \ No newline at end of file
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/render/TikTokRenderView.java 0 → 100644
  1 +package com.libs.video.video.exoplayer.render;
  2 +
  3 +import android.graphics.Bitmap;
  4 +import android.view.View;
  5 +
  6 +import androidx.annotation.NonNull;
  7 +
  8 +import com.libs.video.video.exoplayer.play.AbstractPlayer;
  9 +import com.libs.video.video.exoplayer.play.CNVideoView;
  10 +
  11 +
  12 +/**
  13 + * TikTok专用RenderView,横屏视频默认显示,竖屏视频居中裁剪
  14 + * 使用代理模式实现
  15 + */
  16 +public class TikTokRenderView implements IRenderView {
  17 +
  18 + private IRenderView mProxyRenderView;
  19 +
  20 + TikTokRenderView(@NonNull IRenderView renderView) {
  21 + this.mProxyRenderView = renderView;
  22 + }
  23 +
  24 + @Override
  25 + public void attachToPlayer(@NonNull AbstractPlayer player) {
  26 + mProxyRenderView.attachToPlayer(player);
  27 + }
  28 +
  29 + @Override
  30 + public void setVideoSize(int videoWidth, int videoHeight) {
  31 + if (videoWidth > 0 && videoHeight > 0) {
  32 + mProxyRenderView.setVideoSize(videoWidth, videoHeight);
  33 + if (videoHeight > videoWidth) {
  34 + //竖屏视频,使用居中裁剪
  35 + mProxyRenderView.setScaleType(CNVideoView.SCREEN_SCALE_CENTER_CROP);
  36 + } else {
  37 + //横屏视频,使用默认模式
  38 + mProxyRenderView.setScaleType(CNVideoView.SCREEN_SCALE_DEFAULT);
  39 + }
  40 + }
  41 + }
  42 +
  43 + @Override
  44 + public void setVideoRotation(int degree) {
  45 + mProxyRenderView.setVideoRotation(degree);
  46 + }
  47 +
  48 + @Override
  49 + public void setScaleType(int scaleType) {
  50 + // 置空,不要让外部去设置ScaleType
  51 + }
  52 +
  53 + @Override
  54 + public View getView() {
  55 + return mProxyRenderView.getView();
  56 + }
  57 +
  58 + @Override
  59 + public Bitmap doScreenShot() {
  60 + return mProxyRenderView.doScreenShot();
  61 + }
  62 +
  63 + @Override
  64 + public void release() {
  65 + mProxyRenderView.release();
  66 + }
  67 +}
0 68 \ No newline at end of file
... ...
cloud/video/src/main/java/com/libs/video/video/exoplayer/render/TikTokRenderViewFactory.java 0 → 100644
  1 +package com.libs.video.video.exoplayer.render;
  2 +
  3 +import android.content.Context;
  4 +
  5 +import com.libs.video.video.exoplayer.render.texture.TextureRenderView;
  6 +
  7 +
  8 +public class TikTokRenderViewFactory extends RenderViewFactory {
  9 +
  10 + public static TikTokRenderViewFactory create() {
  11 + return new TikTokRenderViewFactory();
  12 + }
  13 +
  14 + @Override
  15 + public IRenderView createRenderView(Context context) {
  16 + return new TikTokRenderView(new TextureRenderView(context));
  17 + }
  18 +}
... ...
cloud/video/src/main/res/layout/cnvideo_layout_title_view.xml
... ... @@ -21,14 +21,12 @@
21 21 android:padding="@dimen/cnvideo_controller_icon_padding"
22 22 android:src="@drawable/cnvideo_ic_action_arrow_back" />
23 23  
24   - <com.libs.video.video.exoplayer.component.MarqueeTextView
  24 + <TextView
25 25 android:id="@+id/title"
26 26 android:layout_width="0dp"
27 27 android:layout_height="wrap_content"
28 28 android:layout_weight="1"
29 29 android:ellipsize="marquee"
30   - android:focusable="true"
31   - android:focusableInTouchMode="true"
32 30 android:marqueeRepeatLimit="marquee_forever"
33 31 android:paddingLeft="6dp"
34 32 android:paddingRight="6dp"
... ...