package com.shuyu.gsyvideoplayer; import android.content.Context; import android.media.AudioManager; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.text.TextUtils; import android.view.Surface; import com.danikula.videocache.HttpProxyCacheServer; import com.shuyu.gsyvideoplayer.listener.GSYMediaPlayerListener; import com.shuyu.gsyvideoplayer.model.GSYModel; import java.io.File; import java.lang.ref.WeakReference; import java.util.Map; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IjkMediaPlayer; /** * 视频管理,单例 * 目前使用的是IJK封装的谷歌EXOPlayer * Created by shuyu on 2016/11/11. */ public class GSYVideoManager implements IMediaPlayer.OnPreparedListener, IMediaPlayer.OnCompletionListener, IMediaPlayer.OnBufferingUpdateListener, IMediaPlayer.OnSeekCompleteListener, IMediaPlayer.OnErrorListener, IMediaPlayer.OnVideoSizeChangedListener, IMediaPlayer.OnInfoListener { public static String TAG = "GSYVideoManager"; private static GSYVideoManager videoManager; public static final int HANDLER_PREPARE = 0; public static final int HANDLER_SETDISPLAY = 1; public static final int HANDLER_RELEASE = 2; private IjkMediaPlayer mediaPlayer; private HandlerThread mMediaHandlerThread; private MediaHandler mMediaHandler; private Handler mainThreadHandler; private WeakReference listener; private WeakReference lastListener; private HttpProxyCacheServer proxy; //视频代理 private File cacheFile; private String playTag = ""; //播放的tag,防止错位置,因为普通的url也可能重复 private int currentVideoWidth = 0; //当前播放的视频宽的高 private int currentVideoHeight = 0; //当前播放的视屏的高 private int lastState;//当前视频的最后状态 private int playPosition = -22; //播放的tag,防止错位置,因为普通的url也可能重复 public static synchronized GSYVideoManager instance() { if (videoManager == null) { videoManager = new GSYVideoManager(); } return videoManager; } /** * 获取缓存代理服务 */ public static HttpProxyCacheServer getProxy(Context context) { HttpProxyCacheServer proxy = GSYVideoManager.instance().proxy; return proxy == null ? (GSYVideoManager.instance().proxy = GSYVideoManager.instance().newProxy(context)) : proxy; } /** * 获取缓存代理服务,带文件目录的 */ public static HttpProxyCacheServer getProxy(Context context, File file) { //如果为空,返回默认的 if (file == null) { return getProxy(context); } //如果已经有缓存文件路径,那么判断缓存文件路径是否一致 if (GSYVideoManager.instance().cacheFile != null && !GSYVideoManager.instance().cacheFile.getAbsolutePath().equals(file.getAbsolutePath())) { //不一致先关了旧的 HttpProxyCacheServer proxy = GSYVideoManager.instance().proxy; if (proxy != null) { proxy.shutdown(); } //开启新的 return (GSYVideoManager.instance().proxy = GSYVideoManager.instance().newProxy(context, file)); } else { //还没有缓存文件的或者一致的,返回原来 HttpProxyCacheServer proxy = GSYVideoManager.instance().proxy; return proxy == null ? (GSYVideoManager.instance().proxy = GSYVideoManager.instance().newProxy(context, file)) : proxy; } } /** * 创建缓存代理服务,带文件目录的. */ private HttpProxyCacheServer newProxy(Context context, File file) { if (!file.exists()) { file.mkdirs(); } HttpProxyCacheServer.Builder builder = new HttpProxyCacheServer.Builder(context); builder.cacheDirectory(file); cacheFile = file; return builder.build(); } /** * 创建缓存代理服务 */ private HttpProxyCacheServer newProxy(Context context) { return new HttpProxyCacheServer(context.getApplicationContext()); } public GSYMediaPlayerListener listener() { if (listener == null) return null; return listener.get(); } public GSYMediaPlayerListener lastListener() { if (lastListener == null) return null; return lastListener.get(); } public void setListener(GSYMediaPlayerListener listener) { if (listener == null) this.listener = null; else this.listener = new WeakReference<>(listener); } public void setLastListener(GSYMediaPlayerListener lastListener) { if (lastListener == null) this.lastListener = null; else this.lastListener = new WeakReference<>(lastListener); } public GSYVideoManager() { mediaPlayer = new IjkMediaPlayer(); mMediaHandlerThread = new HandlerThread(TAG); mMediaHandlerThread.start(); mMediaHandler = new MediaHandler((mMediaHandlerThread.getLooper())); mainThreadHandler = new Handler(); } public class MediaHandler extends Handler { public MediaHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case HANDLER_PREPARE: try { currentVideoWidth = 0; currentVideoHeight = 0; mediaPlayer.release(); mediaPlayer = new IjkMediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(((GSYModel) msg.obj).getUrl(), ((GSYModel) msg.obj).getMapHeadData()); mediaPlayer.setLooping(((GSYModel) msg.obj).isLooping()); mediaPlayer.setOnCompletionListener(GSYVideoManager.this); mediaPlayer.setOnBufferingUpdateListener(GSYVideoManager.this); mediaPlayer.setScreenOnWhilePlaying(true); mediaPlayer.setOnPreparedListener(GSYVideoManager.this); mediaPlayer.setOnSeekCompleteListener(GSYVideoManager.this); mediaPlayer.setOnErrorListener(GSYVideoManager.this); mediaPlayer.setOnInfoListener(GSYVideoManager.this); mediaPlayer.setOnVideoSizeChangedListener(GSYVideoManager.this); if (((GSYModel) msg.obj).getSpeed() != 1 && ((GSYModel) msg.obj).getSpeed() > 0) { mediaPlayer.setSpeed(((GSYModel) msg.obj).getSpeed()); } mediaPlayer.prepareAsync(); } catch (Exception e) { e.printStackTrace(); } break; case HANDLER_SETDISPLAY: if (msg.obj == null && mediaPlayer != null) { mediaPlayer.setSurface(null); } else { Surface holder = (Surface) msg.obj; if (mediaPlayer != null && holder.isValid()) { mediaPlayer.setSurface(holder); } } break; case HANDLER_RELEASE: if (mediaPlayer != null) { mediaPlayer.release(); } break; } } } public void prepare(final String url, final Map mapHeadData, boolean loop, float speed) { if (TextUtils.isEmpty(url)) return; Message msg = new Message(); msg.what = HANDLER_PREPARE; GSYModel fb = new GSYModel(url, mapHeadData, loop, speed); msg.obj = fb; mMediaHandler.sendMessage(msg); } public void releaseMediaPlayer() { Message msg = new Message(); msg.what = HANDLER_RELEASE; mMediaHandler.sendMessage(msg); playTag = ""; playPosition = -22; } public void setDisplay(Surface holder) { Message msg = new Message(); msg.what = HANDLER_SETDISPLAY; msg.obj = holder; mMediaHandler.sendMessage(msg); } @Override public void onPrepared(IMediaPlayer mp) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onPrepared(); } } }); } @Override public void onCompletion(IMediaPlayer mp) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onAutoCompletion(); } } }); } @Override public void onBufferingUpdate(IMediaPlayer mp, final int percent) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onBufferingUpdate(percent); } } }); } @Override public void onSeekComplete(IMediaPlayer mp) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onSeekComplete(); } } }); } @Override public boolean onError(IMediaPlayer mp, final int what, final int extra) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onError(what, extra); } } }); return true; } @Override public boolean onInfo(IMediaPlayer mp, final int what, final int extra) { mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onInfo(what, extra); } } }); return false; } @Override public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) { currentVideoWidth = mp.getVideoWidth(); currentVideoHeight = mp.getVideoHeight(); mainThreadHandler.post(new Runnable() { @Override public void run() { if (listener != null) { listener().onVideoSizeChanged(); } } }); } public IjkMediaPlayer getMediaPlayer() { return mediaPlayer; } public int getCurrentVideoWidth() { return currentVideoWidth; } public int getCurrentVideoHeight() { return currentVideoHeight; } public int getLastState() { return lastState; } public void setLastState(int lastState) { this.lastState = lastState; } public void setCurrentVideoHeight(int currentVideoHeight) { this.currentVideoHeight = currentVideoHeight; } public void setCurrentVideoWidth(int currentVideoWidth) { this.currentVideoWidth = currentVideoWidth; } public String getPlayTag() { return playTag; } public void setPlayTag(String playTag) { this.playTag = playTag; } public int getPlayPosition() { return playPosition; } public void setPlayPosition(int playPosition) { this.playPosition = playPosition; } }