状态图
需要注意的是和camera的释放类似,调用release()后没法直接进入idle状态,所以mediaplayer的状态是有问题的,要置null
自己的一个栗子:
package yunhen.yunjia.aiservice.camera;
import android.content.res.AssetFileDescriptor;
import android.graphics.Matrix;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import java.io.IOException;
import java.lang.ref.WeakReference;
import yunhen.yunjia.aiservice.utils.Logs;
import yunhen.yunjia.aiservice.utils.SPConfig;
public class MediaPlayUtils {
private static final String TAG = MediaPlayUtils.class.getSimpleName();
private MediaPlayer mMediaPlayer;
private static MediaPlayUtils m;
private WeakReference weak ;
private String filaHelloName = "1.mp4";
private String filaSpeakNameMirror = "2Left.mp4";
private String filaSpeakName = "3Right.mp4";
private AssetFileDescriptor afdHello;
private AssetFileDescriptor afd;
private AssetFileDescriptor afdMirror;
private boolean isMirror = true;
MediaPlayer.OnCompletionListener mCompletionListener;
public static MediaPlayUtils instance() {
synchronized (MediaPlayUtils.class) {
if (null == m) {
synchronized (MediaPlayUtils.class) {
m = new MediaPlayUtils();
}
}
}
return m;
}
private MediaPlayUtils() {
}
/**
* 当前播放的视频
* {@link MediaPlayUtils#currStatu}
* @return
*/
public Statu currStatu() {
return currStatu;
}
public void init(TextureView surfaceView) {
if (null == mMediaPlayer) {
mMediaPlayer = new MediaPlayer();
} else {
}
weak = new WeakReference<>(surfaceView);
// pathDef = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath()
// + File.separator+ filaHelloName;
// pathSpeak = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath()
// + File.separator + filaSpeakName;
try {
afdHello = weak.get().getContext().getAssets().openFd(filaHelloName);
afd = weak.get().getContext().getAssets().openFd(filaSpeakName);
afdMirror = weak.get().getContext().getAssets().openFd(filaSpeakNameMirror);
} catch (IOException e) {
e.printStackTrace();
}
}
public void setCompletionListener(MediaPlayer.OnCompletionListener completionListener) {
mCompletionListener = completionListener;
}
public void play(Statu statu) {
currStatu = statu;
if (null == mMediaPlayer) {
mMediaPlayer = new MediaPlayer();
}
else if (isPlaying()){
pause();
// stop();
// release();
}
resetDate(statu);
Logs.instance().e(TAG,"weak.get() is null "+ (weak.get() == null));
Logs.instance().e(TAG,"weak.getSurfaceTexture is null "+ (weak.get().getSurfaceTexture() == null));
Surface s = new Surface(weak.get().getSurfaceTexture());
mMediaPlayer.setSurface(s);//设置video影片以surfaceviewholder播放
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setVolume(0f, 0f);
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
updateSizeCenterCrop();
mediaPlayer.start();
}
});
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.prepareAsync();
}
public enum Statu{
/**
* 问好嘴动循环
*/
hello_speaking_loop,
/**
* 问好嘴不动循环
*/
hellow_not_speak_loop,
/**
* 向上抬手
*/
tai_shou_one,
/**
* 抬手不动循环
*/
tai_shou_loop,
/**
* 向下放手
*/
fang_shou_one;
}
public void reset() {
if (null != mMediaPlayer) {
try {
mMediaPlayer.reset();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
public void pause() {
if (null != mMediaPlayer) {
try {
mMediaPlayer.pause();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
public boolean isPlaying() {
if (null != mMediaPlayer) {
try {
return mMediaPlayer.isPlaying();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
return false;
}
Statu currStatu;
public void resetDate(Statu statu) {
reset();
try {
if (Statu.hello_speaking_loop == statu) {
String path = SPConfig.instance(weak.get().getContext())
.getVideoPathHellow();
if (null == path || "".equals(path)) {
mMediaPlayer.setDataSource(afdHello.getFileDescriptor(),afdHello.getStartOffset(),afdHello.getLength());
} else {
mMediaPlayer.setDataSource(path);
}
} else if (Statu.hellow_not_speak_loop == statu) {
String path = SPConfig.instance(weak.get().getContext())
.getVideoPathHellowLoop();
if (null == path || "".equals(path)) {
mMediaPlayer.setDataSource(afdHello.getFileDescriptor(),afdHello.getStartOffset(),afdHello.getLength());
} else {
mMediaPlayer.setDataSource(path);
}
} else if (Statu.tai_shou_one == statu) {
String path = "";
if (isMirror) {
path = SPConfig.instance(weak.get().getContext())
.getVideoPathLeftTaiShou();
if (null == path || "".equals(path)) {
mMediaPlayer.setDataSource(afdHello.getFileDescriptor(),afdHello.getStartOffset(),afdHello.getLength());
} else {
mMediaPlayer.setDataSource(path);
}
}else {
path = SPConfig.instance(weak.get().getContext())
.getVideoPathRightTaiShou();
if (null == path || "".equals(path)) {
mMediaPlayer.setDataSource(afdHello.getFileDescriptor(),afdHello.getStartOffset(),afdHello.getLength());
} else {
mMediaPlayer.setDataSource(path);
}
}
} else if (Statu.tai_shou_loop == statu) {
// mMediaPlayer.setDataSource(pathSpeak);
if (isMirror) {//镜像模式下向左
String pathLeft = SPConfig.instance(weak.get().getContext()).getVideoPathLeftTaiShouLoop();
if (null == pathLeft || "".equals(pathLeft)) {
mMediaPlayer.setDataSource(afdMirror.getFileDescriptor(),afdMirror.getStartOffset(),afdMirror.getLength());
} else {
mMediaPlayer.setDataSource(pathLeft);
}
} else {
String pathRight = SPConfig.instance(weak.get().getContext()).getVideoPathRightTaiShouLoop();
if (null == pathRight || "".equals(pathRight)) {
mMediaPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
} else {
mMediaPlayer.setDataSource(pathRight);
}
}
} else if (Statu.fang_shou_one == statu) {
if (isMirror) {//镜像模式下向左
String pathLeft = SPConfig.instance(weak.get().getContext()).getVideoPathLeftFangShou();
if (null == pathLeft || "".equals(pathLeft)) {
mMediaPlayer.setDataSource(afdMirror.getFileDescriptor(),afdMirror.getStartOffset(),afdMirror.getLength());
} else {
mMediaPlayer.setDataSource(pathLeft);
}
} else {
String pathRight = SPConfig.instance(weak.get().getContext()).getVideoPathRightFangShou();
if (null == pathRight || "".equals(pathRight)) {
mMediaPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
} else {
mMediaPlayer.setDataSource(pathRight);
}
}
}
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"IOException "+e.getMessage());
}
}
public void stop() {
if (null != mMediaPlayer) {
try {
mMediaPlayer.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
public void release() {
if (null != mMediaPlayer) {
try {
mMediaPlayer.release();
} catch (IllegalStateException e) {
e.printStackTrace();
}
mMediaPlayer = null;
}
}
public void destroy() {
stop();
release();
}
public void setMirror(boolean mirror) {
this.isMirror = mirror;
}
//重新计算video的显示位置,让其全部显示并据中
public void updateSizeCenter(){
int mVideoWidth = mMediaPlayer.getVideoWidth();
int mVideoHeight = mMediaPlayer.getVideoHeight();
float sx = (float) weak.get().getWidth() / (float) mVideoWidth;
float sy = (float) weak.get().getHeight() / (float) mVideoHeight;
Matrix matrix = new Matrix();
//第1步:把视频区移动到View区,使两者中心点重合.
matrix.preTranslate((weak.get().getWidth() - mVideoWidth) / 2, (weak.get().getHeight() - mVideoHeight) / 2);
//第2步:因为默认视频是fitXY的形式显示的,所以首先要缩放还原回来.
matrix.preScale(mVideoWidth / (float) weak.get().getWidth(), mVideoHeight / (float) weak.get().getHeight());
//第3步,等比例放大或缩小,直到视频区的一边和View一边相等.如果另一边和view的一边不相等,则留下空隙
if (sx >= sy){
matrix.postScale(sy, sy, weak.get().getWidth() / 2, weak.get().getHeight() / 2);
}else{
matrix.postScale(sx, sx, weak.get().getWidth() / 2, weak.get().getHeight() / 2);
}
weak.get().setTransform(matrix);
weak.get().postInvalidate();
}
//重新计算video的显示位置,裁剪后全屏显示
public void updateSizeCenterCrop(){
int mVideoWidth = mMediaPlayer.getVideoWidth();
int mVideoHeight = mMediaPlayer.getVideoHeight();
float sx = (float) weak.get().getWidth() / (float) mVideoWidth;
float sy = (float) weak.get().getHeight() / (float) mVideoHeight;
Matrix matrix = new Matrix();
float maxScale = Math.max(sx, sy);
//第1步:把视频区移动到View区,使两者中心点重合.
matrix.preTranslate((weak.get().getWidth() - mVideoWidth) / 2, (weak.get().getHeight() - mVideoHeight) / 2);
//第2步:因为默认视频是fitXY的形式显示的,所以首先要缩放还原回来.
matrix.preScale(mVideoWidth / (float)weak.get(). getWidth(), mVideoHeight / (float) weak.get().getHeight());
//第3步,等比例放大或缩小,直到视频区的一边超过View一边, 另一边与View的另一边相等. 因为超过的部分超出了View的范围,所以是不会显示的,相当于裁剪了.
matrix.postScale(maxScale, maxScale, weak.get().getWidth() / 2, weak.get().getHeight() / 2);//后两个参数坐标是以整个View的坐标系以参考的
weak.get().setTransform(matrix);
weak.get().postInvalidate();
}
}