Beruflich Dokumente
Kultur Dokumente
nicevideoplayer;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.Surface;
import android.view.TextureView;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import java.io.IOException;
import java.util.Map;
import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
/**
* Created by XiaoJianjun on 2017/4/28.
* 播放器
*/
public class NiceVideoPlayer extends FrameLayout
implements INiceVideoPlayer,
TextureView.SurfaceTextureListener {
/**
* 播放错误
**/
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_BUFFERING_PLAYING = 5;
/**
* 正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,此时暂停播放器,继续缓冲,缓冲区数据足
够后恢复暂停
**/
public static final int STATE_BUFFERING_PAUSED = 6;
/**
* 播放完成
**/
public static final int STATE_COMPLETED = 7;
/**
* 普通模式
**/
public static final int MODE_NORMAL = 10;
/**
* 全屏模式
**/
public static final int MODE_FULL_SCREEN = 11;
/**
* 小窗口模式
**/
public static final int MODE_TINY_WINDOW = 12;
/**
* IjkPlayer
**/
public static final int TYPE_IJK = 111;
/**
* MediaPlayer
**/
public static final int TYPE_NATIVE = 222;
/**
* 设置播放器类型
*
* @param playerType IjkPlayer or MediaPlayer.
*/
public void setPlayerType(int playerType) {
mPlayerType = playerType;
}
/**
* 是否从上一次的位置继续播放
*
* @param continueFromLastPosition true 从上一次的位置继续播放
*/
@Override
public void continueFromLastPosition(boolean continueFromLastPosition) {
this.continueFromLastPosition = continueFromLastPosition;
}
@Override
public void setSpeed(float speed) {
if (mMediaPlayer instanceof IjkMediaPlayer) {
((IjkMediaPlayer) mMediaPlayer).setSpeed(speed);
} else {
LogUtil.d("只有 IjkPlayer 才能设置播放速度");
}
}
@Override
public void start() {
if (mCurrentState == STATE_IDLE) {
NiceVideoPlayerManager.instance().setCurrentNiceVideoPlayer(this);
initAudioManager();
initMediaPlayer();
initTextureView();
addTextureView();
} else {
LogUtil.d("NiceVideoPlayer 只有在 mCurrentState == STATE_IDLE 时才能调用
start 方法.");
}
}
@Override
public void start(long position) {
skipToPosition = position;
start();
}
@Override
public void restart() {
if (mCurrentState == STATE_PAUSED) {
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
mController.onPlayStateChanged(mCurrentState);
LogUtil.d("STATE_PLAYING");
} else if (mCurrentState == STATE_BUFFERING_PAUSED) {
mMediaPlayer.start();
mCurrentState = STATE_BUFFERING_PLAYING;
mController.onPlayStateChanged(mCurrentState);
LogUtil.d("STATE_BUFFERING_PLAYING");
} else if (mCurrentState == STATE_COMPLETED || mCurrentState ==
STATE_ERROR) {
mMediaPlayer.reset();
openMediaPlayer();
} else {
LogUtil.d("NiceVideoPlayer 在 mCurrentState == " + mCurrentState + "时不
能调用 restart()方法.");
}
}
@Override
public void pause() {
if (mCurrentState == STATE_PLAYING) {
mMediaPlayer.pause();
mCurrentState = STATE_PAUSED;
mController.onPlayStateChanged(mCurrentState);
LogUtil.d("STATE_PAUSED");
}
if (mCurrentState == STATE_BUFFERING_PLAYING) {
mMediaPlayer.pause();
mCurrentState = STATE_BUFFERING_PAUSED;
mController.onPlayStateChanged(mCurrentState);
LogUtil.d("STATE_BUFFERING_PAUSED");
}
}
@Override
public void seekTo(long pos) {
if (mMediaPlayer != null) {
mMediaPlayer.seekTo(pos);
}
}
@Override
public void setVolume(int volume) {
if (mAudioManager != null) {
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
}
}
@Override
public boolean isIdle() {
return mCurrentState == STATE_IDLE;
}
@Override
public boolean isPreparing() {
return mCurrentState == STATE_PREPARING;
}
@Override
public boolean isPrepared() {
return mCurrentState == STATE_PREPARED;
}
@Override
public boolean isBufferingPlaying() {
return mCurrentState == STATE_BUFFERING_PLAYING;
}
@Override
public boolean isBufferingPaused() {
return mCurrentState == STATE_BUFFERING_PAUSED;
}
@Override
public boolean isPlaying() {
return mCurrentState == STATE_PLAYING;
}
@Override
public boolean isPaused() {
return mCurrentState == STATE_PAUSED;
}
@Override
public boolean isError() {
return mCurrentState == STATE_ERROR;
}
@Override
public boolean isCompleted() {
return mCurrentState == STATE_COMPLETED;
}
@Override
public boolean isFullScreen() {
return mCurrentMode == MODE_FULL_SCREEN;
}
@Override
public boolean isTinyWindow() {
return mCurrentMode == MODE_TINY_WINDOW;
}
@Override
public boolean isNormal() {
return mCurrentMode == MODE_NORMAL;
}
@Override
public int getMaxVolume() {
if (mAudioManager != null) {
return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
}
return 0;
}
@Override
public int getVolume() {
if (mAudioManager != null) {
return mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
}
return 0;
}
@Override
public long getDuration() {
return mMediaPlayer != null ? mMediaPlayer.getDuration() : 0;
}
@Override
public long getCurrentPosition() {
return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : 0;
}
@Override
public int getBufferPercentage() {
return mBufferPercentage;
}
@Override
public float getSpeed(float speed) {
if (mMediaPlayer instanceof IjkMediaPlayer) {
return ((IjkMediaPlayer) mMediaPlayer).getSpeed(speed);
}
return 0;
}
@Override
public long getTcpSpeed() {
if (mMediaPlayer instanceof IjkMediaPlayer) {
return ((IjkMediaPlayer) mMediaPlayer).getTcpSpeed();
}
return 0;
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
int height) {
if (mSurfaceTexture == null) {
mSurfaceTexture = surfaceTexture;
openMediaPlayer();
} else {
mTextureView.setSurfaceTexture(mSurfaceTexture);
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int
height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return mSurfaceTexture == null;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
/**
* 全屏,将 mContainer(内部包含 mTextureView 和 mController)从当前容器中移除,并添加到
android.R.content 中.
* 切换横屏时需要在 manifest 的 activity 标签下添加 android:configChanges="orientation|
keyboardHidden|screenSize"配置,
* 以避免 Activity 重新走生命周期
*/
@Override
public void enterFullScreen() {
if (mCurrentMode == MODE_FULL_SCREEN) return;
// 隐藏 ActionBar、状态栏,并横屏
NiceUtil.hideActionBar(mContext);
NiceUtil.scanForActivity(mContext)
.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
ViewGroup contentView = (ViewGroup) NiceUtil.scanForActivity(mContext)
.findViewById(android.R.id.content);
if (mCurrentMode == MODE_TINY_WINDOW) {
contentView.removeView(mContainer);
} else {
this.removeView(mContainer);
}
LayoutParams params = new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
contentView.addView(mContainer, params);
mCurrentMode = MODE_FULL_SCREEN;
mController.onPlayModeChanged(mCurrentMode);
LogUtil.d("MODE_FULL_SCREEN");
}
/**
* 退出全屏,移除 mTextureView 和 mController,并添加到非全屏的容器中。
* 切换竖屏时需要在 manifest 的 activity 标签下添加 android:configChanges="orientation|
keyboardHidden|screenSize"配置,
* 以避免 Activity 重新走生命周期.
*
* @return true 退出全屏.
*/
@Override
public boolean exitFullScreen() {
if (mCurrentMode == MODE_FULL_SCREEN) {
NiceUtil.showActionBar(mContext);
NiceUtil.scanForActivity(mContext)
.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mCurrentMode = MODE_NORMAL;
mController.onPlayModeChanged(mCurrentMode);
LogUtil.d("MODE_NORMAL");
return true;
}
return false;
}
/**
* 进入小窗口播放,小窗口播放的实现原理与全屏播放类似。
*/
@Override
public void enterTinyWindow() {
if (mCurrentMode == MODE_TINY_WINDOW) return;
this.removeView(mContainer);
contentView.addView(mContainer, params);
mCurrentMode = MODE_TINY_WINDOW;
mController.onPlayModeChanged(mCurrentMode);
LogUtil.d("MODE_TINY_WINDOW");
}
/**
* 退出小窗口播放
*/
@Override
public boolean exitTinyWindow() {
if (mCurrentMode == MODE_TINY_WINDOW) {
ViewGroup contentView = (ViewGroup) NiceUtil.scanForActivity(mContext)
.findViewById(android.R.id.content);
contentView.removeView(mContainer);
LayoutParams params = new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
this.addView(mContainer, params);
mCurrentMode = MODE_NORMAL;
mController.onPlayModeChanged(mCurrentMode);
LogUtil.d("MODE_NORMAL");
return true;
}
return false;
}
@Override
public void releasePlayer() {
if (mAudioManager != null) {
mAudioManager.abandonAudioFocus(null);
mAudioManager = null;
}
if (mMediaPlayer != null) {
mMediaPlayer.release();
mMediaPlayer = null;
}
mContainer.removeView(mTextureView);
if (mSurface != null) {
mSurface.release();
mSurface = null;
}
if (mSurfaceTexture != null) {
mSurfaceTexture.release();
mSurfaceTexture = null;
}
mCurrentState = STATE_IDLE;
}
@Override
public void release() {
// 保存播放位置
if (isPlaying() || isBufferingPlaying() || isBufferingPaused() ||
isPaused()) {
NiceUtil.savePlayPosition(mContext, mUrl, getCurrentPosition());
} else if (isCompleted()) {
NiceUtil.savePlayPosition(mContext, mUrl, 0);
}
// 退出全屏或小窗口
if (isFullScreen()) {
exitFullScreen();
}
if (isTinyWindow()) {
exitTinyWindow();
}
mCurrentMode = MODE_NORMAL;
// 释放播放器
releasePlayer();
// 恢复控制器
if (mController != null) {
mController.reset();
}
Runtime.getRuntime().gc();
}
}