1.ijkplayer簡介
ijkplayer是一個基于FFmpeg的輕量級Android/iOS視訊播放器。FFmpeg的是全球領先的多媒體架構,能夠解碼,編碼, 轉碼,複用,解複用,流,過濾器和播放大部分的視訊格式。它提供了錄制、轉換以及流化音視訊的完整解決方案。它包含了非常先進的音頻/視訊編解碼庫libavcodec,為了保證高可移植性和編解碼品質,libavcodec裡很多code都是從頭開發的。
2.功能的展示
支援橫豎屏切換展示,上下滑動聲音亮度的調節等功能。
3. androidStudio 接入
1)添加.so庫:
如圖所示:将.so檔案添加到自己的項目中:
2)在Gradle中添加依賴:
// Bili required, enough for most devices.
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
compile 'pub.devrel:easypermissions:1.0.1'
3)開始代碼的實作
1.建立一個類CusIjkView,繼承frameLayout,(自定義播放器樣式)
代碼如下:
// 列印日志的TAG
private String TAG = this.getClass().getSimpleName();
// mCurrentState is a object's current state.
private int mCurrentState = PlayStateParams.STATE_IDLE;
// 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 mTargetState = PlayStateParams.STATE_IDLE;
// 播放位址通過用戶端可設定
private Uri mUri;
// 播放器的一些基本配置
private Map<String, String> mHeaders;
// 所有我們需要播放和顯示視訊的東西
private IRenderView.ISurfaceHolder mSurfaceHolder = null;
// 視訊寬度
private int mVideoWidth;
// 視訊高度
private int mVideoHeight;
// 視窗寬度
private int mSurfaceWidth;
// 視窗高度
private int mSurfaceHeight;
// 視訊旋轉角度
private int mVideoRotationDegree;
// 媒體播放器
private IMediaPlayer mMediaPlayer;
// 媒體控制器
private IMediaController mMediaController;
// 播放完成監聽
private IMediaPlayer.OnCompletionListener mOnCompletionListener;
// 播放準備監聽
private IMediaPlayer.OnPreparedListener mOnPreparedListener;
// 播放緩沖監聽
private int mCurrentBufferPercentage;
// 播放錯誤監聽
private IMediaPlayer.OnErrorListener mOnErrorListener;
// 播放其他資訊監聽
private IMediaPlayer.OnInfoListener mOnInfoListener;
// 為記錄seek位置而做準備
private long mSeekWhenPrepared;
private Context mAppContext;
private IRenderView mRenderView;
private int mVideoSarNum;
private int mVideoSarDen;
// Extend: Aspect Ratio
private static final int[] s_allAspectRatio = {
IRenderView.AR_ASPECT_FIT_PARENT,
IRenderView.AR_ASPECT_FILL_PARENT,
IRenderView.AR_ASPECT_WRAP_CONTENT,
IRenderView.AR_MATCH_PARENT,
IRenderView.AR_16_9_FIT_PARENT,
IRenderView.AR_4_3_FIT_PARENT};
private int mCurrentAspectRatioIndex = 0;
private int mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
// Extend: Render
public static final int RENDER_SURFACE_VIEW = 1;
public static final int RENDER_TEXTURE_VIEW = 2;
private List<Integer> mAllRenders = new ArrayList<>();
// 使用編解碼器寫死還是軟編碼,true 寫死 false 為軟編碼
private boolean usingMediaCodec;
// 使用編解碼是否自轉
private boolean usingMediaCodecAutoRotate;
private boolean usingAndroidPlayer;
private boolean usingOpenSLES;
private boolean enableBackgroundPlay;
public CusIjkView(Context context) {
super(context);
initVideoView(context);
}
public CusIjkView(Context context, AttributeSet attrs) {
super(context, attrs);
initVideoView(context);
}
public CusIjkView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initVideoView(context);
}
/**
* 初始化視訊view
*/
private void initVideoView(Context context) {
mAppContext = context.getApplicationContext();
initRenders();
mVideoWidth = 0;
mVideoHeight = 0;
// 設定為可觸摸并且擷取焦點
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
mCurrentState = PlayStateParams.STATE_IDLE;
mTargetState = PlayStateParams.STATE_IDLE;
}
/**
* 設定渲染器
*/
public void setRenderView(IRenderView renderView) {
if (mRenderView != null) {
if (mMediaPlayer != null) {
mMediaPlayer.setDisplay(null);
}
View renderUIView = mRenderView.getView();
mRenderView.removeRenderCallback(mSHCallback);
mRenderView = null;
removeView(renderUIView);
}
if (renderView == null)
return;
mRenderView = renderView;
renderView.setAspectRatio(mCurrentAspectRatio);
if (mVideoWidth > 0 && mVideoHeight > 0)
renderView.setVideoSize(mVideoWidth, mVideoHeight);
if (mVideoSarNum > 0 && mVideoSarDen > 0)
renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
View renderUIView = mRenderView.getView();
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
renderUIView.setLayoutParams(lp);
addView(renderUIView);
mRenderView.addRenderCallback(mSHCallback);
mRenderView.setVideoRotation(mVideoRotationDegree);
}
/**
* 設定旋轉角度
*/
public void setPlayerRotation(int rotation) {
mVideoRotationDegree = rotation;
if (mRenderView != null) {
mRenderView.setVideoRotation(mVideoRotationDegree);
}
}
/**
* 旋轉渲染器
*/
public void setRender(int render) {
switch (render) {
case RENDER_TEXTURE_VIEW: {
TextureRenderView renderView = new TextureRenderView(getContext());
if (mMediaPlayer != null) {
renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);
renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());
renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());
renderView.setAspectRatio(mCurrentAspectRatio);
}
setRenderView(renderView);
break;
}
case RENDER_SURFACE_VIEW: {
SurfaceRenderView renderView = new SurfaceRenderView(getContext());
setRenderView(renderView);
break;
}
default:
Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
break;
}
}
/**
* 設定視訊路徑
*/
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
/**
* 設定視訊URI
*/
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 stopPlayback() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = PlayStateParams.STATE_IDLE;
mTargetState = PlayStateParams.STATE_IDLE;
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
if (am != null) {
am.abandonAudioFocus(null);
}
}
}
/**
* 打開視訊
*/
private void openVideo() {
if (mUri == null || mSurfaceHolder == null) {
return;
}
release(false);
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
if (am != null) {
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
try {
if (usingAndroidPlayer) {
mMediaPlayer = new AndroidMediaPlayer();
} else {
IjkMediaPlayer ijkMediaPlayer = null;
if (mUri != null) {
ijkMediaPlayer = new IjkMediaPlayer();
IjkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
if (usingMediaCodec) {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
if (usingMediaCodecAutoRotate) {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
} else {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
}
} else {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
}
if (usingOpenSLES) {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
} else {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
}
// Auto Select=,RGB 565=fcc-rv16,RGB 888X=fcc-rv32,YV12=fcc-yv12,預設為RGB 888X
String pixelFormat = "";
if (TextUtils.isEmpty(pixelFormat)) {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
} else {
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
}
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", 10000000);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
}
mMediaPlayer = ijkMediaPlayer;
}
if (enableBackgroundPlay) {
mMediaPlayer = new TextureMediaPlayer(mMediaPlayer);
}
if (mMediaPlayer == null) {
return;
}
// 視訊準備播放監聽
mMediaPlayer.setOnPreparedListener(mPreparedListener);
// 視訊播放完成監聽
mMediaPlayer.setOnCompletionListener(mCompletionListener);
// 視訊錯誤監聽
mMediaPlayer.setOnErrorListener(mErrorListener);
// 視訊其他資訊監聽
mMediaPlayer.setOnInfoListener(mInfoListener);
// 視訊界面大小改變監聽
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
// 視訊緩沖監聽
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
String scheme = mUri.getScheme();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& usingAndroidPlayer && (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
IMediaDataSource dataSource = new FileMediaDataSource(new File(mUri.toString()));
mMediaPlayer.setDataSource(dataSource);
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
} else {
mMediaPlayer.setDataSource(mUri.toString());
}
bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
// 這裡不設定目标狀态,但保護的目标狀态
mCurrentState = PlayStateParams.STATE_PREPARING;
attachMediaController();
} catch (IOException | IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
mCurrentState = PlayStateParams.STATE_ERROR;
mTargetState = PlayStateParams.STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
}
}
public void setMediaController(IMediaController controller) {
if (mMediaController != null) {
mMediaController.hide();
}
mMediaController = controller;
attachMediaController();
}
private void attachMediaController() {
if (mMediaPlayer != null && mMediaController != null) {
mMediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ? (View) this.getParent() : this;
mMediaController.setAnchorView(anchorView);
mMediaController.setEnabled(isInPlaybackState());
}
}
IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
mVideoSarNum = mp.getVideoSarNum();
mVideoSarDen = mp.getVideoSarDen();
if (mVideoWidth != 0 && mVideoHeight != 0) {
if (mRenderView != null) {
mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
}
requestLayout();
}
}
};
IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
public void onPrepared(IMediaPlayer mp) {
// 這裡不設定目标狀态,但保護的目标狀态
mCurrentState = PlayStateParams.STATE_PREPARED;
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
if (mMediaController != null) {
mMediaController.setEnabled(true);
}
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mMediaPlayer, mCurrentState, 0);
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
long seekToPosition = mSeekWhenPrepared;
if (seekToPosition != 0) {
seekTo((int) seekToPosition);
}
if (mVideoWidth != 0 && mVideoHeight != 0) {
if (mRenderView != null) {
mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
if (mTargetState == PlayStateParams.STATE_PLAYING) {
start();
if (mMediaController != null) {
mMediaController.show();
}
} else if (!isPlaying() &&
(seekToPosition != 0 || getCurrentPosition() > 0)) {
if (mMediaController != null) {
mMediaController.show(0);
}
}
}
}
} else {
if (mTargetState == PlayStateParams.STATE_PLAYING) {
start();
}
}
}
};
private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() {
public void onCompletion(IMediaPlayer mp) {
mCurrentState = PlayStateParams.STATE_COMPLETED;
mTargetState = PlayStateParams.STATE_COMPLETED;
if (mMediaController != null) {
mMediaController.hide();
}
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mMediaPlayer, PlayStateParams.STATE_COMPLETED, 0);
}
}
};
private IMediaPlayer.OnInfoListener mInfoListener = new IMediaPlayer.OnInfoListener() {
public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mp, arg1, arg2);
}
switch (arg1) {
case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING:");
break;
case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START:");
break;
case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
Log.d(TAG, "MEDIA_INFO_BUFFERING_START:");
break;
case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
Log.d(TAG, "MEDIA_INFO_BUFFERING_END:");
break;
case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:
Log.d(TAG, "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2);
break;
case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING:");
break;
case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE:");
break;
case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE:
Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE:");
break;
case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:
Log.d(TAG, "MEDIA_INFO_UNSUPPORTED_SUBTITLE:");
break;
case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:
Log.d(TAG, "MEDIA_INFO_SUBTITLE_TIMED_OUT:");
break;
case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
mVideoRotationDegree = arg2;
Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2);
if (mRenderView != null)
mRenderView.setVideoRotation(arg2);
break;
case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
Log.d(TAG, "MEDIA_INFO_AUDIO_RENDERING_START:");
break;
}
return true;
}
};
private IMediaPlayer.OnErrorListener mErrorListener = new IMediaPlayer.OnErrorListener() {
public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
Log.d(TAG, "Error: " + framework_err + "," + impl_err);
mCurrentState = PlayStateParams.STATE_ERROR;
mTargetState = PlayStateParams.STATE_ERROR;
if (mMediaController != null) {
mMediaController.hide();
}
if (mOnErrorListener != null) {
mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err);
}
if (mOnInfoListener != null) {
if (mOnInfoListener.onInfo(mMediaPlayer, framework_err, 0)) {
return true;
}
}
if (getWindowToken() != null) {
String message = "Unknown error";
if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
message = "Invalid progressive playback";
}
new AlertDialog.Builder(getContext())
.setMessage(message)
.setPositiveButton("error", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
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;
}
};
/**
* Register a callback to be invoked when the media file is loaded and ready to go.
*/
public void setOnPreparedListener(IMediaPlayer.OnPreparedListener listener) {
mOnPreparedListener = listener;
}
/**
* Register a callback to be invoked when the end of a media file has been reached during playback.
*/
public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) {
mOnCompletionListener = l;
}
/**
* Register a callback to be invoked when an error occurs during playback or setup. If no listener
* is specified, or if the listener returned false, VideoView will inform the user of any errors.
*/
public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {
mOnErrorListener = l;
}
/**
* Register a callback to be invoked when an informational event occurs during playback or setup.
*/
public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {
mOnInfoListener = l;
}
private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
if (mp == null)
return;
if (holder == null) {
mp.setDisplay(null);
return;
}
holder.bindToMediaPlayer(mp);
}
IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
@Override
public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
if (holder.getRenderView() != mRenderView) {
Log.e(TAG, "onSurfaceChanged: unmatched render callback\n");
return;
}
mSurfaceWidth = w;
mSurfaceHeight = h;
boolean isValidState = (mTargetState == PlayStateParams.STATE_PLAYING);
boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
if (mMediaPlayer != null && isValidState && hasValidSize) {
if (mSeekWhenPrepared != 0) {
seekTo((int) mSeekWhenPrepared);
}
start();
}
}
@Override
public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
if (holder.getRenderView() != mRenderView) {
Log.e(TAG, "onSurfaceCreated: unmatched render callback\n");
return;
}
mSurfaceHolder = holder;
if (mMediaPlayer != null)
bindSurfaceHolder(mMediaPlayer, holder);
else
openVideo();
}
@Override
public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
if (holder.getRenderView() != mRenderView) {
Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
return;
}
mSurfaceHolder = null;
releaseWithoutStop();
}
};
public void releaseWithoutStop() {
if (mMediaPlayer != null)
mMediaPlayer.setDisplay(null);
}
/**
* release the media player in any state
*/
public void release(boolean clearTargetState) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = PlayStateParams.STATE_IDLE;
if (clearTargetState) {
mTargetState = PlayStateParams.STATE_IDLE;
}
AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
if (am != null) {
am.abandonAudioFocus(null);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisibility();
}
return false;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisibility();
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK
&& keyCode != KeyEvent.KEYCODE_VOLUME_UP
&& keyCode != KeyEvent.KEYCODE_VOLUME_DOWN
&& keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
&& keyCode != KeyEvent.KEYCODE_MENU
&& keyCode != KeyEvent.KEYCODE_CALL
&& keyCode != KeyEvent.KEYCODE_ENDCALL;
if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (mMediaPlayer.isPlaying()) {
pause();
mMediaController.show();
} else {
start();
mMediaController.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
if (!mMediaPlayer.isPlaying()) {
start();
mMediaController.hide();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
|| keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
if (mMediaPlayer.isPlaying()) {
pause();
mMediaController.show();
}
return true;
} else {
toggleMediaControlsVisibility();
}
}
return super.onKeyDown(keyCode, event);
}
private void toggleMediaControlsVisibility() {
if (mMediaController.isShowing()) {
mMediaController.hide();
} else {
mMediaController.show();
}
}
@Override
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start();
mCurrentState = PlayStateParams.STATE_PLAYING;
}
mTargetState = PlayStateParams.STATE_PLAYING;
}
@Override
public void pause() {
if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
mCurrentState = PlayStateParams.STATE_PAUSED;
}
}
mTargetState = PlayStateParams.STATE_PAUSED;
}
public void onPause() {
release(false);
}
public void onResume() {
openVideo();
}
@Override
public int getDuration() {
if (isInPlaybackState()) {
return (int) mMediaPlayer.getDuration();
}
return -1;
}
@Override
public int getCurrentPosition() {
if (isInPlaybackState()) {
return (int) mMediaPlayer.getCurrentPosition();
}
return 0;
}
@Override
public void seekTo(int msec) {
if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
mSeekWhenPrepared = 0;
} else {
mSeekWhenPrepared = msec;
}
}
@Override
public boolean isPlaying() {
return isInPlaybackState() && mMediaPlayer.isPlaying();
}
@Override
public int getBufferPercentage() {
if (mMediaPlayer != null) {
return mCurrentBufferPercentage;
}
return 0;
}
private boolean isInPlaybackState() {
return (mMediaPlayer != null &&
mCurrentState != PlayStateParams.STATE_ERROR &&
mCurrentState != PlayStateParams.STATE_IDLE &&
mCurrentState != PlayStateParams.STATE_PREPARING);
}
@Override
public boolean canPause() {
return true;
}
@Override
public boolean canSeekBackward() {
return false;
}
@Override
public boolean canSeekForward() {
return false;
}
@Override
public int getAudioSessionId() {
return 0;
}
public void toggleAspectRatio() {
mCurrentAspectRatioIndex++;
mCurrentAspectRatioIndex %= s_allAspectRatio.length;
mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
if (mRenderView != null) {
mRenderView.setAspectRatio(mCurrentAspectRatio);
}
}
/**
* 初始化渲染器
*/
private void initRenders() {
mAllRenders.clear();
mAllRenders.add(RENDER_SURFACE_VIEW); // 添加surface渲染
int mCurrentRenderIndex;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mAllRenders.add(RENDER_TEXTURE_VIEW); // 添加texture渲染
mCurrentRenderIndex = 1;
} else {
mCurrentRenderIndex = 0;
}
int mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
setRender(mCurrentRender);
}
/**
* 設定播放區域拉伸類型
*/
public void setAspectRatio(int aspectRatio) {
for (int i = 0; i < s_allAspectRatio.length; i++) {
if (s_allAspectRatio[i] == aspectRatio) {
mCurrentAspectRatioIndex = i;
if (mRenderView != null) {
mRenderView.setAspectRatio(mCurrentAspectRatio);
}
break;
}
}
}
2.播放器功能的實作類(代碼中有功能的注釋)
// 通知使用的flags
private static final int MESSAGE_SHOW_PROGRESS = 1; // 同步進度
private static final int MESSAGE_SEEK_NEW_POSITION = 3; // 設定新位置
private static final int MESSAGE_HIDE_CENTER_BOX = 4; // 隐藏提示的box
private static final int MESSAGE_RESTART_PLAY = 5; // 重新播放
// 控件部分
private final Activity mActivity; // 依附的容器Activity
private final LayoutQuery mLayoutQuery; // 界面的中布局的查詢器
private final CusIjkView mIjkView; // 原生IjkPlayer
private final View mTopBarView; // 播放器頂部控制bar
private final View mBottomBarView; // 播放器底部控制bar
private final ImageView mThumbnailImg; // 播放前的封面或縮略圖
private final ImageView mBackImage; // 視訊傳回按鈕
private final ImageView mBottomBarPlayerImage; // 視訊bottomBar的播放按鈕
private final ImageView mCenterPlayerImage; // 視訊中間的播放按鈕
private final ImageView mFullScreenImage; // 視訊全屏按鈕
private final TextView mPlayerSpeedTv; // 視訊加載速度
private final SeekBar mProgressSeekBar; // 視訊播放進度條
// 視訊相關參數
private List<VideoIjkBean> mListVideos = new ArrayList<>(); // 碼流清單
private int mCurrStatus = PlayStateParams.STATE_IDLE; // 目前狀态
private int mCurrShowType = PlayStateParams.FIT_PARENT; // 視訊顯示比例,預設保持原視訊的大小
private final AudioManager mAudioManager; // 音頻管理器
private String mCurrVideoUrl; // 目前播放位址
private int mCurrPlayPosition; // 目前播放位置
private long mNewPosition = -1; // 滑動進度條得到的新位置,和目前播放位置是有差別的,mNewPosition =0也會調用設定的,故初始化值為-1
private int mCurrVolume; // 目前聲音大小
private int mMaxVolume = 0; // 裝置最大音量
private final int mScreenWidthPix; // 擷取目前裝置的寬度
private final int mPlayerViewInitHeight; // 記錄播放器豎屏時的高度
private float mCurrBrightness; // 目前亮度大小
private int mBgState; // 記錄進行背景時的播放狀态0為播放,1為暫停
private int mAutoConnectTime = 5000; // 自動重連的時間
private boolean mIsPlayerSupport; // 第三方so是否支援,預設不支援,true為支援
private boolean mIsLive; // 是否是直播,預設為非直播,true為直播false為點播。mIsLive()方法判斷直播的方式比較片面
private boolean mIsForbidTouch; // 禁止觸摸,預設可以觸摸,true為禁止false為可觸摸
private boolean mIsForbidHideControlPanel; // 禁止收起控制台,預設可以收起,true為禁止false為可觸摸
private boolean mIsForbidDoubleUp; // 是否禁止輕按兩下,預設不禁止,true為禁止,false為不禁止
private boolean mIsDragging; // 是否在拖動進度條中,預設為停止拖動,true為在拖動中,false為停止拖動
private boolean mIsErrorStop = true; // 是否出錯停止播放,預設是出錯停止播放,true出錯停止播放,false為使用者點選停止播放
private boolean mIsOnlyFullScreen; // 是否隻有全屏,預設非全屏,true為全屏,false為非全屏
private boolean mIsPortrait = true; // 是否是豎屏,預設為豎屏,true為豎屏,false為橫屏
private boolean mIsAutoReConnect = true; // 是否自動重連,預設5秒重連,true為重連,false為不重連
private boolean mIsHideCenterPlayer; // 是否隐藏中間播放按鈕,預設不隐藏,true為隐藏,false為不隐藏
private boolean mIsHideTopBar; // 是否隐藏topBar,true為隐藏,false為不隐藏
private boolean mIsHideBottomBar; // 是否隐藏bottomBar,true為隐藏,false為不隐藏
private boolean mIsShowControlPanel; // 是否顯示控制台,預設為隐藏,true為顯示false為隐藏
private boolean mIsCharge; // 是否免費觀看
private int mMaxPlaytime; // 設定最大播放時間
private boolean mIsHasSwitchStream; // 目前是否切換視訊流,預設為否,true是切換視訊流,false沒有切換
private boolean mIsNetWorkTip; // 播放時是否有網絡提示,true為顯示網絡提示,false不顯示網絡提示
private boolean mIsFirstPlayer = true; // 是否是第一次播放
// 視訊和UI的回調監聽
private Handler mHandler = new CusUiHandler();
private AutoPlayRunnable mAutoPlayRunnable = new AutoPlayRunnable(); // 控制台收起或者顯示的輪詢監聽
private OnPlayerBackListener mPlayerBack; // 視訊的傳回鍵監聽
private IMediaPlayer.OnInfoListener mOnInfoListener; // 視訊播放時資訊回調
private OrientationEventListener mOrientationEventListener; // Activity界面方向監聽
private OnControlVisibilityChangeListener mOnControlVisibilityChangeListener; // 控制台顯示或隐藏監聽
// ========================================== 初始化 ========================================== //
public PlayerView(Activity activity, View rootView) {
this.mActivity = activity;
try {
IjkMediaPlayer.loadLibrariesOnce(null);
IjkMediaPlayer.native_profileBegin("libijkplayer.so");
mIsPlayerSupport = true;
} catch (Throwable e) {
e.printStackTrace();
}
try {
int e = Settings.System.getInt(mActivity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
float progress = 1.0F * (float) e / 255.0F;
WindowManager.LayoutParams layout = this.mActivity.getWindow().getAttributes();
layout.screenBrightness = progress;
mActivity.getWindow().setAttributes(layout);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
mAudioManager = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE);
if (mAudioManager != null) {
mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
}
// 播放器整個界面
View rootBoxRL;
if (rootView == null) {
mLayoutQuery = new LayoutQuery(mActivity);
rootBoxRL = mActivity.findViewById(R.id.app_video_box);
mIjkView = mActivity.findViewById(R.id.video_view);
mTopBarView = mActivity.findViewById(R.id.app_video_top_box);
mBottomBarView = mActivity.findViewById(R.id.ll_bottom_bar);
mThumbnailImg = mActivity.findViewById(R.id.iv_trumb);
mBackImage = mActivity.findViewById(R.id.app_video_finish);
mBottomBarPlayerImage = mActivity.findViewById(R.id.app_video_play);
mCenterPlayerImage = mActivity.findViewById(R.id.play_icon);
mFullScreenImage = mActivity.findViewById(R.id.app_video_fullscreen);
mPlayerSpeedTv = mActivity.findViewById(R.id.app_video_speed);
mProgressSeekBar = mActivity.findViewById(R.id.app_video_seekBar);
mProgressSeekBar.setMax(1000);
} else {
mLayoutQuery = new LayoutQuery(mActivity, rootView);
rootBoxRL = rootView.findViewById(R.id.app_video_box);
mIjkView = rootView.findViewById(R.id.video_view);
mTopBarView = rootView.findViewById(R.id.app_video_top_box);
mBottomBarView = rootView.findViewById(R.id.ll_bottom_bar);
mThumbnailImg = rootView.findViewById(R.id.iv_trumb);
mBackImage = rootView.findViewById(R.id.app_video_finish);
mBottomBarPlayerImage = rootView.findViewById(R.id.app_video_play);
mCenterPlayerImage = rootView.findViewById(R.id.play_icon);
mFullScreenImage = rootView.findViewById(R.id.app_video_fullscreen);
mPlayerSpeedTv = rootView.findViewById(R.id.app_video_speed);
mProgressSeekBar = rootView.findViewById(R.id.app_video_seekBar);
mProgressSeekBar.setMax(1000);
}
mProgressSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
long duration = getDuration();
int position = (int) ((duration * progress * 1.0) / 1000);
String time = generateTime(position);
mLayoutQuery.id(R.id.app_video_currentTime).text(time);
mLayoutQuery.id(R.id.app_video_currentTime_full).text(time);
mLayoutQuery.id(R.id.app_video_currentTime_left).text(time);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mIsDragging = true;
mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
long duration = getDuration();
mIjkView.seekTo((int) ((duration * seekBar.getProgress() * 1.0) / 1000));
mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);
mIsDragging = false;
mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_PROGRESS, 1000);
}
});
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v.getId() == R.id.app_video_fullscreen) {
toggleFullScreen();
} else if (v.getId() == R.id.app_video_play || v.getId() == R.id.play_icon) {
if (mIjkView.isPlaying()) {
if (mIsLive) {
mIjkView.stopPlayback();
} else {
pausePlay();
}
} else {
startPlay();
if (mIjkView.isPlaying()) {
// TODO ijkPlayer内部的監聽沒有回調,隻能手動修改狀态
mCurrStatus = PlayStateParams.STATE_PREPARING;
hideStatusUI();
}
}
updatePausePlay();
} else if (v.getId() == R.id.app_video_finish) {
backClick();
} else if (v.getId() == R.id.app_video_netTie_icon) {
// 使用移動網絡提示繼續播放
mIsNetWorkTip = false;
hideStatusUI();
startPlay();
updatePausePlay();
} else if (v.getId() == R.id.app_video_replay_icon) {
// 重新播放
mCurrStatus = PlayStateParams.STATE_ERROR;
hideStatusUI();
startPlay();
updatePausePlay();
}
}
};
mBottomBarPlayerImage.setOnClickListener(onClickListener);
mCenterPlayerImage.setOnClickListener(onClickListener);
mFullScreenImage.setOnClickListener(onClickListener);
mBackImage.setOnClickListener(onClickListener);
mLayoutQuery.id(R.id.app_video_netTie_icon).clicked(onClickListener);
mLayoutQuery.id(R.id.app_video_replay_icon).clicked(onClickListener);
mIjkView.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(IMediaPlayer mp, int what, int extra) {
if (what == PlayStateParams.MEDIA_INFO_NETWORK_BANDWIDTH || what == PlayStateParams.MEDIA_INFO_BUFFERING_BYTES_UPDATE) {
if (mPlayerSpeedTv != null) {
mPlayerSpeedTv.setText(getFormatSize(extra));
}
}
statusChange(what);
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mp, what, extra);
}
if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
mLayoutQuery.id(R.id.app_video_freeTie).visible();
pausePlay();
}
return true;
}
});
final GestureDetector detector = new GestureDetector(mActivity, new PlayerGestureListener());
rootBoxRL.setClickable(true);
rootBoxRL.setOnTouchListener(new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (mAutoPlayRunnable != null) {
mAutoPlayRunnable.stop();
}
break;
}
if (detector.onTouchEvent(motionEvent)) {
return true;
}
// 處理手勢結束
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
endGesture();
break;
default:
break;
}
return false;
}
});
mOrientationEventListener = new OrientationEventListener(mActivity) {
@Override
public void onOrientationChanged(int orientation) {
if (orientation >= 0 && orientation <= 30 || orientation >= 330 || (orientation >= 150 && orientation <= 210)) {
if (mIsPortrait) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
mOrientationEventListener.disable();
}
} else if ((orientation >= 90 && orientation <= 120) || (orientation >= 240 && orientation <= 300)) {
if (!mIsPortrait) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
mOrientationEventListener.disable();
}
}
}
};
if (mIsOnlyFullScreen) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
mIsPortrait = (getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mPlayerViewInitHeight = rootBoxRL.getLayoutParams().height;
mScreenWidthPix = mActivity.getResources().getDisplayMetrics().widthPixels;
hideAllUI();
if (!mIsPlayerSupport) {
showStatus(mActivity.getResources().getString(R.string.not_support));
} else {
mLayoutQuery.id(R.id.ll_bg).visible();
}
}
// ========================================= 生命周期 ========================================= //
public void onPause() {
mBgState = (mIjkView.isPlaying() ? 0 : 1);
getCurrPlayPosition();
mIjkView.onPause();
}
public void onResume() {
mIjkView.onResume();
if (mIsLive) {
mIjkView.seekTo(0);
} else {
mIjkView.seekTo(mCurrPlayPosition);
}
if (mBgState != 0) {
pausePlay();
}
}
public void onDestroy() {
mOrientationEventListener.disable();
mHandler.removeMessages(MESSAGE_RESTART_PLAY);
mHandler.removeMessages(MESSAGE_SEEK_NEW_POSITION);
mIjkView.stopPlayback();
}
public void onConfigurationChanged(final Configuration newConfig) {
mIsPortrait = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
doOnConfigurationChanged(mIsPortrait);
}
public boolean onBackPressed() {
if (!mIsOnlyFullScreen && getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
doOnNoAllScreen();
return true;
}
return false;
}
// ========================================= 對外接口 ========================================= //
/**
* 設定播放資訊監聽回調
*/
public void setOnInfoListener(IMediaPlayer.OnInfoListener onInfoListener) {
this.mOnInfoListener = onInfoListener;
}
/**
* 設定播放器中的傳回鍵監聽
*/
public void setPlayerBackListener(OnPlayerBackListener listener) {
this.mPlayerBack = listener;
}
/**
* 設定控制台顯示隐藏監聽
*/
public void setOnControlPanelVisibilityChangListenter(OnControlVisibilityChangeListener listener) {
this.mOnControlVisibilityChangeListener = listener;
}
/**
* 顯示縮略圖
*/
public void showThumbnail(OnShowThumbnailListener onShowThumbnailListener) {
if (onShowThumbnailListener != null && mThumbnailImg != null) {
onShowThumbnailListener.onShowThumbnail(mThumbnailImg);
}
}
/**
* 設定播放位址
*/
public void setPlaySource(String stream, String url) {
VideoIjkBean mVideoIjkBean = new VideoIjkBean();
mVideoIjkBean.setStream(stream);
mVideoIjkBean.setUrl(url);
setPlaySource(mVideoIjkBean);
}
/**
* 設定播放位址
*/
public void setPlaySource(VideoIjkBean videoIjkBean) {
mListVideos.clear();
if (videoIjkBean != null) {
mListVideos.add(videoIjkBean);
if (mListVideos.size() > 0) {
mCurrVideoUrl = mListVideos.get(0).getUrl();
mListVideos.get(0).setSelect(true);
isLive();
if (mIjkView.isPlaying()) {
getCurrPlayPosition();
mIjkView.release(false);
}
mIsHasSwitchStream = true;
}
}
}
/**
* 開始播放
*/
public void startPlay() {
if (mIsLive) {
mIjkView.setVideoPath(mCurrVideoUrl);
mIjkView.seekTo(0);
} else {
if (mIsHasSwitchStream || mCurrStatus == PlayStateParams.STATE_ERROR) {
// TODO 換源之後聲音可播,畫面卡住,主要是渲染問題,目前隻是提供了軟解方式,後期提供設定方式
mIjkView.setRender(CusIjkView.RENDER_TEXTURE_VIEW);
mIjkView.setVideoPath(mCurrVideoUrl);
mIjkView.seekTo(mCurrPlayPosition);
mIsHasSwitchStream = false;
}
}
hideStatusUI();
if (mIsNetWorkTip && (NetworkUtils.getNetworkType(mActivity) == 4
|| NetworkUtils.getNetworkType(mActivity) == 5
|| NetworkUtils.getNetworkType(mActivity) == 6)) {
mLayoutQuery.id(R.id.app_video_netTie).visible();
} else {
if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
mLayoutQuery.id(R.id.app_video_freeTie).visible();
} else {
if (mIsPlayerSupport) {
mIjkView.start();
if (mIsFirstPlayer) {
mLayoutQuery.id(R.id.app_video_loading).visible();
mIsFirstPlayer = false;
}
} else {
showStatus(mActivity.getResources().getString(R.string.not_support));
}
}
}
}
/**
* 暫停播放
*/
public void pausePlay() {
mCurrStatus = PlayStateParams.STATE_PAUSED;
getCurrPlayPosition();
mIjkView.pause();
}
/**
* 停止播放
*/
public void stopPlay() {
mIjkView.stopPlayback();
mIsErrorStop = true;
if (mHandler != null) {
mHandler.removeMessages(MESSAGE_RESTART_PLAY);
}
}
public boolean isPlaying() {
return mIjkView.isPlaying();
}
public void backClick() {
if (!mIsOnlyFullScreen && !mIsPortrait) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
doOnNoAllScreen();
} else {
if (mPlayerBack != null) {
mPlayerBack.onPlayerBack();
} else {
mActivity.finish();
}
}
}
/**
* 設定播放位置
*/
public void seekTo(int playtime) {
mIjkView.seekTo(playtime);
}
/**
* 擷取目前播放位置
*/
public int getCurrPlayPosition() {
if (!mIsLive) {
mCurrPlayPosition = mIjkView.getCurrentPosition();
} else {
mCurrPlayPosition = -1;
}
return mCurrPlayPosition;
}
/**
* 擷取視訊播放總時長
*/
public long getDuration() {
return (long) mIjkView.getDuration();
}
/**
* 百分比顯示切換
*/
public void toggleAspectRatio() {
if (mIjkView != null) {
mIjkView.toggleAspectRatio();
}
}
/**
* 設定視訊名稱
*/
public void setTitle(String title) {
mLayoutQuery.id(R.id.app_video_title).text(title);
}
/**
* 設定最大觀看時長
*
* @param isCharge true為收費 false為免費即不做限制
* @param maxPlaytime 最大能播放時長,機關秒
*/
public void setChargeState(boolean isCharge, int maxPlaytime) {
this.mIsCharge = isCharge;
this.mMaxPlaytime = maxPlaytime * 1000;
}
/**
* 設定播放區域拉伸類型
*/
public void setScaleType(int showType) {
mCurrShowType = showType;
mIjkView.setAspectRatio(mCurrShowType);
}
/**
* 旋轉指定角度
*/
public void setPlayerRotation(int rotation) {
if (mIjkView != null) {
mIjkView.setPlayerRotation(rotation);
mIjkView.setAspectRatio(mCurrShowType);
}
}
/**
* 設定自動重連的模式或者重連時間,isAuto true 出錯重連,false出錯不重連,connectTime重連的時間
*/
public void setAutoReConnect(boolean isAuto, int connectTime) {
this.mIsAutoReConnect = isAuto;
this.mAutoConnectTime = connectTime;
}
/**
* 是否僅僅為全屏
*/
public void setOnlyFullScreen(boolean isFull) {
this.mIsOnlyFullScreen = isFull;
tryFullScreen(mIsOnlyFullScreen);
if (mIsOnlyFullScreen) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
} else {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
}
/**
* 設定是否禁止輕按兩下
*/
public void setForbidDoubleUp(boolean flag) {
this.mIsForbidDoubleUp = flag;
}
/**
* 設定是否禁止隐藏bar
*/
public void setForbidHideControlPanel(boolean flag) {
this.mIsForbidHideControlPanel = flag;
}
/**
* 是否禁止觸摸
*/
public void forbidTouch(boolean forbidTouch) {
this.mIsForbidTouch = forbidTouch;
}
/**
* 隐藏傳回鍵,true隐藏,false為顯示
*/
public void hideBack(boolean isHide) {
mBackImage.setVisibility(isHide ? View.GONE : View.VISIBLE);
}
/**
* 隐藏全屏按鈕,true隐藏,false為顯示
*/
public void hideFullscreen(boolean isHide) {
mFullScreenImage.setVisibility(isHide ? View.GONE : View.VISIBLE);
}
/**
* 隐藏中間播放按鈕,ture為隐藏,false為不做隐藏處理,但不是顯示
*/
public void hideCenterPlayer(boolean isHide) {
mIsHideCenterPlayer = isHide;
mCenterPlayerImage.setVisibility(mIsHideCenterPlayer ? View.GONE : View.VISIBLE);
}
/**
* 是否隐藏topbar,true為隐藏,false為不隐藏,但不一定是顯示
*/
public void hideHideTopBar(boolean isHide) {
mIsHideTopBar = isHide;
mTopBarView.setVisibility(mIsHideTopBar ? View.GONE : View.VISIBLE);
}
/**
* 是否隐藏bottonbar,true為隐藏,false為不隐藏,但不一定是顯示
*/
public void hideBottomBar(boolean isHide) {
mIsHideBottomBar = isHide;
mBottomBarView.setVisibility(mIsHideBottomBar ? View.GONE : View.VISIBLE);
}
/**
* 是否隐藏上下bar,true為隐藏,false為不隐藏,但不一定是顯示
*/
public void hideControlPanl(boolean isHide) {
hideBottomBar(isHide);
hideHideTopBar(isHide);
}
/**
* 顯示菜單設定
*/
public void showMenu() {
if (!mIsForbidHideControlPanel) {
mTopBarView.setVisibility(View.GONE);
mBottomBarView.setVisibility(View.GONE);
}
}
/**
* 設定顯示加載網速或者隐藏
*/
public void setShowSpeed(boolean isShow) {
mPlayerSpeedTv.setVisibility(isShow ? View.VISIBLE : View.GONE);
}
// ========================================= 内部實作 ========================================= //
/**
* 目前播放的是否是直播
*/
private void isLive() {
mIsLive = mCurrVideoUrl != null
&& (mCurrVideoUrl.startsWith("rtmp://")
|| (mCurrVideoUrl.startsWith("http://") && mCurrVideoUrl.endsWith(".m3u8"))
|| (mCurrVideoUrl.startsWith("http://") && mCurrVideoUrl.endsWith(".flv")));
}
/**
* 隐藏所有界面
*/
private void hideAllUI() {
if (!mIsForbidHideControlPanel) {
mTopBarView.setVisibility(View.GONE);
mBottomBarView.setVisibility(View.GONE);
}
hideStatusUI();
}
/**
* 顯示或隐藏操作面闆
*/
private void operatorPanel() {
mIsShowControlPanel = !mIsShowControlPanel;
if (mIsShowControlPanel) {
mTopBarView.setVisibility(mIsHideTopBar ? View.GONE : View.VISIBLE);
mBottomBarView.setVisibility(mIsHideBottomBar ? View.GONE : View.VISIBLE);
if (mIsLive) {
mLayoutQuery.id(R.id.app_video_process_panl).invisible();
} else {
mLayoutQuery.id(R.id.app_video_process_panl).visible();
}
if (mIsOnlyFullScreen || mIsForbidDoubleUp) {
mFullScreenImage.setVisibility(View.GONE);
} else {
mFullScreenImage.setVisibility(View.VISIBLE);
}
if (mOnControlVisibilityChangeListener != null) {
mOnControlVisibilityChangeListener.change(true);
}
// 顯示面闆的時候再根據狀态顯示播放按鈕
if (mCurrStatus == PlayStateParams.STATE_PLAYING
|| mCurrStatus == PlayStateParams.STATE_PREPARED
|| mCurrStatus == PlayStateParams.STATE_PREPARING
|| mCurrStatus == PlayStateParams.STATE_PAUSED) {
if (mIsHideCenterPlayer) {
mCenterPlayerImage.setVisibility(View.GONE);
} else {
mCenterPlayerImage.setVisibility(mIsLive ? View.GONE : View.VISIBLE);
}
} else {
mCenterPlayerImage.setVisibility(View.GONE);
}
updatePausePlay();
mHandler.sendEmptyMessage(MESSAGE_SHOW_PROGRESS);
mAutoPlayRunnable.start();
} else {
if (mIsHideTopBar) {
mTopBarView.setVisibility(View.GONE);
} else {
mTopBarView.setVisibility(mIsForbidHideControlPanel ? View.VISIBLE : View.GONE);
}
if (mIsHideBottomBar) {
mBottomBarView.setVisibility(View.GONE);
} else {
mBottomBarView.setVisibility(mIsForbidHideControlPanel ? View.VISIBLE : View.GONE);
}
if (!mIsLive && mCurrStatus == PlayStateParams.STATE_PAUSED && !mIjkView.isPlaying()) {
if (mIsHideCenterPlayer) {
mCenterPlayerImage.setVisibility(View.GONE);
} else {
// 暫停時一直顯示按鈕
mCenterPlayerImage.setVisibility(View.VISIBLE);
}
} else {
mCenterPlayerImage.setVisibility(View.GONE);
}
mHandler.removeMessages(MESSAGE_SHOW_PROGRESS);
if (mOnControlVisibilityChangeListener != null) {
mOnControlVisibilityChangeListener.change(false);
}
mAutoPlayRunnable.stop();
}
}
/**
* 全屏切換
*/
private void toggleFullScreen() {
if (getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
doOnNoAllScreen();
} else {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
doOnAllScreen();
}
updateFullScreenButton();
}
/**
* 進度條和時長顯示的方向切換
*/
private void toggleProcessDurationOrientation() {
setProcessDurationOrientation(PlayStateParams.PROCESS_PORTRAIT);
}
/**
* 設定進度條和時長顯示的方向,預設為上下顯示,true為上下顯示false為左右顯示
*/
private void setProcessDurationOrientation(int portrait) {
if (portrait == PlayStateParams.PROCESS_CENTER) {
mLayoutQuery.id(R.id.app_video_currentTime_full).gone();
mLayoutQuery.id(R.id.app_video_endTime_full).gone();
mLayoutQuery.id(R.id.app_video_center).gone();
mLayoutQuery.id(R.id.app_video_lift).visible();
} else if (portrait == PlayStateParams.PROCESS_LANDSCAPE) {
mLayoutQuery.id(R.id.app_video_currentTime_full).visible();
mLayoutQuery.id(R.id.app_video_endTime_full).visible();
mLayoutQuery.id(R.id.app_video_center).gone();
mLayoutQuery.id(R.id.app_video_lift).gone();
} else {
mLayoutQuery.id(R.id.app_video_currentTime_full).gone();
mLayoutQuery.id(R.id.app_video_endTime_full).gone();
mLayoutQuery.id(R.id.app_video_center).visible();
mLayoutQuery.id(R.id.app_video_lift).gone();
}
}
/**
* 擷取界面方向
*/
private int getScreenOrientation() {
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int orientation;
if ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) && height > width ||
(rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && width > height) {
switch (rotation) {
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case Surface.ROTATION_90:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_180:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
case Surface.ROTATION_270:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
default:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
}
} else {
switch (rotation) {
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_90:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case Surface.ROTATION_180:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
case Surface.ROTATION_270:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
default:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
}
}
return orientation;
}
/**
* 狀态改變同步UI
*/
private void statusChange(int newStatus) {
if (newStatus == PlayStateParams.STATE_COMPLETED) {
mCurrStatus = PlayStateParams.STATE_COMPLETED;
mCurrPlayPosition = 0;
hideAllUI();
showStatus("播放結束");
} else if (newStatus == PlayStateParams.STATE_PREPARING || newStatus == PlayStateParams.MEDIA_INFO_BUFFERING_START) {
mCurrStatus = PlayStateParams.STATE_PREPARING;
hideStatusUI(); // 視訊緩沖
mLayoutQuery.id(R.id.app_video_loading).visible();
} else if (newStatus == PlayStateParams.MEDIA_INFO_VIDEO_RENDERING_START
|| newStatus == PlayStateParams.STATE_PLAYING
|| newStatus == PlayStateParams.STATE_PREPARED
|| newStatus == PlayStateParams.MEDIA_INFO_BUFFERING_END
|| newStatus == PlayStateParams.STATE_PAUSED) {
if (mCurrStatus == PlayStateParams.STATE_PAUSED) {
mCurrStatus = PlayStateParams.STATE_PAUSED;
} else {
mCurrStatus = PlayStateParams.STATE_PLAYING;
}
// 視訊緩沖結束後隐藏縮列圖
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
hideStatusUI();
// 顯示控制bar
mIsShowControlPanel = false;
if (!mIsForbidTouch) {
operatorPanel();
}
mLayoutQuery.id(R.id.ll_bg).gone(); // 延遲0.5秒隐藏視訊封面隐藏
}
}, 500);
} else if (newStatus == PlayStateParams.MEDIA_INFO_VIDEO_INTERRUPT) {
// 直播停止推流
mCurrStatus = PlayStateParams.STATE_ERROR;
if (!(mIsNetWorkTip && (NetworkUtils.getNetworkType(mActivity) == 4
|| NetworkUtils.getNetworkType(mActivity) == 5
|| NetworkUtils.getNetworkType(mActivity) == 6))) {
if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
mLayoutQuery.id(R.id.app_video_freeTie).visible();
} else {
hideAllUI();
if (mIsLive) {
showStatus("擷取不到直播源");
} else {
showStatus(mActivity.getResources().getString(R.string.small_problem));
}
// 5秒嘗試重連
if (!mIsErrorStop && mIsAutoReConnect) {
mHandler.sendEmptyMessageDelayed(MESSAGE_RESTART_PLAY, mAutoConnectTime);
}
}
} else {
mLayoutQuery.id(R.id.app_video_netTie).visible();
}
} else if (newStatus == PlayStateParams.STATE_ERROR
|| newStatus == PlayStateParams.MEDIA_INFO_UNKNOWN
|| newStatus == PlayStateParams.MEDIA_ERROR_IO
|| newStatus == PlayStateParams.MEDIA_ERROR_MALFORMED
|| newStatus == PlayStateParams.MEDIA_ERROR_UNSUPPORTED
|| newStatus == PlayStateParams.MEDIA_ERROR_TIMED_OUT
|| newStatus == PlayStateParams.MEDIA_ERROR_SERVER_DIED) {
mCurrStatus = PlayStateParams.STATE_ERROR;
if (!(mIsNetWorkTip && (NetworkUtils.getNetworkType(mActivity) == 4
|| NetworkUtils.getNetworkType(mActivity) == 5
|| NetworkUtils.getNetworkType(mActivity) == 6))) {
if (mIsCharge && mMaxPlaytime < getCurrPlayPosition()) {
mLayoutQuery.id(R.id.app_video_freeTie).visible();
} else {
hideStatusUI();
showStatus(mActivity.getResources().getString(R.string.small_problem));
// 秒嘗試重連
if (!mIsErrorStop && mIsAutoReConnect) {
mHandler.sendEmptyMessageDelayed(MESSAGE_RESTART_PLAY, mAutoConnectTime);
}
}
} else {
mLayoutQuery.id(R.id.app_video_netTie).visible();
}
}
}
/**
* 顯示視訊播放狀态提示
*/
private void showStatus(String statusText) {
mLayoutQuery.id(R.id.app_video_replay).visible();
mLayoutQuery.id(R.id.app_video_status_text).text(statusText);
}
/**
* 界面方向改變時重新整理界面
*/
private void doOnConfigurationChanged(final boolean portrait) {
if (mIjkView != null && !mIsOnlyFullScreen) {
mHandler.post(new Runnable() {
@Override
public void run() {
tryFullScreen(!portrait);
if (portrait) {
mLayoutQuery.id(R.id.app_video_box).height(mPlayerViewInitHeight, false);
} else {
int heightPixels = mActivity.getResources().getDisplayMetrics().heightPixels;
int widthPixels = mActivity.getResources().getDisplayMetrics().widthPixels;
mLayoutQuery.id(R.id.app_video_box).height(Math.min(heightPixels, widthPixels), false);
}
updateFullScreenButton();
}
});
mOrientationEventListener.enable();
}
}
private void doOnAllScreen() {
setFullScreen(true);
if (mIjkView != null && !mIsOnlyFullScreen) {
mHandler.post(new Runnable() {
@Override
public void run() {
mIsPortrait = false;
int heightPixels = mActivity.getResources().getDisplayMetrics().heightPixels;
int widthPixels = mActivity.getResources().getDisplayMetrics().widthPixels;
mLayoutQuery.id(R.id.app_video_box).height(Math.min(heightPixels, widthPixels), false);
}
});
}
}
private void doOnNoAllScreen() {
setFullScreen(false);
if (mIjkView != null && !mIsOnlyFullScreen) {
mHandler.post(new Runnable() {
@Override
public void run() {
mIsPortrait = true;
mLayoutQuery.id(R.id.app_video_box).height(mPlayerViewInitHeight, false);
}
});
}
}
/**
* 設定界面方向
*/
private void setFullScreen(boolean fullScreen) {
if (mActivity != null) {
WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes();
if (fullScreen) {
attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
mActivity.getWindow().setAttributes(attrs);
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
} else {
attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
mActivity.getWindow().setAttributes(attrs);
mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
toggleProcessDurationOrientation();
}
}
/**
* 設定界面方向帶隐藏actionbar
*/
private void tryFullScreen(boolean fullScreen) {
if (mActivity instanceof AppCompatActivity) {
ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
if (supportActionBar != null) {
if (fullScreen) {
supportActionBar.hide();
} else {
supportActionBar.show();
}
}
}
setFullScreen(fullScreen);
}
/**
* 隐藏狀态界面
*/
private void hideStatusUI() {
mCenterPlayerImage.setVisibility(View.GONE);
mLayoutQuery.id(R.id.app_video_replay).gone();
mLayoutQuery.id(R.id.app_video_netTie).gone();
mLayoutQuery.id(R.id.app_video_freeTie).gone();
mLayoutQuery.id(R.id.app_video_loading).gone();
if (mOnControlVisibilityChangeListener != null) {
mOnControlVisibilityChangeListener.change(false);
}
}
/**
* 手勢結束
*/
private void endGesture() {
mCurrVolume = -1;
mCurrBrightness = -1f;
if (mNewPosition >= 0) {
mHandler.removeMessages(MESSAGE_SEEK_NEW_POSITION);
mHandler.sendEmptyMessage(MESSAGE_SEEK_NEW_POSITION);
}
mHandler.removeMessages(MESSAGE_HIDE_CENTER_BOX);
mHandler.sendEmptyMessageDelayed(MESSAGE_HIDE_CENTER_BOX, 500);
if (mAutoPlayRunnable != null) {
mAutoPlayRunnable.start();
}
}
/**
* 同步進度
*/
private long syncProgress() {
if (mIsDragging) {
return 0;
}
long position = mIjkView.getCurrentPosition();
long duration = mIjkView.getDuration();
if (mProgressSeekBar != null) {
if (duration > 0) {
long pos = 1000L * position / duration;
mProgressSeekBar.setProgress((int) pos);
}
int percent = mIjkView.getBufferPercentage();
mProgressSeekBar.setSecondaryProgress(percent * 10);
}
if (mIsCharge && mMaxPlaytime + 1000 < getCurrPlayPosition()) {
mLayoutQuery.id(R.id.app_video_freeTie).visible();
pausePlay();
} else {
mLayoutQuery.id(R.id.app_video_currentTime).text(generateTime(position));
mLayoutQuery.id(R.id.app_video_currentTime_full).text(generateTime(position));
mLayoutQuery.id(R.id.app_video_currentTime_left).text(generateTime(position));
mLayoutQuery.id(R.id.app_video_endTime).text(generateTime(duration));
mLayoutQuery.id(R.id.app_video_endTime_full).text(generateTime(duration));
mLayoutQuery.id(R.id.app_video_endTime_left).text(generateTime(duration));
}
return position;
}
/**
* 更新播放、暫停和停止按鈕
*/
private void updatePausePlay() {
if (mIjkView.isPlaying()) {
if (mIsLive) {
mBottomBarPlayerImage.setImageResource(R.drawable.simple_player_stop_white_24dp);
} else {
mBottomBarPlayerImage.setImageResource(R.drawable.simple_player_icon_media_pause);
mCenterPlayerImage.setImageResource(R.drawable.simple_player_center_pause);
}
} else {
mBottomBarPlayerImage.setImageResource(R.drawable.simple_player_arrow_white_24dp);
mCenterPlayerImage.setImageResource(R.drawable.simple_player_center_play);
}
}
/**
* 更新全屏和半屏按鈕
*/
private void updateFullScreenButton() {
if (getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
mFullScreenImage.setImageResource(R.drawable.simple_player_icon_fullscreen_shrink);
} else {
mFullScreenImage.setImageResource(R.drawable.simple_player_icon_fullscreen_stretch);
}
}
/**
* 滑動改變聲音大小
*/
private void onVolumeSlide(float percent) {
if (mCurrVolume == -1) {
mCurrVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
if (mCurrVolume < 0) {
mCurrVolume = 0;
}
}
int index = (int) (percent * mMaxVolume) + mCurrVolume;
if (index > mMaxVolume) {
index = mMaxVolume;
} else if (index < 0) {
index = 0;
}
// 變更聲音
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
// 變更進度條
int i = (int) (index * 1.0 / mMaxVolume * 100);
String s = i + "%";
if (i == 0) {
s = "off";
}
// 顯示
mLayoutQuery.id(R.id.app_video_volume_icon).image(i == 0
? R.drawable.simple_player_volume_off_white_36dp : R.drawable.simple_player_volume_up_white_36dp);
mLayoutQuery.id(R.id.app_video_brightness_box).gone();
mLayoutQuery.id(R.id.app_video_volume_box).visible();
mLayoutQuery.id(R.id.app_video_volume_box).visible();
mLayoutQuery.id(R.id.app_video_volume).text(s).visible();
}
/**
* 快進或者快退滑動改變進度
*/
private void onProgressSlide(float percent) {
int position = mIjkView.getCurrentPosition();
long duration = mIjkView.getDuration();
long deltaMax = Math.min(100 * 1000, duration - position);
long delta = (long) (deltaMax * percent);
mNewPosition = delta + position;
if (mNewPosition > duration) {
mNewPosition = duration;
} else if (mNewPosition <= 0) {
mNewPosition = 0;
delta = -position;
}
int showDelta = (int) delta / 1000;
if (showDelta != 0) {
mLayoutQuery.id(R.id.app_video_fastForward_box).visible();
String text = showDelta > 0 ? ("+" + showDelta) : "" + showDelta;
mLayoutQuery.id(R.id.app_video_fastForward).text(text + "s");
mLayoutQuery.id(R.id.app_video_fastForward_target).text(generateTime(mNewPosition) + "/");
mLayoutQuery.id(R.id.app_video_fastForward_all).text(generateTime(duration));
}
}
/**
* 亮度滑動改變亮度
*/
private void onBrightnessSlide(float percent) {
if (mCurrBrightness < 0) {
mCurrBrightness = mActivity.getWindow().getAttributes().screenBrightness;
if (mCurrBrightness <= 0.00f) {
mCurrBrightness = 0.50f;
} else if (mCurrBrightness < 0.01f) {
mCurrBrightness = 0.01f;
}
}
Log.d(this.getClass().getSimpleName(), "mCurrBrightness:" + mCurrBrightness + ",percent:" + percent);
mLayoutQuery.id(R.id.app_video_brightness_box).visible();
WindowManager.LayoutParams lpa = mActivity.getWindow().getAttributes();
lpa.screenBrightness = mCurrBrightness + percent;
if (lpa.screenBrightness > 1.0f) {
lpa.screenBrightness = 1.0f;
} else if (lpa.screenBrightness < 0.01f) {
lpa.screenBrightness = 0.01f;
}
mLayoutQuery.id(R.id.app_video_brightness).text(((int) (lpa.screenBrightness * 100)) + "%");
mActivity.getWindow().setAttributes(lpa);
}
/**
* 時長格式化顯示
*/
@SuppressLint("DefaultLocale")
private String generateTime(long time) {
int totalSeconds = (int) (time / 1000);
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds);
}
/**
* 下載下傳速度格式化顯示
*/
private String getFormatSize(int size) {
long fileSize = (long) size;
String showSize = "";
if (fileSize >= 0 && fileSize < 1024) {
showSize = fileSize + "Kb/s";
} else if (fileSize >= 1024 && fileSize < (1024 * 1024)) {
showSize = Long.toString(fileSize / 1024) + "KB/s";
} else if (fileSize >= (1024 * 1024) && fileSize < (1024 * 1024 * 1024)) {
showSize = Long.toString(fileSize / (1024 * 1024)) + "MB/s";
}
return showSize;
}
// ========================================== 内部類 ========================================== //
@SuppressLint("HandlerLeak")
private class CusUiHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
// 滑動完成,隐藏滑動提示的box
case MESSAGE_HIDE_CENTER_BOX:
mLayoutQuery.id(R.id.app_video_volume_box).gone();
mLayoutQuery.id(R.id.app_video_brightness_box).gone();
mLayoutQuery.id(R.id.app_video_fastForward_box).gone();
break;
// 滑動完成,設定播放進度
case MESSAGE_SEEK_NEW_POSITION:
if (!mIsLive && mNewPosition >= 0) {
mIjkView.seekTo((int) mNewPosition);
mNewPosition = -1;
}
break;
// 滑動中,同步播放進度
case MESSAGE_SHOW_PROGRESS:
long pos = syncProgress();
if (!mIsDragging && mIsShowControlPanel) {
msg = obtainMessage(MESSAGE_SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
updatePausePlay();
}
break;
// 重新去播放
case MESSAGE_RESTART_PLAY:
mCurrStatus = PlayStateParams.STATE_ERROR;
startPlay();
updatePausePlay();
break;
}
}
}
/**
* 收起控制台輪詢,預設5秒無操作,收起控制台
*/
private class AutoPlayRunnable implements Runnable {
private int AUTO_PLAY_INTERVAL = 5000;
private boolean mShouldAutoPlay;
AutoPlayRunnable() {
mShouldAutoPlay = false;
}
void start() {
if (!mShouldAutoPlay) {
mShouldAutoPlay = true;
mHandler.removeCallbacks(this);
mHandler.postDelayed(this, AUTO_PLAY_INTERVAL);
}
}
void stop() {
if (mShouldAutoPlay) {
mHandler.removeCallbacks(this);
mShouldAutoPlay = false;
}
}
@Override
public void run() {
if (mShouldAutoPlay) {
mHandler.removeCallbacks(this);
if (!mIsForbidTouch) {
operatorPanel();
}
}
}
}
/**
* 播放器的手勢監聽
*/
public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener {
private boolean isDownTouch; // 是否是按下的辨別,預設為其他動作,true為按下辨別,false為其他動作
private boolean isVolume; // 是否聲音控制,預設為亮度控制,true為聲音控制,false為亮度控制
private boolean isLandscape; // 是否橫向滑動,預設為縱向滑動,true為橫向滑動,false為縱向滑動
/**
* 輕按兩下,視訊視窗輕按兩下事件
*/
@Override
public boolean onDoubleTap(MotionEvent e) {
// if (!mIsForbidTouch && !mIsOnlyFullScreen && !mIsForbidDoubleUp) {
// toggleFullScreen();
// }
return true;
}
/**
* 按下
*/
@Override
public boolean onDown(MotionEvent e) {
isDownTouch = true;
return super.onDown(e);
}
/**
* 滑動
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!mIsForbidTouch) {
float mOldX = e1.getX(), mOldY = e1.getY();
float deltaY = mOldY - e2.getY();
float deltaX = mOldX - e2.getX();
if (isDownTouch) {
isLandscape = Math.abs(distanceX) >= Math.abs(distanceY);
isVolume = mOldX > mScreenWidthPix * 0.5f;
isDownTouch = false;
}
if (isLandscape) {
if (!mIsLive) {
// 進度設定
onProgressSlide(-deltaX / mIjkView.getWidth());
}
} else {
float percent = deltaY / mIjkView.getHeight();
if (isVolume) {
// 聲音設定
onVolumeSlide(percent);
} else {
// 亮度設定
onBrightnessSlide(percent);
}
}
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
/**
* 單擊,視訊視窗單擊事件
*/
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (!mIsForbidTouch) {
operatorPanel();
}
return true;
}
}
3.具體的使用:
在你實作播放器的activity使用:
1)首先初始化播放器:
2)對視訊進行網絡判斷
3)吊起播放:
項目位址:
https://download.csdn.net/download/wk_beicai/11177930