1584 lines
54 KiB
Java
1584 lines
54 KiB
Java
|
||
package com.pukka.videoplayertv;
|
||
|
||
import static android.view.KeyEvent.ACTION_DOWN;
|
||
|
||
import android.annotation.TargetApi;
|
||
import android.content.Context;
|
||
import android.media.AudioManager;
|
||
import android.media.MediaPlayer;
|
||
import android.net.Uri;
|
||
import android.os.Build;
|
||
import android.util.AttributeSet;
|
||
import android.util.Log;
|
||
import android.view.Gravity;
|
||
import android.view.KeyEvent;
|
||
import android.view.MotionEvent;
|
||
import android.view.View;
|
||
import android.view.ViewGroup;
|
||
import android.widget.FrameLayout;
|
||
|
||
import androidx.annotation.NonNull;
|
||
|
||
import com.pukka.libcore.boxShared.BoxSharedParamsUtils;
|
||
import com.pukka.libcore.utils.ContextUtils;
|
||
import com.pukka.libcore.utils.LogUtils;
|
||
import com.pukka.videoplayertv.exoplayer.PkExoMediaPlayer;
|
||
|
||
import java.io.IOException;
|
||
import java.lang.reflect.Method;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 视频播放控件
|
||
* 使用方法
|
||
* mMediaController = new TVmediaController(this, true);
|
||
* mVideoView = (VideoViewTv) findViewById(R.id.video_view);
|
||
* mVideoView.setVideoPath(mVideoPath);
|
||
* mVideoView.setMediaController(mMediaController);
|
||
* mVideoView.start();
|
||
*/
|
||
public class VideoViewTv extends FrameLayout implements MediaPlayerControl {
|
||
|
||
private static final String TAG = "VideoViewTv";
|
||
|
||
/**
|
||
* 本次 APK 运行期间是否已经设置过默认音量
|
||
* 用途:控制只在首次进入视频播放时设置默认音量(30%),后续切换分集、切换影片不再重置。
|
||
* 进程重启(APK 重启)后静态变量自动重置为 false,从而恢复"首次进入详情设置默认音量"的流程。
|
||
* 不使用 SharedPreferences:因为需求要求 APK 重启后重新走首次设置流程,需内存级标志位。
|
||
*/
|
||
private static boolean sDefaultVolumeApplied = false;
|
||
|
||
// 播放视频路径
|
||
private Uri mUri;
|
||
|
||
// 媒体视频headers
|
||
private Map<String, String> mHeaders;
|
||
|
||
// 播放器可能的状态
|
||
// 播放器出错状态
|
||
public static final int STATE_ERROR = -1;
|
||
|
||
// 闲置状态
|
||
public static final int STATE_IDLE = 0;
|
||
|
||
// 准备状态
|
||
public static final int STATE_PREPARING = 1;
|
||
|
||
// 准备结束状态
|
||
public static final int STATE_PREPARED = 2;
|
||
|
||
// 播放状态
|
||
public static final int STATE_PLAYING = 3;
|
||
|
||
// 暂停状态
|
||
public static final int STATE_PAUSED = 4;
|
||
|
||
// 播放结束状态
|
||
public static final int STATE_PLAYBACK_COMPLETED = 5;
|
||
|
||
// mCurrentState is a VideoView object's current state.
|
||
// mTargetState is the state that a method caller intends to reach.
|
||
// For instance, regardless the VideoView object's current state,
|
||
// calling pause() intends to bring the object to a target state
|
||
// of STATE_PAUSED.
|
||
// 播放器当前状态
|
||
private int mCurrentState = STATE_IDLE;
|
||
|
||
// 播放器下一个状态
|
||
private int mTargetState = STATE_IDLE;
|
||
|
||
// All the stuff we need for playing and showing a video
|
||
// 播放的surfaceholder接口
|
||
private IRenderView.ISurfaceHolder mSurfaceHolder = null;
|
||
|
||
// 播放器接口
|
||
private IMediaPlayer mMediaPlayer = null;
|
||
|
||
// 视频宽度
|
||
private int mVideoWidth;
|
||
|
||
// 视频高度
|
||
private int mVideoHeight;
|
||
|
||
// surface宽度
|
||
private int mSurfaceWidth;
|
||
|
||
// surface高度
|
||
private int mSurfaceHeight;
|
||
|
||
// 视频控制器
|
||
private IMediaController mMediaController;
|
||
|
||
// 视频播放完成的监听
|
||
private IMediaPlayer.OnCompletionListener mOnCompletionListener;
|
||
|
||
// 视频准备结束的监听
|
||
private IMediaPlayer.OnPreparedListener mOnPreparedListener;
|
||
|
||
private int mCurrentBufferPercentage;
|
||
|
||
// 缓冲
|
||
private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener;
|
||
|
||
// 视频播放过程中出错的监听
|
||
private IMediaPlayer.OnErrorListener mOnErrorListener;
|
||
|
||
// 视频信息列表的监听
|
||
private IMediaPlayer.OnInfoListener mOnInfoListener;
|
||
|
||
// recording the seek position while preparing
|
||
private int mSeekWhenPrepared;
|
||
|
||
// 暂停
|
||
private boolean mCanPause = true;
|
||
|
||
// 后退
|
||
private boolean mCanSeekBack = true;
|
||
|
||
// 前进
|
||
private boolean mCanSeekForward = true;
|
||
|
||
// 视频呈现方式
|
||
private int mCurrentAspectRatio = IRenderView.AR_ASPECT_WRAP_CONTENT;
|
||
|
||
// 播放视频VIEW
|
||
private IRenderView mRenderView;
|
||
|
||
private int mVideoSarNum;
|
||
|
||
private int mVideoSarDen;
|
||
|
||
// 直播[1]和点播[0]的区分
|
||
private int isLive = 0;
|
||
|
||
// 判断是否是软终端,选择不同的播放器 0是常规 , 1是软终端 2是ExoMediaPlayer
|
||
private int terminalType = 2;
|
||
|
||
/**
|
||
* 全屏模式
|
||
**/
|
||
public static final int MODE_FULL_SCREEN = 11;
|
||
|
||
/**
|
||
* 小窗口模式
|
||
**/
|
||
public static final int MODE_TINY_WINDOW = 12;
|
||
|
||
/**
|
||
* 普通模式
|
||
*/
|
||
public static final int MODE_NORMAL = 13;
|
||
|
||
private int mCurrentMode = MODE_NORMAL;
|
||
|
||
|
||
public IOnPauseListener onPauseListener;
|
||
|
||
public IOnResumeListener onResumeListener;
|
||
|
||
/**
|
||
* 是否是快进
|
||
*/
|
||
private boolean isSeekForward;
|
||
|
||
public boolean isSeekForward() {
|
||
return isSeekForward;
|
||
}
|
||
|
||
/**
|
||
* 首次播放的seek播放进度(比如说release 播放器以后要播放到指定position)
|
||
*/
|
||
private int firstPlayPosition;
|
||
|
||
public void setFirstPlayPosition(int firstPlayPosition) {
|
||
this.firstPlayPosition = firstPlayPosition;
|
||
}
|
||
|
||
public IMediaPlayer getMediaPlayer() {
|
||
LogUtils.d("getMediaPlayer: "+mMediaPlayer.toString());
|
||
return mMediaPlayer;
|
||
}
|
||
|
||
/**
|
||
* 设置成全屏播放模式
|
||
*/
|
||
public void setModeFullScreen() {
|
||
setmCurrentAspectRatio(IRenderView.AR_ASPECT_FIT_PARENT);
|
||
this.mCurrentMode = MODE_FULL_SCREEN;
|
||
// setRenderView();
|
||
FrameLayout.LayoutParams layoutParams_txt =
|
||
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.TOP);
|
||
this.setLayoutParams(layoutParams_txt);
|
||
}
|
||
|
||
/**
|
||
* 设置成全屏播放模式
|
||
*
|
||
* @param width 全屏时的width
|
||
* @param height 全屏时的height
|
||
*/
|
||
public void setModeFullScreen(int width, int height) {
|
||
setmCurrentAspectRatio(IRenderView.AR_ASPECT_FIT_PARENT);
|
||
this.mCurrentMode = MODE_FULL_SCREEN;
|
||
mRenderView.setVideoSize(width > 0 ? width : mVideoWidth, height > 0 ? height : mVideoHeight);
|
||
}
|
||
|
||
/**
|
||
* 设置成小屏播放模式
|
||
*
|
||
* @param width 小屏时的width
|
||
* @param height 小屏时的height
|
||
*/
|
||
public void setModeTinyScreen(int width, int height) {
|
||
setmCurrentAspectRatio(IRenderView.AR_ASPECT_FIT_PARENT);
|
||
this.mCurrentMode = MODE_TINY_WINDOW;
|
||
LogUtils.d("smm -- ", "setModeTinyScreen width:"+width + " height:"+height);
|
||
mRenderView.setVideoSize(width, height);
|
||
setFocusable(false);
|
||
// 隐藏播控
|
||
if (null != mMediaController) {
|
||
mMediaController.setMediaPlayer(null);
|
||
mMediaController.hide();
|
||
mMediaController = null;
|
||
}
|
||
}
|
||
|
||
public void setmCurrentMode(int mCurrentMode) {
|
||
this.mCurrentMode = mCurrentMode;
|
||
}
|
||
|
||
/**
|
||
* 是否是全屏模式
|
||
*
|
||
* @return
|
||
*/
|
||
public boolean isFullScreen() {
|
||
return this.mCurrentMode == MODE_FULL_SCREEN;
|
||
}
|
||
|
||
/**
|
||
* 设置成小屏播放模式,且隐藏播控
|
||
*
|
||
* @param width 视频控件 宽
|
||
* @param height 视频控件 高
|
||
* @param left 左侧偏移量
|
||
* @param top 头部偏移量
|
||
*/
|
||
public void setModeTinyWindow(int width, int height, int left, int top) {
|
||
setmCurrentAspectRatio(IRenderView.AR_ASPECT_FIT_PARENT);
|
||
this.mCurrentMode = MODE_TINY_WINDOW;
|
||
FrameLayout.LayoutParams layoutParams_txt = new FrameLayout.LayoutParams(width, height, Gravity.TOP);
|
||
layoutParams_txt.setMarginStart(left);
|
||
layoutParams_txt.topMargin = top;
|
||
setLayoutParams(layoutParams_txt);
|
||
setFocusable(false);
|
||
// 隐藏播控
|
||
if (null != mMediaController) {
|
||
mMediaController.hide();
|
||
}
|
||
}
|
||
|
||
public void setTerminalType(int terminalType) {
|
||
this.terminalType = terminalType;
|
||
}
|
||
|
||
public int getTerminalType() {
|
||
return terminalType;
|
||
}
|
||
|
||
public void switchTerminal(int terminalType, String path) {
|
||
this.terminalType = terminalType;
|
||
mMediaPlayer.release();
|
||
mMediaPlayer = null;
|
||
initVideoView();
|
||
setVideoPath(path);
|
||
}
|
||
|
||
/**
|
||
* 获取播放器状态
|
||
*/
|
||
public int getCurrentState() {
|
||
return mCurrentState;
|
||
}
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
public VideoViewTv(Context context) {
|
||
super(context);
|
||
initVideoView();
|
||
}
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
public VideoViewTv(Context context, AttributeSet attrs) {
|
||
super(context, attrs);
|
||
initVideoView();
|
||
}
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
public VideoViewTv(Context context, AttributeSet attrs, int defStyleAttr) {
|
||
super(context, attrs, defStyleAttr);
|
||
initVideoView();
|
||
}
|
||
|
||
private void initVideoView() {
|
||
if (!checkAudioCapability()){
|
||
terminalType = 0;
|
||
}
|
||
if (BoxSharedParamsUtils.getInstance().getModel().equals("NL_MTK9255_D1E8_RG_828_RX50")){
|
||
//这个型号设备Guava库版本过低,使用exo会崩溃
|
||
terminalType = 0;
|
||
}
|
||
setRenderView();
|
||
mVideoWidth = 0;
|
||
mVideoHeight = 0;
|
||
mCurrentState = STATE_IDLE;
|
||
mTargetState = STATE_IDLE;
|
||
}
|
||
|
||
private boolean checkAudioCapability() {
|
||
LogUtils.d("Audio", "getModel:" +BoxSharedParamsUtils.getInstance().getModel());
|
||
try {
|
||
// 1. 先检查类是否存在
|
||
Class<?> audioCapClass = Class.forName("com.google.android.exoplayer2.audio.AudioCapabilities");
|
||
// 2. 检查方法是否存在
|
||
Method getCapabilitiesMethod = audioCapClass.getDeclaredMethod("getCapabilities", Context.class);
|
||
// 3. 调用方法
|
||
Object result = getCapabilitiesMethod.invoke(null, getContext());
|
||
return true;
|
||
} catch (ClassNotFoundException e) {
|
||
LogUtils.d("Audio", "AudioCapabilities类不存在");
|
||
return false;
|
||
} catch (NoSuchMethodException e) {
|
||
LogUtils.d("Audio", "getCapabilities方法不存在");
|
||
return false;
|
||
} catch (Throwable t) {
|
||
LogUtils.d("Audio", "其他错误:"+ t);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置RenderView
|
||
*/
|
||
public void setRenderView() {
|
||
LogUtils.d("smm -- ", "setRenderView");
|
||
SurfaceRenderView renderView = new SurfaceRenderView(getContext());
|
||
// 修改原视图
|
||
if (mRenderView != null) {
|
||
if (mMediaPlayer != null) {
|
||
mMediaPlayer.setDisplay(null);
|
||
}
|
||
LogUtils.d("smm --- mid -- ", "setRenderView");
|
||
View renderUIView = mRenderView.getView();
|
||
mRenderView.removeRenderCallback(mSHCallback);
|
||
mRenderView = null;
|
||
removeView(renderUIView);
|
||
mSurfaceHolder = null;
|
||
}
|
||
|
||
if (renderView == null) {
|
||
return;
|
||
}
|
||
|
||
mRenderView = renderView;
|
||
// 设置视频显示方式
|
||
renderView.setAspectRatio(mCurrentAspectRatio);
|
||
LogUtils.d("mCurrentAspectRatio=" + mCurrentAspectRatio);
|
||
if (mVideoWidth > 0 && mVideoHeight > 0) {
|
||
renderView.setVideoSize(mVideoWidth, mVideoHeight);
|
||
}
|
||
if (mVideoSarNum > 0 && mVideoSarDen > 0) {
|
||
renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
|
||
}
|
||
LogUtils.d("mVideoHeight=" + mVideoHeight);
|
||
View renderUIView = mRenderView.getView();
|
||
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
|
||
LogUtils.d("LP -- width : " + lp.width + " height : " + lp.height);
|
||
renderUIView.setLayoutParams(lp);
|
||
// 将SurfaceRenderView添加到这个自定义控件中
|
||
addView(renderUIView);
|
||
mRenderView.addRenderCallback(mSHCallback);
|
||
LogUtils.d("smm --- end -- ", "setRenderView");
|
||
}
|
||
|
||
public void setVolume(float leftVolume, float rightVolume) {
|
||
LogUtils.d("setVolume() + leftVolume: " + leftVolume + " rightVolume: " + rightVolume
|
||
+ " mMediaPlayer= " + mMediaPlayer);
|
||
if (mMediaPlayer != null) {
|
||
mMediaPlayer.setVolume(leftVolume, rightVolume);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 打开视频
|
||
*/
|
||
@TargetApi(Build.VERSION_CODES.M)
|
||
private void openVideo() {
|
||
LogUtils.d("openVideo() + uri : " + mUri);
|
||
if (mMediaPlayer != null) {
|
||
LogUtils.d("mMediaPlayer is null");
|
||
return;
|
||
}
|
||
if (mUri == null || mSurfaceHolder == null) {
|
||
// not ready for playback just yet, will try again later
|
||
LogUtils.d("mSurfaceHolder is null");
|
||
return;
|
||
}
|
||
// we shouldn't com.pukka.common_lib.clear the target state, because somebody might have
|
||
// called start() previously
|
||
|
||
// 重复的销毁播放器,把销毁播放放到epg来做
|
||
|
||
// release(false);
|
||
// releaseError(true);
|
||
// 音频管理器
|
||
AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
||
if (am != null) {
|
||
// 仅在本次 APK 运行期间首次进入视频播放时设置默认音量(30%),
|
||
// 后续切换分集、切换影片保持用户当前音量不变;
|
||
// APK 重启后 sDefaultVolumeApplied 静态标志位自动重置,重新走首次设置流程
|
||
if (!sDefaultVolumeApplied) {
|
||
int maxVolume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
||
// 使用 Math.round 四舍五入,寻找最接近 10% 的真实硬件阶数(避免向下取整导致偏差过大)
|
||
int targetVolume = Math.round(maxVolume * 0.1f);
|
||
am.setStreamVolume(AudioManager.STREAM_MUSIC, targetVolume, 0);
|
||
sDefaultVolumeApplied = true;
|
||
LogUtils.d("openVideo() set STREAM_MUSIC volume to 30%: " + targetVolume + " / " + maxVolume);
|
||
} else {
|
||
LogUtils.d("openVideo() keep current STREAM_MUSIC volume, default already applied this session");
|
||
}
|
||
}
|
||
int audioStatus = am.requestAudioFocus(focusChange -> LogUtils.d("onAudioFocusChange --XX : " + focusChange), AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||
|
||
LogUtils.d("requestAudioFocus -- : " + audioStatus);
|
||
try {
|
||
LogUtils.d("smm -- ", "openvideo -- create");
|
||
// 获得一个视频管理器
|
||
mMediaPlayer = createPlayer();
|
||
LogUtils.d("mMediaPlayer -- : " + mMediaPlayer);
|
||
if (mMediaPlayer != null) {
|
||
// a context for the subtitle renderers
|
||
// REMOVED: SubtitleController
|
||
// REMOVED: mAudioSession
|
||
// 注册监听事件
|
||
mMediaPlayer.setOnPreparedListener(mPreparedListener);
|
||
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
|
||
mMediaPlayer.setOnCompletionListener(mCompletionListener);
|
||
mMediaPlayer.setOnErrorListener(mErrorListener);
|
||
mMediaPlayer.setOnInfoListener(mInfoListener);
|
||
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
|
||
mMediaPlayer.setOnSeekCompleteListener(seekCompleteListener);
|
||
mCurrentBufferPercentage = 0;
|
||
LogUtils.d("mMediaPlayer -- setOn over : ");
|
||
mMediaPlayer.setDataSource(getContext(), mUri, mHeaders);
|
||
LogUtils.d("smm -00- setDataSource url is -- :" + mUri);
|
||
|
||
bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
|
||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||
mMediaPlayer.setScreenOnWhilePlaying(true);
|
||
mMediaPlayer.prepareAsync();
|
||
LogUtils.d("prepareAsync ---- start----");
|
||
|
||
/*
|
||
* if (mHudViewHolder != null)
|
||
* mHudViewHolder.setMediaPlayer(mMediaPlayer);
|
||
*/
|
||
|
||
// REMOVED: mPendingSubtitleTracks
|
||
|
||
// we don't set the target state here either, but preserve the
|
||
// target state that was there before.
|
||
mCurrentState = STATE_PREPARING;
|
||
attachMediaController();
|
||
} else {
|
||
LogUtils.d("mMediaPlayer ---- is null----");
|
||
}
|
||
} catch (IOException ex) {
|
||
Log.w(TAG, "Unable to open content: " + mUri, ex);
|
||
mCurrentState = STATE_ERROR;
|
||
mTargetState = STATE_ERROR;
|
||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||
} catch (IllegalArgumentException ex) {
|
||
Log.w(TAG, "Unable to open content: " + mUri, ex);
|
||
mCurrentState = STATE_ERROR;
|
||
mTargetState = STATE_ERROR;
|
||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||
} catch (IllegalStateException ex) {
|
||
ex.printStackTrace();
|
||
Log.w(TAG, "IllegalStateException: " + mUri, ex);
|
||
} catch (NullPointerException ex) {
|
||
ex.printStackTrace();
|
||
Log.w(TAG, "NullPointerException: " + ex);
|
||
} finally {
|
||
// REMOVED: mPendingSubtitleTracks.com.pukka.common_lib.clear();
|
||
}
|
||
}
|
||
|
||
/***
|
||
* 根据配置创建一个播放器
|
||
*/
|
||
// @UnstableApi
|
||
public IMediaPlayer createPlayer() {
|
||
LogUtils.i("createPlayer -- start -- new ");
|
||
IMediaPlayer mediaPlayer;
|
||
// 1为软终端 采用杭研播放器
|
||
if (terminalType == 1) {
|
||
LogUtils.d("SoftMediaPlayer() terminalType: "+terminalType);
|
||
mediaPlayer = new SoftMediaPlayer(getContext());
|
||
}else if(terminalType == 2){
|
||
LogUtils.d("PkExoMediaPlayer() terminalType: "+terminalType);
|
||
mediaPlayer = new PkExoMediaPlayer(ContextUtils.getContext());
|
||
}
|
||
else {
|
||
LogUtils.d("AndroidMediaPlayer() terminalType: "+terminalType);
|
||
mediaPlayer = new AndroidMediaPlayer();
|
||
}
|
||
LogUtils.i("createPlayer -- end");
|
||
return mediaPlayer;
|
||
}
|
||
|
||
/**
|
||
* release the media player in any state
|
||
* 复位播放器,释放播放器资源
|
||
*
|
||
* @param clearTargetState clearTargetState
|
||
**/
|
||
public void release(boolean clearTargetState) {
|
||
LogUtils.i("release");
|
||
try {
|
||
if (mMediaPlayer != null) {
|
||
LogUtils.i("release---------start---------1" + clearTargetState);
|
||
mCurrentState = STATE_IDLE;
|
||
mMediaPlayer.setDisplay(null);
|
||
// mMediaPlayer.setSurface(null);
|
||
pause();
|
||
reset();
|
||
mMediaPlayer.release();
|
||
if(mMediaPlayer != null){
|
||
if(mMediaPlayer instanceof PkExoMediaPlayer){
|
||
PkExoMediaPlayer pkExoMediaPlayer = (PkExoMediaPlayer)mMediaPlayer;
|
||
pkExoMediaPlayer.resetListeners();
|
||
}
|
||
}
|
||
mMediaPlayer = null;
|
||
mUri = null;
|
||
mVideoWidth = 0;
|
||
mVideoHeight = 0;
|
||
}
|
||
} catch (Exception e) {
|
||
releaseError(clearTargetState);
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
public void releaseError(boolean clearTargetState) {
|
||
try {
|
||
if (null != mMediaPlayer) {
|
||
mMediaPlayer = null;
|
||
mCurrentState = STATE_IDLE;
|
||
mUri = null;
|
||
if (clearTargetState) {
|
||
mTargetState = STATE_IDLE;
|
||
}
|
||
AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
||
am.abandonAudioFocus(focusChange -> LogUtils.d("onAudioFocusChange --YY : " + focusChange));
|
||
LogUtils.i("release---------end ----");
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 复位播放器
|
||
*/
|
||
public void reset() {
|
||
try {
|
||
if (mMediaPlayer != null) {
|
||
mMediaPlayer.reset();
|
||
mCurrentState = STATE_IDLE;
|
||
mTargetState = STATE_IDLE;
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 关联IjkVideoView与mediaController
|
||
*/
|
||
private void attachMediaController() {
|
||
if (this.mCurrentMode == MODE_FULL_SCREEN || this.mCurrentMode == MODE_NORMAL) {
|
||
if (mMediaPlayer != null && mMediaController != null) {
|
||
// 将ijkvideoview对象传递给controller的成员变量
|
||
mMediaController.setMediaPlayer(this);
|
||
// View anchorView = this.getParent() instanceof View ?
|
||
// (View) this.getParent() : this;
|
||
ViewGroup anchorView = this.getParent() instanceof ViewGroup ? (ViewGroup) this.getParent() : this;
|
||
// ViewGroup anchorView = this;
|
||
// 把控制条附加到播放视频的SurfaceView上
|
||
mMediaController.setAnchorView(anchorView);
|
||
mMediaController.setEnabled(isInPlaybackState());
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 为VideoView设置MediaController
|
||
**/
|
||
public void setMediaController(IMediaController controller) {
|
||
if (mMediaController != null) {
|
||
mMediaController.hide();
|
||
}
|
||
// 将AndroidMediaController对象赋值给IjkVideoView类的成员变量
|
||
mMediaController = controller;
|
||
attachMediaController();
|
||
}
|
||
|
||
public void setTouchModeEnabled(boolean isTouchMode) {
|
||
if (mMediaController instanceof TvMediaController) {
|
||
((TvMediaController) mMediaController).setTouchModeEnabled(isTouchMode);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 判断是否可以进行播放
|
||
*/
|
||
private boolean isInPlaybackState() {
|
||
return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE
|
||
&& mCurrentState != STATE_PREPARING);
|
||
}
|
||
|
||
/**
|
||
* 判断是否可以获取总时长,当前时间等
|
||
*/
|
||
private boolean isInOperation() {
|
||
return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE
|
||
&& mCurrentState != STATE_PREPARING && mCurrentState != STATE_PLAYBACK_COMPLETED);
|
||
}
|
||
|
||
/**
|
||
* 判断是否可以快进
|
||
*/
|
||
private boolean isInffwdState() {
|
||
return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE
|
||
&& mCurrentState != STATE_PREPARING && mCurrentState != STATE_PLAYBACK_COMPLETED);
|
||
}
|
||
|
||
/**
|
||
* 设置视频路径
|
||
*
|
||
* @param path the path of the video.
|
||
*/
|
||
public void setVideoPath(String path) {
|
||
if(BoxSharedParamsUtils.getInstance().isNeed2http()) {
|
||
String videoUrl = path.replace("https://", "http://");
|
||
setVideoURI(Uri.parse(videoUrl));
|
||
}else {
|
||
setVideoURI(Uri.parse(path));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 停止播放 释放播放资源
|
||
*/
|
||
public void stopPlayback() {
|
||
try {
|
||
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
|
||
mMediaPlayer.stop();
|
||
mMediaPlayer.release();
|
||
mMediaPlayer.reset();
|
||
mMediaPlayer = null;
|
||
|
||
mCurrentState = STATE_IDLE;
|
||
mTargetState = STATE_IDLE;
|
||
AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
||
am.abandonAudioFocus(null);
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置视频URI.
|
||
*
|
||
* @param uri the URI of the video.
|
||
*/
|
||
public void setVideoURI(Uri uri) {
|
||
setVideoURI(uri, null);
|
||
}
|
||
|
||
/**
|
||
* Sets video URI using specific headers.
|
||
*
|
||
* @param uri the URI of the video.
|
||
* @param headers the headers for the URI request.
|
||
* Note that the cross domain redirection is allowed by default, but that can be
|
||
* changed with key/value pairs through the headers parameter with
|
||
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
|
||
* to disallow or allow cross domain redirection.
|
||
*/
|
||
private void setVideoURI(Uri uri, Map<String, String> headers) {
|
||
mUri = uri;
|
||
mHeaders = headers;
|
||
mSeekWhenPrepared = 0;
|
||
// 打开视频
|
||
openVideo();
|
||
// 重新绘制画面
|
||
requestLayout();
|
||
// 重新绘制画面
|
||
invalidate();
|
||
}
|
||
|
||
public void setVideoURIFull(Uri uri, Map<String, String> headers) {
|
||
LogUtils.d("uri --YY : " + uri.toString());
|
||
mUri = uri;
|
||
mHeaders = headers;
|
||
mSeekWhenPrepared = 0;
|
||
// 打开视频
|
||
// openVideo();
|
||
// 重新绘制画面
|
||
requestLayout();
|
||
// 重新绘制画面
|
||
invalidate();
|
||
}
|
||
|
||
/**
|
||
* 设置
|
||
*/
|
||
// ***************************按键事件响应**********************************************//
|
||
@Override
|
||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||
return super.dispatchKeyEvent(event);
|
||
}
|
||
// ***************************按键事件响应**********************************************//
|
||
|
||
// ************************* 画布Callback **********************************//
|
||
/**
|
||
* surface发生变化, 执行
|
||
*/
|
||
IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
|
||
@Override
|
||
public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
|
||
LogUtils.d("onSurfaceChanged holder : " + holder);
|
||
LogUtils.d("onSurfaceChanged : " + w + " height : " + h);
|
||
if (holder.getRenderView() != mRenderView) {
|
||
LogUtils.e("onSurfaceChanged: unmatched render callback\n");
|
||
return;
|
||
}
|
||
|
||
mSurfaceWidth = w;
|
||
mSurfaceHeight = h;
|
||
boolean isValidState = (mTargetState == STATE_PLAYING);
|
||
boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
|
||
if (mMediaPlayer != null && isValidState && hasValidSize) {
|
||
if (mSeekWhenPrepared != 0) {
|
||
seekTo(mSeekWhenPrepared);
|
||
}
|
||
LogUtils.d("onSurfaceChanged()");
|
||
// 添加一个判断,如果已经在播放了,不要重复起播 -- 21/10/12
|
||
// if(mCurrentState != STATE_PLAYING){
|
||
LogUtils.d("start -- 22 --");
|
||
start();
|
||
// }
|
||
// if (mMediaController != null) {
|
||
// mMediaController.show();
|
||
// LogUtils.d(" mMediaController.show()");
|
||
// }
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
|
||
LogUtils.d("onSurfaceCreated holder : " + holder);
|
||
LogUtils.d("onSurfaceCreated : " + width + " height : " + height);
|
||
if (holder.getRenderView() != mRenderView) {
|
||
LogUtils.e("onSurfaceCreated: unmatched render callback\n");
|
||
return;
|
||
}
|
||
|
||
mSurfaceHolder = holder;
|
||
if (mMediaPlayer != null) {
|
||
LogUtils.d("bindSurfaceHolder : 00 ");
|
||
|
||
bindSurfaceHolder(mMediaPlayer, holder);
|
||
} else {
|
||
LogUtils.d("openVideo : 00 ");
|
||
openVideo();
|
||
}
|
||
|
||
}
|
||
|
||
@Override
|
||
public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
|
||
LogUtils.d("onSurfaceDestroyed : 00 " + holder);
|
||
if (holder.getRenderView() != mRenderView) {
|
||
LogUtils.e("onSurfaceDestroyed: unmatched render callback\n");
|
||
return;
|
||
}
|
||
|
||
// after we return from this we can't use the surface any more
|
||
mSurfaceHolder = null;
|
||
// REMOVED: if (mMediaController != null) mMediaController.hide();
|
||
// REMOVED: release(true);
|
||
releaseWithoutStop();
|
||
}
|
||
};
|
||
|
||
public void releaseWithoutStop() {
|
||
if (mMediaPlayer != null) {
|
||
mMediaPlayer.stop();
|
||
mMediaPlayer.setDisplay(null);
|
||
}
|
||
}
|
||
|
||
private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
|
||
if (mp == null) {
|
||
LogUtils.d("bindSurfaceHolder -- mp -- " + mp);
|
||
return;
|
||
}
|
||
|
||
if (holder == null) {
|
||
LogUtils.d("bindSurfaceHolder -- holder -- " + holder);
|
||
mp.setDisplay(null);
|
||
return;
|
||
}
|
||
|
||
holder.bindToMediaPlayer(mp);
|
||
}
|
||
|
||
// ************************* 画布Callback **********************************//
|
||
|
||
// ******************************播放器Callbak*****************************************//
|
||
|
||
IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
|
||
public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
|
||
LogUtils.d("OnVideoSizeChangedListener --- IMediaPlayer = " + mp);
|
||
try {
|
||
if (mp != null) {
|
||
mVideoWidth = mp.getVideoWidth();
|
||
mVideoHeight = mp.getVideoHeight();
|
||
mVideoSarNum = mp.getVideoSarNum();
|
||
mVideoSarDen = mp.getVideoSarDen();
|
||
LogUtils.d(
|
||
"OnVideoSizeChangedListener --- mVideoWidth = " + mVideoWidth + "-- mVideoHeight -- : "
|
||
+ mVideoHeight + "-- mVideoSarNum -- : " + mVideoSarNum + "-- mVideoSarDen -- : "
|
||
+ mVideoSarDen);
|
||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||
if (mRenderView != null) {
|
||
mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
|
||
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
|
||
}
|
||
// REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
|
||
LogUtils.d("OnVideoSizeChangedListener()");
|
||
requestLayout();
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
LogUtils.e("OnVideoSizeChangedListener --- IMediaPlayer = " + mp);
|
||
}
|
||
}
|
||
};
|
||
|
||
IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
|
||
public void onPrepared(IMediaPlayer mp) {
|
||
try {
|
||
LogUtils.d("准备好了,开始播放了。");
|
||
|
||
mCurrentState = STATE_PREPARED;
|
||
mTargetState = STATE_PLAYING;
|
||
// Get the capabilities of the player for this stream
|
||
// REMOVED: Metadata
|
||
|
||
if (mOnPreparedListener != null) {
|
||
mOnPreparedListener.onPrepared(mMediaPlayer);
|
||
}
|
||
if (ConfigPlayer.getInstance().isNeedStartFirstFrame()) {
|
||
if (mOnInfoListener != null) {
|
||
mOnInfoListener.onInfo(mMediaPlayer, 3, 0);
|
||
}
|
||
}
|
||
if (mMediaController != null) {
|
||
mMediaController.setEnabled(true);
|
||
}
|
||
mVideoWidth = mp.getVideoWidth();
|
||
mVideoHeight = mp.getVideoHeight();
|
||
LogUtils.d(
|
||
"onPrepared --- mVideoWidth -- :" + mVideoWidth + "-- mVideoHeight -- :" + mVideoHeight);
|
||
int seekToPosition = 0;
|
||
if (firstPlayPosition != 0) {
|
||
seekTo(firstPlayPosition);
|
||
setFirstPlayPosition(0);
|
||
} else {
|
||
// 定位到上次播放的位置
|
||
seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
|
||
if (seekToPosition != 0) {
|
||
seekTo(seekToPosition);
|
||
}
|
||
}
|
||
if (mVideoWidth != 0 && mVideoHeight != 0) {
|
||
// Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
|
||
// REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
|
||
if (mRenderView != null) {
|
||
mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
|
||
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
|
||
// mRenderView.setVideoRotation(90);
|
||
// Log.i("wxf videowidth",mVideoWidth+" | "+mVideoHeight);
|
||
// Log.i("wxf videosarnum","mVideoSarNum="+mVideoSarNum +" mVideoSarDen="+mVideoSarDen);
|
||
if (!mRenderView.shouldWaitForResize()
|
||
|| mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
|
||
// We didn't actually change the size (it was already at the size
|
||
// we need), so we won't get a "surface changed" callback, so
|
||
// start the video here instead of in the callback.
|
||
if (mTargetState == STATE_PLAYING) {
|
||
LogUtils.d("start -- 11 --");
|
||
start();
|
||
// if (mMediaController != null) {
|
||
// if (null != mMediaController && mCurrentMode != MODE_TINY_WINDOW) {
|
||
// mMediaController.show();
|
||
// }
|
||
// }
|
||
} else if (!isPlaying() && (seekToPosition != 0 || getCurrentPosition() > 0)) {
|
||
// if (mMediaController != null && mCurrentMode != MODE_TINY_WINDOW) {
|
||
// // Show the media controls when we're paused into a video and make 'em stick.
|
||
// mMediaController.show(0);
|
||
// }
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// We don't know the video size yet, but should start anyway.
|
||
// The video size might be reported to us later.
|
||
if (mTargetState == STATE_PLAYING) {
|
||
LogUtils.d("start -- 00 --");
|
||
start();
|
||
// if (mMediaController != null) {
|
||
// mMediaController.show();
|
||
// LogUtils.d( "toggleMediaControlsVisiblity()");
|
||
// }
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
LogUtils.e("OnVideoSizeChangedListener --- IMediaPlayer = " + mp);
|
||
}
|
||
}
|
||
};
|
||
|
||
private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() {
|
||
public void onCompletion(IMediaPlayer mp) {
|
||
mCurrentState = STATE_PLAYBACK_COMPLETED;
|
||
mTargetState = STATE_PLAYBACK_COMPLETED;
|
||
if (mMediaController != null) {
|
||
mMediaController.hide();
|
||
}
|
||
if (mOnCompletionListener != null) {
|
||
mOnCompletionListener.onCompletion(mMediaPlayer);
|
||
}
|
||
}
|
||
};
|
||
|
||
private IMediaPlayer.OnInfoListener mInfoListener = new IMediaPlayer.OnInfoListener() {
|
||
public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
|
||
if (mOnInfoListener != null) {
|
||
mOnInfoListener.onInfo(mp, arg1, arg2);
|
||
}
|
||
// LogUtils.d( "mediaInfo - arg1: " + arg1);
|
||
// LogUtils.d( "mediaInfo - arg2: " + arg2);
|
||
// switch (arg1) {
|
||
// case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
|
||
// LogUtils.d( "MEDIA_INFO_VIDEO_TRACK_LAGGING:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
|
||
// LogUtils.d( "MEDIA_INFO_VIDEO_RENDERING_START:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
|
||
// LogUtils.d( "MEDIA_INFO_BUFFERING_START:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
|
||
// LogUtils.d( "MEDIA_INFO_BUFFERING_END:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:
|
||
// LogUtils.d( "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2);
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
|
||
// LogUtils.d( "MEDIA_INFO_BAD_INTERLEAVING:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
|
||
// LogUtils.d( "MEDIA_INFO_NOT_SEEKABLE:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE:
|
||
// LogUtils.d( "MEDIA_INFO_METADATA_UPDATE:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:
|
||
// LogUtils.d( "MEDIA_INFO_UNSUPPORTED_SUBTITLE:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:
|
||
// LogUtils.d( "MEDIA_INFO_SUBTITLE_TIMED_OUT:");
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
|
||
// //mVideoRotationDegree = arg2;
|
||
// LogUtils.d( "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2);
|
||
// if (mRenderView != null)
|
||
// mRenderView.setVideoRotation(arg2);
|
||
// break;
|
||
// case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
|
||
// LogUtils.d( "MEDIA_INFO_AUDIO_RENDERING_START:");
|
||
// break;
|
||
// default:
|
||
// // throw new IllegalStateException("Unexpected value: " + arg1);
|
||
// }
|
||
return true;
|
||
}
|
||
};
|
||
|
||
private IMediaPlayer.OnErrorListener mErrorListener = new IMediaPlayer.OnErrorListener() {
|
||
public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
|
||
LogUtils.d("Error: " + framework_err + "," + impl_err);
|
||
mCurrentState = STATE_ERROR;
|
||
mTargetState = STATE_ERROR;
|
||
if (mMediaController != null) {
|
||
mMediaController.hide();
|
||
}
|
||
|
||
/* If an error handler has been supplied, use it and finish. */
|
||
if (mOnErrorListener != null) {
|
||
if (impl_err == 3516 || impl_err == 3515) {
|
||
// 组播切单播,组播播放报错,切单播
|
||
framework_err = impl_err;
|
||
}
|
||
if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Otherwise, pop up an error dialog so the user knows that
|
||
* something bad has happened. Only try and pop up the dialog
|
||
* if we're attached to a window. When we're going away and no
|
||
* longer have a window, don't bother showing the user an error.
|
||
*/
|
||
// if (getWindowToken() != null) {
|
||
// Resources r = getContext().getResources();
|
||
// int messageId;
|
||
//
|
||
// if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
|
||
// messageId = R.string.VideoView_error_text_invalid_progressive_playback;
|
||
// } else {
|
||
// messageId = R.string.VideoView_error_text_unknown;
|
||
// }
|
||
//
|
||
// new AlertDialog.Builder(getContext())
|
||
// .setMessage(messageId)
|
||
// .setPositiveButton(R.string.VideoView_error_button,
|
||
// new DialogInterface.OnClickListener() {
|
||
// public void onClick(DialogInterface dialog, int whichButton) {
|
||
// /* If we get here, there is no onError listener, so
|
||
// * at least inform them that the video is over.
|
||
// */
|
||
// if (mOnCompletionListener != null) {
|
||
// mOnCompletionListener.onCompletion(mMediaPlayer);
|
||
// }
|
||
// }
|
||
// })
|
||
// .setCancelable(false)
|
||
// .show();
|
||
// }
|
||
return true;
|
||
}
|
||
};
|
||
|
||
private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
|
||
new IMediaPlayer.OnBufferingUpdateListener() {
|
||
public void onBufferingUpdate(IMediaPlayer mp, int percent) {
|
||
mCurrentBufferPercentage = percent;
|
||
LogUtils.d("onBufferingUpdate ---- : "+percent);
|
||
// if (mOnBufferingUpdateListener != null) {
|
||
// mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
|
||
// }
|
||
}
|
||
};
|
||
|
||
private IMediaPlayer.OnSeekCompleteListener seekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
|
||
@Override
|
||
public void onSeekComplete(IMediaPlayer mp) {
|
||
|
||
}
|
||
};
|
||
|
||
// 暂停
|
||
public interface IOnPauseListener {
|
||
public void onPause();
|
||
}
|
||
|
||
// 继续播放
|
||
public interface IOnResumeListener {
|
||
public void onResume();
|
||
}
|
||
// ************************************播放器Callbak***********************************//
|
||
|
||
/// ** 媒体控制器 MediaPlayerControl **////
|
||
|
||
/**
|
||
* MediaPlayerControl的start() 方法
|
||
* 播放
|
||
*/
|
||
@Override
|
||
public void start() {
|
||
LogUtils.d(
|
||
"start: " + " mMediaPlayer != null " + (mMediaPlayer != null) + ": mCurrentState: " + mCurrentState);
|
||
if (isInPlaybackState()) {
|
||
//
|
||
LogUtils.d("点击了播放 : " + mCurrentState);
|
||
mMediaPlayer.start();
|
||
mCurrentState = STATE_PLAYING;
|
||
|
||
LogUtils.d("start()");
|
||
// if (null != mMediaController && mCurrentMode != MODE_TINY_WINDOW) {
|
||
// mMediaController.show();
|
||
// }
|
||
}
|
||
mTargetState = STATE_PLAYING;
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的pause() 方法
|
||
* 暂定
|
||
*/
|
||
@Override
|
||
public void pause() {
|
||
try {
|
||
if (isInPlaybackState()) {
|
||
if (mMediaPlayer.isPlaying()) {
|
||
LogUtils.d("pause : ");
|
||
mMediaPlayer.pause();
|
||
mCurrentState = STATE_PAUSED;
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
mTargetState = STATE_PAUSED;
|
||
// mMediaController.hide();
|
||
// if (null != mMediaController) {
|
||
// mMediaController.show(0);
|
||
// }
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的pause() 方法
|
||
* 暂定
|
||
*/
|
||
public void pause(boolean isShow) {
|
||
if (isInPlaybackState()) {
|
||
if (mMediaPlayer.isPlaying()) {
|
||
mMediaPlayer.pause();
|
||
mCurrentState = STATE_PAUSED;
|
||
}
|
||
}
|
||
mTargetState = STATE_PAUSED;
|
||
// mMediaController.hide();
|
||
if (isShow) {
|
||
mMediaController.show(0);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的getDuration方法
|
||
* 时长
|
||
*/
|
||
@Override
|
||
public int getDuration() {
|
||
/**
|
||
* 会有出现一直error -38 报错的情况,
|
||
* Attempt to call getDuration without a valid mediaplayer
|
||
* 改 isInPlaybackState 为 isInOperation
|
||
*/
|
||
|
||
if (isInOperation()) {
|
||
// if(isLive == 1){
|
||
// return 14400 * 1000;
|
||
// }
|
||
LogUtils.d("getDuration:" + mCurrentState);
|
||
return (int) mMediaPlayer.getDuration();
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的getCurrentPosition方法
|
||
* 播放位置
|
||
*/
|
||
@Override
|
||
public int getCurrentPosition() {
|
||
if (isInOperation()) {
|
||
// if(isLive == 1){
|
||
// return 14400 * 1000;
|
||
// }
|
||
LogUtils.d("getCurrentPosition:" + mCurrentState);
|
||
return (int) mMediaPlayer.getCurrentPosition();
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 获取对应播放进度
|
||
*
|
||
* @return 返回进度
|
||
* @throws Exception 获取异常
|
||
*/
|
||
public long getMediaPlayerCurrentPosition() throws Exception {
|
||
return mMediaPlayer.getCurrentPosition();
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的seekTo方法
|
||
* 播放位置
|
||
*/
|
||
@Override
|
||
public void seekTo(int msec) {
|
||
try {
|
||
if (isInPlaybackState()) {
|
||
LogUtils.d("seekTo : " + mCurrentState);
|
||
Log.i("wxf", "seekto====" + msec);
|
||
mMediaPlayer.seekTo(msec);
|
||
mSeekWhenPrepared = 0;
|
||
} else {
|
||
mSeekWhenPrepared = msec;
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
public void seekTo(int msec,boolean isPause) {
|
||
try {
|
||
if (isInPlaybackState()) {
|
||
LogUtils.d("seekTo : " + mCurrentState);
|
||
Log.i("wxf", "seekto====" + msec);
|
||
mMediaPlayer.pause();
|
||
mMediaPlayer.seekTo(msec);
|
||
mSeekWhenPrepared = 0;
|
||
} else {
|
||
mSeekWhenPrepared = msec;
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
public boolean isSwitchDirectionEnable() {
|
||
if (mCurrentState == STATE_PLAYING || mCurrentState == STATE_PREPARING || mCurrentState == STATE_PREPARED) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的isPlaying()方法
|
||
* 判断是否正在播放
|
||
*/
|
||
@Override
|
||
public boolean isPlaying() {
|
||
try {
|
||
return isInPlaybackState() && mMediaPlayer.isPlaying();
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* MediaPlayerControl的getBufferPercentage方法
|
||
* 缓冲
|
||
*/
|
||
@Override
|
||
public int getBufferPercentage() {
|
||
if (mMediaPlayer != null) {
|
||
return mCurrentBufferPercentage;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/***
|
||
* 不销毁播放器,切换到另一个频道
|
||
*/
|
||
public void switchChannel(String channelUrl) {
|
||
if (mMediaPlayer != null) {
|
||
try {
|
||
// mMediaPlayer.stop();
|
||
mMediaPlayer.reset();
|
||
mUri = Uri.parse(channelUrl);
|
||
mMediaPlayer.setOnPreparedListener(mPreparedListener);
|
||
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
|
||
mMediaPlayer.setOnCompletionListener(mCompletionListener);
|
||
mMediaPlayer.setOnErrorListener(mErrorListener);
|
||
mMediaPlayer.setOnInfoListener(mInfoListener);
|
||
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
|
||
mMediaPlayer.setOnSeekCompleteListener(seekCompleteListener);
|
||
mCurrentBufferPercentage = 0;
|
||
mMediaPlayer.setDataSource(getContext(), mUri, mHeaders);
|
||
bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
|
||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||
mMediaPlayer.setScreenOnWhilePlaying(true);
|
||
mMediaPlayer.prepareAsync();
|
||
/*
|
||
* if (mHudViewHolder != null)
|
||
* mHudViewHolder.setMediaPlayer(mMediaPlayer);
|
||
*/
|
||
|
||
// REMOVED: mPendingSubtitleTracks
|
||
|
||
// we don't set the target state here either, but preserve the
|
||
// target state that was there before.
|
||
mCurrentState = STATE_PREPARING;
|
||
// attachMediaController();
|
||
// if (null != mMediaController && mCurrentMode !=MODE_TINY_WINDOW) {
|
||
// mMediaController.show();
|
||
// }
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
mCurrentState = STATE_ERROR;
|
||
mTargetState = STATE_ERROR;
|
||
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 判断是否可以暂停
|
||
*/
|
||
@Override
|
||
public boolean canPause() {
|
||
return mCanPause;
|
||
}
|
||
|
||
/**
|
||
* 判断是否可以倒退
|
||
*/
|
||
@Override
|
||
public boolean canSeekBackward() {
|
||
return mCanSeekBack;
|
||
}
|
||
|
||
/**
|
||
* 判断是否可以前进
|
||
*/
|
||
@Override
|
||
public boolean canSeekForward() {
|
||
return mCanSeekForward;
|
||
}
|
||
|
||
/**
|
||
* 获取当前模式
|
||
*/
|
||
@Override
|
||
public int getCurrentMode() {
|
||
return mCurrentMode;
|
||
}
|
||
public void setCurrentMode(int mCurrentMode) {
|
||
this.mCurrentMode = mCurrentMode;
|
||
}
|
||
|
||
/**
|
||
* 设置视频显示方式
|
||
**/
|
||
public void setmCurrentAspectRatio(int mCurrentAspectRatio) {
|
||
this.mCurrentAspectRatio = mCurrentAspectRatio;
|
||
if (mRenderView != null) {
|
||
mRenderView.setAspectRatio(mCurrentAspectRatio);
|
||
}
|
||
}
|
||
|
||
public void setmVideoWidth(int mVideoWidth) {
|
||
this.mVideoWidth = mVideoWidth;
|
||
}
|
||
|
||
public void setmVideoHeight(int mVideoHeight) {
|
||
Log.d("onSurfaceChanged -- ", "setmVideoHeight -- " + mVideoHeight);
|
||
this.mVideoHeight = mVideoHeight;
|
||
// setLayoutParams(new RelativeLayout.LayoutParams(mVideoWidth,this.mVideoWidth));
|
||
// if (mRenderView != null) {
|
||
// mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
|
||
// }
|
||
// requestLayout();
|
||
// //重新绘制画面
|
||
// invalidate();
|
||
}
|
||
|
||
/**
|
||
* 设置播放器的位置和宽高并刷新重新绘制画面
|
||
*/
|
||
public void setVideoPositionSize() {
|
||
// if (mRenderView != null) {
|
||
// mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
|
||
// }
|
||
requestLayout();
|
||
// 重新绘制画面
|
||
invalidate();
|
||
}
|
||
|
||
/**
|
||
* 区分是直播还是点播
|
||
* 直播 1 点播 0
|
||
*/
|
||
public void setIsLive(int isLive) {
|
||
this.isLive = isLive;
|
||
}
|
||
|
||
/// ** 媒体控制器 MediaPlayerControl **////
|
||
|
||
public void setmOnCompletionListener(IMediaPlayer.OnCompletionListener mOnCompletionListener) {
|
||
this.mOnCompletionListener = mOnCompletionListener;
|
||
}
|
||
|
||
public void setmSizeChangedListener(IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener) {
|
||
this.mSizeChangedListener = mSizeChangedListener;
|
||
}
|
||
|
||
public void setmPreparedListener(IMediaPlayer.OnPreparedListener mPreparedListener) {
|
||
this.mOnPreparedListener = mPreparedListener;
|
||
}
|
||
|
||
public void setmCompletionListener(IMediaPlayer.OnCompletionListener mCompletionListener) {
|
||
this.mCompletionListener = mCompletionListener;
|
||
}
|
||
|
||
public void setmInfoListener(IMediaPlayer.OnInfoListener mInfoListener) {
|
||
this.mOnInfoListener = mInfoListener;
|
||
}
|
||
|
||
public void setmErrorListener(IMediaPlayer.OnErrorListener mErrorListener) {
|
||
this.mErrorListener = mErrorListener;
|
||
}
|
||
|
||
public void setmBufferingUpdateListener(IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener) {
|
||
this.mBufferingUpdateListener = mBufferingUpdateListener;
|
||
}
|
||
|
||
public void setmSeekListener(IMediaPlayer.OnSeekCompleteListener seekListener) {
|
||
this.seekCompleteListener = seekListener;
|
||
}
|
||
|
||
public void setIOnPauseListener(IOnPauseListener onPauseListener) {
|
||
this.onPauseListener = onPauseListener;
|
||
}
|
||
|
||
public void setIOnResumeListener(IOnResumeListener onResumeListener) {
|
||
this.onResumeListener = onResumeListener;
|
||
}
|
||
|
||
public void removeListener(){
|
||
LogUtils.d("removeListener() ====");
|
||
mOnCompletionListener = null;
|
||
mSizeChangedListener = null;
|
||
mOnPreparedListener = null;
|
||
mCompletionListener = null;
|
||
mOnInfoListener = null;
|
||
mErrorListener = null;
|
||
mBufferingUpdateListener = null;
|
||
seekCompleteListener = null;
|
||
onPauseListener = null;
|
||
onResumeListener = null;
|
||
if(mMediaPlayer != null){
|
||
if(mMediaPlayer instanceof PkExoMediaPlayer){
|
||
PkExoMediaPlayer pkExoMediaPlayer = (PkExoMediaPlayer)mMediaPlayer;
|
||
pkExoMediaPlayer.resetListeners();
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 获取当前mediaplayer
|
||
*/
|
||
public IMediaPlayer getMediaPlayerName() {
|
||
if (mMediaPlayer != null) {
|
||
return mMediaPlayer;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 返回正在播放的url
|
||
*
|
||
* @return
|
||
*/
|
||
public String getUrl() {
|
||
if (mUri != null) {
|
||
return String.valueOf(mUri);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 设置是否循环播放
|
||
*/
|
||
public void setLoopPlay() {
|
||
if (mMediaPlayer != null) {
|
||
mMediaPlayer.setLooping(true);
|
||
}
|
||
}
|
||
|
||
public void setLoopPlay(boolean isLoop) {
|
||
if (mMediaPlayer != null) {
|
||
mMediaPlayer.setLooping(isLoop);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清除掉surfaceView
|
||
*/
|
||
public void clearSurfaceView() {
|
||
try {
|
||
if (mRenderView != null) {
|
||
LogUtils.d("clearSurfaceView -- : " + mRenderView);
|
||
View renderUIView = mRenderView.getView();
|
||
mRenderView.removeRenderCallback(mSHCallback);
|
||
LogUtils.d("clearSurfaceView --renderUIView-- : " + renderUIView);
|
||
LogUtils.d("clearSurfaceView --this-- : " + this);
|
||
if (renderUIView != null) {
|
||
removeView(renderUIView);
|
||
}
|
||
mRenderView = null;
|
||
mSurfaceHolder = null;
|
||
}
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
public void surfaceHolderIsNull(){
|
||
LogUtils.d("surfaceHolderIsNull path: " + mUri.getPath());
|
||
LogUtils.d("surfaceHolderIsNull mSurfaceHolder: " + mSurfaceHolder);
|
||
LogUtils.d("surfaceHolderIsNull mRenderView: " + mRenderView);
|
||
if (mSurfaceHolder==null){
|
||
setVideoPath(mUri.getPath());
|
||
}
|
||
}
|
||
|
||
public void setSpeed(float speed){
|
||
if(mMediaPlayer != null) {
|
||
mMediaPlayer.setSpeed(speed);
|
||
}
|
||
}
|
||
|
||
public float getSpeed(){
|
||
if(mMediaPlayer != null) {
|
||
return mMediaPlayer.getSpeed();
|
||
}else{
|
||
return 0f;
|
||
}
|
||
}
|
||
}
|