Files
jiecheng-business/mediaplayertv/src/main/java/com/pukka/videoplayertv/VideoViewTv.java
zhaogd d11464d466 基线备份:thirdparty 变体完成 + Android 4.2 兼容改造前
包含内容:
- thirdparty flavor 独立 applicationId + Intent 入口(ThirdPartyEntryActivity)
- 58 后端接口适配(单 /api 路径、code 0/200、camelCase 字段、UNBOUND 轮询)
- MAC 硬件锚定校验(防一凭证多设备共用)
- EPG mac 覆盖 SDK init(sMacOverride)+ ChannelManger 初始化对齐
- 提示文案优化(设备未注册/权益未绑定)
2026-08-25 11:16:40 +08:00

1584 lines
54 KiB
Java
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}