GSYVideoPlayer 是一个比较火的开源框架。其支持Android 系统中的MediaPlayer内核,ExoPlayer 内核, ijkPlayer 内核。 在我使用的过程中发现不支持h265格式的avi 文件播放,所以我实现了一个VLC内核。
1.继承AbstractMediaPlayer,VLCMediaPlayer.java
public class VLCMediaPlayer extends AbstractMediaPlayer {
private final LibVLC mLibVLC ;
private final MediaPlayer mInternalMediaPlayer;
private String mDataSource;
private final VLCMediaPlayerListenerHolder mInternalListenerAdapter;
private final Object mInitLock = new Object();
private static MediaInfo sMediaInfo;
private Media mCurrentMedia = null;
//默认设为1,等开始播放后才能获取到正确的视频宽高
private int videoWidth=1,videoHeight=1;
public VLCMediaPlayer() {
synchronized (mInitLock) {
ArrayList<String> options = new ArrayList<String>();
options.add("--avcodec-codec=h265,h264");
options.add("--rtsp-tcp");
options.add("--aout=opensles");
options.add("--audio-time-stretch");
options.add("-vvv");
mLibVLC = new LibVLC(SYunApplication.getInstance(),options);
mInternalMediaPlayer = new MediaPlayer(mLibVLC);
}
mInternalListenerAdapter= new VLCMediaPlayerListenerHolder(this);
attachInternalListeners();
}
private void attachInternalListeners() {
mInternalMediaPlayer.setEventListener(mInternalListenerAdapter);
}
@Override
public void setDisplay(SurfaceHolder sh) {
Timber.e("call setDisplay ");
}
@Override
public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
mCurrentMedia = new Media(mLibVLC, uri);
mInternalMediaPlayer.setMedia(mCurrentMedia);
}
@Override
public void setDataSource(Context context, Uri uri, Map<String, String> headers) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
mCurrentMedia = new Media(mLibVLC, uri);
mInternalMediaPlayer.setMedia(mCurrentMedia);
}
@Override
public void setDataSource(FileDescriptor fd) throws IOException, IllegalArgumentException, IllegalStateException {
mCurrentMedia = new Media(mLibVLC, fd);
mInternalMediaPlayer.setMedia(mCurrentMedia);
}
@Override
public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
mDataSource=path;
Timber.e(path);
if(path.startsWith("http")||path.startsWith("rtsp")){
mCurrentMedia = new Media(mLibVLC, Uri.parse(mDataSource));
}else {
mCurrentMedia = new Media(mLibVLC, path);
}
mInternalMediaPlayer.setMedia(mCurrentMedia);
}
@Override
public String getDataSource() {
return mDataSource;
}
@Override
public void prepareAsync() throws IllegalStateException {
mCurrentMedia.addOption(":video-paused");
mInternalMediaPlayer.play();
}
@Override
public void start() throws IllegalStateException {
Timber.e("start");
mInternalMediaPlayer.play();
}
@Override
public void stop() throws IllegalStateException {
mInternalMediaPlayer.stop();
}
@Override
public void pause() throws IllegalStateException {
mInternalMediaPlayer.pause();
}
@Override
public void setScreenOnWhilePlaying(boolean screenOn) {
// holder.setKeepScreenOn(true);
}
@Override
public int getVideoWidth() {
return videoWidth;
}
@Override
public int getVideoHeight() {
return videoHeight;
}
@Override
public boolean isPlaying() {
return mInternalMediaPlayer.isPlaying();
}
@Override
public void seekTo(long msec) throws IllegalStateException {
mInternalMediaPlayer.setTime(msec);
}
@Override
public long getCurrentPosition() {
return mInternalMediaPlayer.getTime();
}
@Override
public long getDuration() {
return mInternalMediaPlayer.getLength();
}
@Override
public void release() {
if(mInternalMediaPlayer != null){
mInternalMediaPlayer.release();
mLibVLC.release();
}
}
@Override
public void reset() {
}
@Override
public void setVolume(float leftVolume, float rightVolume) {
mInternalMediaPlayer.setVolume( (int)((leftVolume + rightVolume) * 100/2));
}
@Override
public int getAudioSessionId() {
return mInternalMediaPlayer.getAudioTrack();
}
@Override
public MediaInfo getMediaInfo() {
if (sMediaInfo == null) {
MediaInfo module = new MediaInfo();
module.mVideoDecoder = "android";
module.mVideoDecoderImpl = "HW";
module.mAudioDecoder = "android";
module.mAudioDecoderImpl = "HW";
sMediaInfo = module;
}
return sMediaInfo;
}
@Override
public void setLogEnabled(boolean enable) {
}
@Override
public boolean isPlayable() {
return true;
}
@Override
public void setAudioStreamType(int streamtype) {
}
@Override
public void setKeepInBackground(boolean keepInBackground) {
}
/**
* SAR表示Sample Aspect Ratio,含义是采样宽高比。
* DAR(Display Aspect Ratio)表示显示宽高比,也就是我们经常说的16:9,4:3。
* @return SAR
*/
@Override
public int getVideoSarNum() {
IMedia.VideoTrack vtrack = mInternalMediaPlayer.getCurrentVideoTrack();
int sarNum=vtrack!=null?vtrack.sarNum:1;
getVideoSize(vtrack);
return sarNum;
}
@Override
public int getVideoSarDen() {
IMedia.VideoTrack vtrack = mInternalMediaPlayer.getCurrentVideoTrack();
int sarDen=vtrack!=null?vtrack.sarDen:1;
return sarDen;
}
@Override
public void setWakeMode(Context context, int mode) {
}
@Override
public void setLooping(boolean looping) {
}
@Override
public boolean isLooping() {
return false;
}
@Override
public ITrackInfo[] getTrackInfo() {
return new ITrackInfo[0];
}
@Override
public void setSurface(Surface surface) {
if(surface!=null){
mInternalMediaPlayer.getVLCVout().setVideoSurface(surface,null);
mInternalMediaPlayer.getVLCVout().attachViews(new IVLCVout.OnNewVideoLayoutListener() {
@Override
public void onNewVideoLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) {
Timber.e(" width=%1$d, height=%2$d,visibleWidth=%3$d,visibleHeight=%4$d",width,height,visibleWidth,visibleHeight);
}
});
setWindowSize();
}
}
/**
* 设置窗口大小为全屏,未正式播放拿不到视频帧的宽高,也只能设置成全屏
*/
private void setWindowSize() {
Timber.e("setWindowSize ");
if (GSYVideoType.getShowType() == SCREEN_MATCH_FULL) {
int screenWidth = ScreenUtil.getScreenWidth(SYunApplication.getInstance());
int screenHeight = ScreenUtil.getScreenHeight(SYunApplication.getInstance());
mInternalMediaPlayer.getVLCVout().setWindowSize(screenWidth, screenHeight);
mInternalMediaPlayer.setScale(0);
//视频显示比例
String aspectRatio = String.format("%1$s:%2$s", screenWidth, screenHeight);
Timber.e("setWindowSize ,aspectRatio=%s", aspectRatio);
mInternalMediaPlayer.setAspectRatio(aspectRatio);
} else {
int screenHeight = ScreenUtil.getScreenHeight(SYunApplication.getInstance());
mInternalMediaPlayer.getVLCVout().setWindowSize(videoWidth * screenHeight / videoHeight, screenHeight);
mInternalMediaPlayer.setScale(0);
//视频显示比例
String aspectRatio = String.format("%1$s:%2$s", videoWidth, videoHeight);
Timber.e("getVideoSize ,aspectRatio=%s", aspectRatio);
mInternalMediaPlayer.setAspectRatio(aspectRatio);
}
}
public MediaPlayer getmInternalMediaPlayer() {
return mInternalMediaPlayer;
}
private static class VLCMediaPlayerListenerHolder implements MediaPlayer.EventListener{
public final WeakReference<VLCMediaPlayer> mWeakMediaPlayer;
public VLCMediaPlayerListenerHolder(VLCMediaPlayer mp) {
mWeakMediaPlayer = new WeakReference<VLCMediaPlayer>(mp);
}
@Override
public void onEvent(MediaPlayer.Event event) {
try{
VLCMediaPlayer self = mWeakMediaPlayer.get();
switch(event.type) {
case MediaPlayer.Event.Opening:
if (self == null)
return;
self.pause();
self.notifyOnPrepared();
break;
case MediaPlayer.Event.Playing:
Timber.e("Playing");
break;
case MediaPlayer.Event.Paused:
Timber.e("Paused");
break;
case MediaPlayer.Event.EncounteredError:
Timber.e("EncounteredError");
if (self == null)
return;
self.notifyOnError(MediaPlayer.Event.EncounteredError,-1);
case MediaPlayer.Event.Vout:
Timber.e("Vout");
break;
case MediaPlayer.Event.EndReached:
if (self == null)
return;
self.notifyOnCompletion();
break;
default:
// Timber.e("default"+event.type);
break;
}
if(mWeakMediaPlayer.get().getmInternalMediaPlayer().getPlayerState()==Media.State.Ended){
if (self == null)
return;
self.notifyOnCompletion();
}
}catch (Exception e){
}
}
}
/**
* 读取视频宽高,切换窗口大小时可以触发,获取到视频宽高
* @param track 流信息
*/
private void getVideoSize(IMedia.VideoTrack track) {
if (track!=null) {
if(track.width>0&&track.height>0){
videoWidth = track.width;
videoHeight = track.height;
Timber.e("getVideoSize w=%1$d,h=%2$d", videoWidth, videoHeight);
setWindowSize();
}
}
}
}
2.继承BasePlayerManager实现VLCPlayerManager.java
import android.content.Context;
import android.os.Message;
import android.text.TextUtils;
import android.view.Surface;
import com.shuyu.gsyvideoplayer.cache.ICacheManager;
import com.shuyu.gsyvideoplayer.model.GSYModel;
import com.shuyu.gsyvideoplayer.model.VideoOptionModel;
import com.shuyu.gsyvideoplayer.player.BasePlayerManager;
import java.io.IOException;
import java.util.List;
import tv.danmaku.ijk.media.player.IMediaPlayer;
public class VLCPlayerManager extends BasePlayerManager {
private VLCMediaPlayer mediaPlayer;
private Surface surface;
@Override
public IMediaPlayer getMediaPlayer() {
return mediaPlayer;
}
@Override
public void initVideoPlayer(Context context, Message msg, List<VideoOptionModel> optionModelList, ICacheManager cacheManager) {
mediaPlayer=new VLCMediaPlayer();
GSYModel gsyModel = (GSYModel) msg.obj;
String url = gsyModel.getUrl();
if(!TextUtils.isEmpty(url)){
try {
mediaPlayer.setDataSource(url);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void showDisplay(Message msg) {
if (msg.obj == null && mediaPlayer != null) {
mediaPlayer.setSurface(null);
} else {
Surface holder = (Surface) msg.obj;
surface = holder;
if (mediaPlayer != null && holder.isValid()) {
mediaPlayer.setSurface(holder);
}
}
}
@Override
public void setNeedMute(boolean needMute) {
if (mediaPlayer != null) {
if (needMute) {
mediaPlayer.setVolume(0, 0);
} else {
mediaPlayer.setVolume(1, 1);
}
}
}
@Override
public void setVolume(float left, float right) {
if (mediaPlayer != null) {
mediaPlayer.setVolume(left, right);
}
}
@Override
public void releaseSurface() {
if (surface != null) {
//surface.release();
surface = null;
}
}
@Override
public void release() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public int getBufferedPercentage() {
return -1;
}
@Override
public long getNetSpeed() {
return 0;
}
@Override
public void setSpeedPlaying(float speed, boolean soundTouch) {
}
@Override
public boolean isSurfaceSupportLockCanvas() {
return false;
}
@Override
public void setSpeed(float speed, boolean soundTouch) {
}
@Override
public void start() {
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
@Override
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
@Override
public void pause() {
if (mediaPlayer != null) {
mediaPlayer.pause();
}
}
@Override
public int getVideoWidth() {
if (mediaPlayer != null) {
return mediaPlayer.getVideoWidth();
}
return 0;
}
@Override
public int getVideoHeight() {
if (mediaPlayer != null) {
return mediaPlayer.getVideoHeight();
}
return 0;
}
@Override
public boolean isPlaying() {
if (mediaPlayer != null) {
return mediaPlayer.isPlaying();
}
return false;
}
@Override
public void seekTo(long time) {
if (mediaPlayer != null) {
mediaPlayer.seekTo(time);
}
}
@Override
public long getCurrentPosition() {
if (mediaPlayer != null) {
return mediaPlayer.getCurrentPosition();
}
return 0;
}
@Override
public long getDuration() {
if (mediaPlayer != null) {
return mediaPlayer.getDuration();
}
return 0;
}
@Override
public int getVideoSarNum() {
if (mediaPlayer != null) {
return mediaPlayer.getVideoSarNum();
}
return 1;
}
@Override
public int getVideoSarDen() {
if (mediaPlayer != null) {
return mediaPlayer.getVideoSarDen();
}
return 1;
}
}
3.使用方法:
1.添加依赖
//gsyVideoPlayer播放器
implementation 'com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-java:v8.1.7-release-jitpack'
//更多ijk的编码支持
implementation 'com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-ex_so:v8.1.7-release-jitpack'
//VLC
implementation 'de.mrmaffen:vlc-android-sdk:3.0.0'
2.调用
PlayerFactory.setPlayManager(VLCPlayerManager.class);
mVideoPlayer.setUp(url,true,"");
//设置旋转
orientationUtils = new OrientationUtils(this, mVideoPlayer);
//设置全屏按键功能,这是使用的是选择屏幕,而不是全屏
mVideoPlayer.getFullscreenButton().setOnClickListener(v->{
orientationUtils.resolveByClick();
});
//是否可以滑动调整
mVideoPlayer.setIsTouchWiget(true);
//设置返回按键功能
mVideoPlayer.startPlayLogic();