fix [修复-修改视频框架]

This commit is contained in:
hch
2024-04-01 18:20:10 +08:00
parent 962a07d6d1
commit 97c692d41d
15 changed files with 316 additions and 169 deletions

View File

@@ -43,7 +43,6 @@ public class VideoPlayNewActivity extends AbsVideoPlayActivity {
context.startActivity(intent);
}
public static void forwardSingle(Context context, ActiveBean videoBean) {
if (videoBean == null) {
return;
@@ -80,7 +79,6 @@ public class VideoPlayNewActivity extends AbsVideoPlayActivity {
}
@Override
protected int getLayoutId() {
return R.layout.activity_video_play;

View File

@@ -0,0 +1,37 @@
package com.yunbao.video.views;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class MyImageView extends androidx.appcompat.widget.AppCompatImageView {
public MyImageView(@NonNull Context context) {
super(context);
}
public MyImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Drawable drawable = getDrawable();
if (drawable != null) {
//图片 使用android:layout_width="match_parent",得到的是整个屏幕宽
int width = MeasureSpec.getSize(widthMeasureSpec);
// 根据图片的宽度填充屏幕后 计算得到自适应的图片高度
int height = (int) Math.ceil((float) width * (float) drawable.getIntrinsicHeight() / (float) drawable.getIntrinsicWidth());
setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}

View File

@@ -3,23 +3,23 @@ package com.yunbao.video.views;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.RelativeLayout;
import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXVodPlayConfig;
import com.tencent.rtmp.TXVodPlayer;
import com.tencent.rtmp.ui.TXCloudVideoView;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.StyledPlayerView;
import com.yunbao.common.bean.ActiveBean;
import com.yunbao.common.utils.L;
import com.yunbao.common.utils.ToastUtil;
import com.yunbao.common.views.AbsViewHolder;
import com.yunbao.video.R;
import com.yunbao.common.bean.VideoBean;
import com.yunbao.video.http.VideoHttpConsts;
import com.yunbao.video.http.VideoHttpUtil;
@@ -28,21 +28,18 @@ import com.yunbao.video.http.VideoHttpUtil;
* 视频播放器
*/
public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayListener, View.OnClickListener {
private TXCloudVideoView mTXCloudVideoView;
public class VideoPlayViewHolder extends AbsViewHolder implements View.OnClickListener {
private StyledPlayerView placeholderView;
private ExoPlayer mPlayer;
private View mVideoCover;
private TXVodPlayer mPlayer;
private boolean mPaused;//生命周期暂停
private boolean mClickPaused;//点击暂停
private ActionListener mActionListener;
private View mPlayBtn;
private ActionListener mActionListener;
private ObjectAnimator mPlayBtnAnimator;//暂停按钮的动画
private boolean mStartPlay;
private boolean mEndPlay;
private ActiveBean mVideoBean;
private String mCachePath;
private TXVodPlayConfig mTXVodPlayConfig;
public VideoPlayViewHolder(Context context, ViewGroup parentView) {
super(context, parentView);
@@ -55,19 +52,69 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
@Override
public void init() {
mCachePath = mContext.getCacheDir().getAbsolutePath();
mTXCloudVideoView = (TXCloudVideoView) findViewById(R.id.video_view);
mTXCloudVideoView.setRenderMode(TXLiveConstants.RENDER_ROTATION_PORTRAIT);
mPlayer = new TXVodPlayer(mContext);
mTXVodPlayConfig = new TXVodPlayConfig();
mTXVodPlayConfig.setMaxCacheItems(15);
mTXVodPlayConfig.setProgressInterval(200);
mPlayer.setConfig(mTXVodPlayConfig);
mPlayer.setAutoPlay(true);
mPlayer.setVodListener(this);
mPlayer.setPlayerView(mTXCloudVideoView);
findViewById(R.id.root).setOnClickListener(this);
placeholderView = findViewById(R.id.placeholderView);
intiPlayView();
}
private void intiPlayView() {
DefaultLoadControl control = new DefaultLoadControl.Builder()
.setPrioritizeTimeOverSizeThresholds(false)
.setBackBuffer(10_000, true)
.setBufferDurationsMs(500,
5_000,
150,
200)
.build();
mPlayer = new ExoPlayer.Builder(mContext).setLoadControl(control).build();
placeholderView = findViewById(com.yunbao.live.R.id.placeholderView);
mPlayer = new ExoPlayer.Builder(mContext).setLoadControl(control).build();
mPlayer.setVideoScalingMode(C.VIDEO_SCALING_MODE_DEFAULT);
mPlayer.addListener(new Player.Listener() {
@Override
public void onPlaybackStateChanged(int playbackState) {
Player.Listener.super.onPlaybackStateChanged(playbackState);
switch (playbackState) {
case Player.STATE_IDLE://这是初始状态、播放器停止时以及播放失败时的状态。在此状态下,播放器将仅保留有限的资源。
break;
case Player.STATE_BUFFERING://播放器无法立即从当前位置开始播放。这主要是因为需要加载更多数据。
break;
case Player.STATE_READY://播放器能够从当前位置立即播放。
if (mActionListener != null) {
mActionListener.onFirstFrame();
}
break;
case Player.STATE_ENDED://播放器完整播放了所有媒体。
replay();
break;
}
}
@Override
public void onPlayerError(PlaybackException error) {
Player.Listener.super.onPlayerError(error);
ToastUtil.show(mContext.getResources().getString(R.string.live_play_error));
}
});
placeholderView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH);
placeholderView.requestLayout();
placeholderView.setKeepContentOnPlayerReset(false);
placeholderView.setPlayer(mPlayer);
placeholderView.setKeepContentOnPlayerReset(true);
placeholderView.setShowRewindButton(false);
placeholderView.setShowFastForwardButton(false);
placeholderView.setShowPreviousButton(false);
placeholderView.setShowNextButton(false);
placeholderView.setShowShuffleButton(false);
placeholderView.setShowMultiWindowTimeBar(false);
placeholderView.setControllerAutoShow(false);
placeholderView.setUseController(false);
mVideoCover = findViewById(R.id.video_cover);
mVideoCover.setOnClickListener(this);
mPlayBtn = findViewById(R.id.btn_play);
//暂停按钮动画
mPlayBtnAnimator = ObjectAnimator.ofPropertyValuesHolder(mPlayBtn, PropertyValuesHolder.ofFloat("scaleX", 4f, 0.8f, 1f), PropertyValuesHolder.ofFloat("scaleY", 4f, 0.8f, 1f), PropertyValuesHolder.ofFloat("alpha", 0f, 1f));
@@ -75,102 +122,15 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
mPlayBtnAnimator.setInterpolator(new AccelerateInterpolator());
}
/**
* 播放器事件回调
*/
@Override
public void onPlayEvent(TXVodPlayer txVodPlayer, int e, Bundle bundle) {
switch (e) {
case TXLiveConstants.PLAY_EVT_PLAY_BEGIN://加载完成,开始播放的回调
mStartPlay = true;
if (mActionListener != null) {
mActionListener.onPlayBegin(txVodPlayer.getDuration());
}
if (mActionListener != null) {
mActionListener.onFirstFrame();
}
break;
case TXLiveConstants.PLAY_EVT_PLAY_LOADING: //开始加载的回调
if (mActionListener != null) {
mActionListener.onPlayLoading();
}
break;
case TXLiveConstants.PLAY_EVT_PLAY_END://获取到视频播放完毕的回调
replay();
if (!mEndPlay) {
mEndPlay = true;
if (mVideoBean != null) {
VideoHttpUtil.videoWatchEnd(mVideoBean.getUser_id(), mVideoBean.getId());
}
}
break;
case TXLiveConstants.PLAY_EVT_RCV_FIRST_I_FRAME://获取到视频首帧回调
if (mActionListener != null) {
mActionListener.onFirstFrame();
}
if (mPaused && mPlayer != null) {
mPlayer.pause();
}
break;
case TXLiveConstants.PLAY_EVT_CHANGE_RESOLUTION://获取到视频宽高回调
onVideoSizeChanged( bundle.getInt("EVT_PARAM2", 0),bundle.getInt("EVT_PARAM1", 0));
break;
case TXLiveConstants.PLAY_EVT_PLAY_PROGRESS:
if (mActionListener != null) {
int progress = bundle.getInt(TXLiveConstants.EVT_PLAY_PROGRESS_MS);
int duration = bundle.getInt(TXLiveConstants.EVT_PLAY_DURATION_MS);
mActionListener.onProgress(progress, duration);
}
break;
}
}
@Override
public void onNetStatus(TXVodPlayer txVodPlayer, Bundle bundle) {
}
/**
* 获取到视频宽高回调
*/
public void onVideoSizeChanged(float videoWidth, float videoHeight) {
if (mTXCloudVideoView != null && videoWidth > 0 && videoHeight > 0) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mTXCloudVideoView.getLayoutParams();
/*
int videoViewHeight = params.height;
int videoViewWidth = params.width;
if (videoWidth < videoViewWidth && videoHeight >= videoViewHeight) {
params.width = (int) (videoViewHeight / (videoHeight / videoViewHeight));
} else if (videoWidth > videoViewWidth && videoHeight >= videoViewHeight) {
params.width = (int) (videoViewHeight / (videoHeight / videoWidth));
}
mTXCloudVideoView.requestLayout();
if (mVideoCover != null && mVideoCover.getVisibility() == View.VISIBLE) {
mVideoCover.setVisibility(View.INVISIBLE);
}*/
int targetH = 0;
if (videoWidth / videoHeight > 0.5625f) {//横屏 9:16=0.5625
/*targetH = (int) (videoHeight*(videoWidth/videoHeight));*/
targetH = (int) (mTXCloudVideoView.getWidth() / videoWidth * videoHeight);
} else {
targetH = ViewGroup.LayoutParams.MATCH_PARENT;
}
if (targetH != params.height) {
params.height = targetH;
mTXCloudVideoView.requestLayout();
}
if (mVideoCover != null && mVideoCover.getVisibility() == View.VISIBLE) {
mVideoCover.setVisibility(View.INVISIBLE);
}
}
private MediaItem createMediaItem(String url) {
return MediaItem.fromUri(url);
}
/**
* 开始播放
*/
public void startPlay(ActiveBean videoBean) {
mStartPlay = false;
mStartPlay = true;
mClickPaused = false;
mEndPlay = false;
mVideoBean = videoBean;
@@ -178,28 +138,14 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
mVideoCover.setVisibility(View.VISIBLE);
}
hidePlayBtn();
if (mPlayer.isPlaying()) {
mPlayer.stop();
}
L.e("播放视频--->" + videoBean);
if (videoBean == null) {
return;
}
String url = videoBean.getVideo();
if (TextUtils.isEmpty(url)) {
return;
}
if (mTXVodPlayConfig == null) {
mTXVodPlayConfig = new TXVodPlayConfig();
mTXVodPlayConfig.setMaxCacheItems(15);
mTXVodPlayConfig.setProgressInterval(200);
}
if (url.endsWith(".m3u8")) {
mTXVodPlayConfig.setCacheFolderPath(null);
} else {
mTXVodPlayConfig.setCacheFolderPath(mCachePath);
}
mPlayer.setConfig(mTXVodPlayConfig);
if (mPlayer != null) {
mPlayer.startPlay(url);
}
mPlayer.setMediaItem(createMediaItem(videoBean.getVideo()));
mPlayer.prepare();
mPlayer.play();
VideoHttpUtil.videoWatchStart(videoBean.getUser_id(), videoBean.getId());
}
@@ -208,7 +154,7 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
*/
public void stopPlay() {
if (mPlayer != null) {
mPlayer.stopPlay(false);
mPlayer.stop();
}
}
@@ -217,8 +163,7 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
*/
private void replay() {
if (mPlayer != null) {
mPlayer.seek(0);
mPlayer.resume();
startPlay(mVideoBean);
}
}
@@ -226,8 +171,7 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
VideoHttpUtil.cancel(VideoHttpConsts.VIDEO_WATCH_START);
VideoHttpUtil.cancel(VideoHttpConsts.VIDEO_WATCH_END);
if (mPlayer != null) {
mPlayer.stopPlay(false);
mPlayer.setPlayListener(null);
mPlayer.stop();
}
mPlayer = null;
mActionListener = null;
@@ -249,7 +193,7 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
public void resumePlay() {
if (mPaused) {
if (!mClickPaused && mPlayer != null) {
mPlayer.resume();
mPlayer.play();
}
}
mPaused = false;
@@ -283,7 +227,7 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
}
if (mPlayer != null) {
if (mClickPaused) {
mPlayer.resume();
mPlayer.play();
} else {
mPlayer.pause();
}
@@ -302,7 +246,7 @@ public class VideoPlayViewHolder extends AbsViewHolder implements ITXVodPlayList
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.root) {
if (i == R.id.video_cover) {
clickTogglePlay();
}
}

View File

@@ -57,7 +57,7 @@ import java.util.List;
public class VideoPlayWrapViewHolder extends AbsViewHolder implements View.OnClickListener {
private ViewGroup mVideoContainer;
private ImageView mCover;
private MyImageView mCover;
private ImageView mAvatar;
private TextView mName;
private TextView mTitle;
@@ -101,7 +101,7 @@ public class VideoPlayWrapViewHolder extends AbsViewHolder implements View.OnCli
progressCount = (TextView) findViewById(R.id.progressCount);
mVideoContainer = (ViewGroup) findViewById(R.id.video_container);
mCover = (ImageView) findViewById(R.id.cover);
mCover = (MyImageView) findViewById(R.id.cover);
mAvatar = (ImageView) findViewById(R.id.avatar);
mName = (TextView) findViewById(R.id.name);
mTitle = (TextView) findViewById(R.id.title);
@@ -303,6 +303,20 @@ public class VideoPlayWrapViewHolder extends AbsViewHolder implements View.OnCli
mCover.requestLayout();
}
mCover.setImageDrawable(drawable);
/*
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mCover.getLayoutParams();
int imageWidth = drawable.getIntrinsicWidth();
int imageHeight = drawable.getIntrinsicHeight();
//宽度固定,然后根据原始宽高比得到此固定宽度需要的高度
//screenWidth 是屏幕宽度
int height = mCover.getWidth() * imageHeight / imageWidth;
ViewGroup.LayoutParams para = mCover.getLayoutParams();
para.height = height;
para.width = mCover.getWidth();*/
//mCover.setImageDrawable(drawable);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

View File

@@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/video_view"
<com.google.android.exoplayer2.ui.StyledPlayerView
android:id="@+id/placeholderView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
android:layout_height="match_parent" />
<View
android:id="@+id/video_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000" />
android:background="@color/transparent" />
<ImageView
android:id="@+id/btn_play"
@@ -24,5 +24,4 @@
android:adjustViewBounds="true"
android:src="@mipmap/icon_video_play"
android:visibility="invisible" />
</RelativeLayout>

View File

@@ -10,12 +10,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
<com.yunbao.video.views.MyImageView
android:id="@+id/cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:scaleType="centerCrop" />
android:layout_centerInParent="true" />
<RelativeLayout
android:layout_width="50dp"