package com.shuyu.gsyvideoplayer;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
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.CacheListener;
import com.danikula.videocache.HttpProxyCacheServer;
import com.danikula.videocache.file.Md5FileNameGenerator;
import com.shuyu.gsyvideoplayer.listener.GSYMediaPlayerListener;
import com.shuyu.gsyvideoplayer.model.GSYModel;
import com.shuyu.gsyvideoplayer.model.VideoOptionModel;
import com.shuyu.gsyvideoplayer.utils.GSYVideoType;
import com.shuyu.gsyvideoplayer.utils.CommonUtil;
import com.shuyu.gsyvideoplayer.utils.Debuger;
import com.shuyu.gsyvideoplayer.utils.FileUtils;
import com.shuyu.gsyvideoplayer.utils.StorageUtils;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import tv.danmaku.ijk.media.exo.IjkExoMediaPlayer;
import tv.danmaku.ijk.media.player.AbstractMediaPlayer;
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, CacheListener {
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 AbstractMediaPlayer mediaPlayer;
private HandlerThread mMediaHandlerThread;
private MediaHandler mMediaHandler;
private Handler mainThreadHandler;
private WeakReference<GSYMediaPlayerListener> listener;
private WeakReference<GSYMediaPlayerListener> lastListener;
private List<VideoOptionModel> optionModelList;//配置ijk option
private HttpProxyCacheServer proxy; //视频代理
private File cacheFile;
private String playTag = ""; //播放的tag,防止错位置,因为普通的url也可能重复
private Context context;
private int currentVideoWidth = 0; //当前播放的视频宽的高
private int currentVideoHeight = 0; //当前播放的视屏的高
private int lastState;//当前视频的最后状态
private int playPosition = -22; //播放的tag,防止错位置,因为普通的url也可能重复
private int buffterPoint;
private int videoType = GSYVideoType.IJKPLAYER;
private boolean needMute = false; //是否需要静音
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 void clearAllDefaultCache(Context context) {
String path = StorageUtils.getIndividualCacheDirectory
(context.getApplicationContext()).getAbsolutePath();
FileUtils.deleteFiles(new File(path));
}
/**
* 删除url对应默认缓存文件
*/
public static void clearDefaultCache(Context context, String url) {
Md5FileNameGenerator md5FileNameGenerator = new Md5FileNameGenerator();
String name = md5FileNameGenerator.generate(url);
String pathTmp = StorageUtils.getIndividualCacheDirectory
(context.getApplicationContext()).getAbsolutePath()
+ File.separator + name + ".download";
String path = StorageUtils.getIndividualCacheDirectory
(context.getApplicationContext()).getAbsolutePath()
+ File.separator + name;
CommonUtil.deleteFile(pathTmp);
CommonUtil.deleteFile(path);
}
/**
* 获取缓存代理服务,带文件目录的
*/
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:
initVideo(msg);
break;
case HANDLER_SETDISPLAY:
showDisplay(msg);
break;
case HANDLER_RELEASE:
if (mediaPlayer != null) {
mediaPlayer.release();
}
setNeedMute(false);
if (proxy != null) {
proxy.unregisterCacheListener(GSYVideoManager.this);
}
buffterPoint = 0;
break;
}
}
}
private void initVideo(Message msg) {
try {
currentVideoWidth = 0;
currentVideoHeight = 0;
mediaPlayer.release();
if (videoType == GSYVideoType.IJKPLAYER) {
initIJKPlayer(msg);
} else if (videoType == GSYVideoType.IJKEXOPLAYER) {
initEXOPlayer(msg);
}
setNeedMute(needMute);
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);
mediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
private void initIJKPlayer(Message msg) {
mediaPlayer = new IjkMediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
if (GSYVideoType.isMediaCodec()) {
Debuger.printfLog("enable mediaCodec");
((IjkMediaPlayer) mediaPlayer).setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
((IjkMediaPlayer) mediaPlayer).setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
((IjkMediaPlayer) mediaPlayer).setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
}
((IjkMediaPlayer) mediaPlayer).setDataSource(((GSYModel) msg.obj).getUrl(), ((GSYModel) msg.obj).getMapHeadData());
mediaPlayer.setLooping(((GSYModel) msg.obj).isLooping());
if (((GSYModel) msg.obj).getSpeed() != 1 && ((GSYModel) msg.obj).getSpeed() > 0) {
((IjkMediaPlayer) mediaPlayer).setSpeed(((GSYModel) msg.obj).getSpeed());
}
initIJKOption((IjkMediaPlayer) mediaPlayer);
} catch (IOException e) {
e.printStackTrace();
}
}
private void initEXOPlayer(Message msg) {
mediaPlayer = new IjkExoMediaPlayer(context);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(context, Uri.parse(((GSYModel) msg.obj).getUrl()), ((GSYModel) msg.obj).getMapHeadData());
} catch (IOException e) {
e.printStackTrace();
}
}
private void initIJKOption(IjkMediaPlayer ijkMediaPlayer) {
if (optionModelList != null && optionModelList.size() > 0) {
for (VideoOptionModel videoOptionModel : optionModelList) {
if (videoOptionModel.getValueType() == VideoOptionModel.VALUE_TYPE_INT) {
ijkMediaPlayer.setOption(videoOptionModel.getCategory(),
videoOptionModel.getName(), videoOptionModel.getValueInt());
} else {
ijkMediaPlayer.setOption(videoOptionModel.getCategory(),
videoOptionModel.getName(), videoOptionModel.getValueString());
}
}
}
}
private void showDisplay(Message msg) {
if (msg.obj == null && mediaPlayer != null) {
mediaPlayer.setSurface(null);
} else {
Surface holder = (Surface) msg.obj;
if (mediaPlayer != null && holder.isValid()) {
mediaPlayer.setSurface(holder);
}
if (mediaPlayer instanceof IjkExoMediaPlayer) {
if (mediaPlayer != null && mediaPlayer.getDuration() > 30
&& mediaPlayer.getCurrentPosition() < mediaPlayer.getDuration()) {
mediaPlayer.seekTo(mediaPlayer.getCurrentPosition() - 20);
}
}
}
}
public void prepare(final String url, final Map<String, String> 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) {
if (percent > buffterPoint) {
listener().onBufferingUpdate(percent);
} else {
listener().onBufferingUpdate(buffterPoint);
}
}
}
});
}
@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();
}
}
});
}
@Override
public void onCacheAvailable(File cacheFile, String url, int percentsAvailable) {
buffterPoint = percentsAvailable;
}
/**
* 暂停播放
*/
public static void onPause() {
if (GSYVideoManager.instance().listener() != null) {
GSYVideoManager.instance().listener().onVideoPause();
}
}
/**
* 恢复播放
*/
public static void onResume() {
if (GSYVideoManager.instance().listener() != null) {
GSYVideoManager.instance().listener().onVideoResume();
}
}
public AbstractMediaPlayer 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;
}
public int getVideoType() {
return videoType;
}
public List<VideoOptionModel> getOptionModelList() {
return optionModelList;
}
/**
* 设置IJK视频的option
*/
public void setOptionModelList(List<VideoOptionModel> optionModelList) {
this.optionModelList = optionModelList;
}
/**
* 设置了视频的播放类型
* GSYVideoType IJKPLAYER = 0 or IJKEXOPLAYER = 1;
*/
public void setVideoType(Context context, int videoType) {
this.context = context.getApplicationContext();
this.videoType = videoType;
}
public boolean isNeedMute() {
return needMute;
}
/**
* 是否需要静音
*/
public void setNeedMute(boolean needMute) {
this.needMute = needMute;
if (mediaPlayer != null) {
if (needMute) {
mediaPlayer.setVolume(0,0);
} else {
mediaPlayer.setVolume(1, 1);
}
}
}
}