前言
gsyVideoPlayer是一个很棒的播放器,也可以当成是对ijkPlayer的封装库。
在初始化时,可以写如下代码。当然这是默认的,可以不写。
PlayerFactory.setPlayManager(IjkPlayerManager.class);
默认选择ijkplayer播放,那么像使用其他播放器怎么办,gsyVideoPlayer提供了如下选择:
PlayerFactory.setPlayManager(IjkPlayerManager.class);//ijk内核,默认模式
PlayerFactory.setPlayManager(SystemPlayerManager.class);//系统内核模式
PlayerFactory.setPlayManager(Exo2PlayerManager.class);//EXOPlayer内核
但是这三种都不是自己想用的怎么办,如果使用腾讯播放器如何集成进去?
翻看PlayerFactory的源码,在 getPlayManager 方法会返回一个IPlayerManager对象,那么我只要写一个QQPlayerManager,然后在这样初始化就行了。
PlayerFactory.setPlayManager(QQPlayerManager.class);//使用腾讯播放器
集成腾讯播放器
在写QQPlayerManager前,需要去腾讯播放器网站 下载SDK。然后如下方式集成:
compile(name: 'LiteAVSDK_Player', ext: 'aar')
//compile(name: 'libsuperplayer', ext: 'aar')//使用gsyVideoPlayer,这个就可以不要了
接着就可以直接写了,QQPlayerManager要实现IPlayerManager,那么写起来只要将接口IPlayerManager的方法实现既可以,此处就直接贴代码了。
QQPlayerManager.java
package com.shopshops.cn.player;
import android.content.Context;
import android.media.AudioManager;
import android.os.Message;
import android.view.Surface;
import com.shopshops.cn.BuildConfig;
import com.shuyu.gsyvideoplayer.cache.ICacheManager;
import com.shuyu.gsyvideoplayer.model.GSYModel;
import com.shuyu.gsyvideoplayer.model.VideoOptionModel;
import com.shuyu.gsyvideoplayer.player.IPlayerManager;
import java.util.List;
import tv.danmaku.ijk.media.player.IMediaPlayer;
public class QQPlayerManager implements IPlayerManager {
private QQMediaPlayer mediaPlayer;
private boolean release;
private Surface surface;
@Override
public IMediaPlayer getMediaPlayer() {
return mediaPlayer;
}
@Override
public void initVideoPlayer(Context context, Message message, List<VideoOptionModel> optionModelList, ICacheManager cacheManager) {
boolean enableHardware = true;
/*GSYVideoManager videoManager = GSYVideoManager.instance();
String playTag = videoManager.getPlayTag();
if (!TextUtils.isEmpty(playTag))
enableHardware = playTag.startsWith("m3u8Speed");*/
mediaPlayer = new QQMediaPlayer(context, enableHardware);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
release = false;
GSYModel gsyModel = (GSYModel) message.obj;
try {
if (gsyModel.isCache() && cacheManager != null) {
cacheManager.doCacheLogic(context, mediaPlayer, gsyModel.getUrl(), gsyModel.getMapHeadData(), gsyModel.getCachePath());
} else mediaPlayer.setDataSource(gsyModel.getUrl());
mediaPlayer.setLooping(gsyModel.isLooping());
if (gsyModel.getSpeed() != 1 && gsyModel.getSpeed() > 0) {
setSpeed(gsyModel.getSpeed());
}
} catch (Exception e) {
if (BuildConfig.DEBUG) e.printStackTrace();
}
}
@Override
public void showDisplay(Message msg) {
Surface holder = (Surface) msg.obj;
if (holder == null && mediaPlayer != null && !release) {
mediaPlayer.setSurface(null);
} else if (holder != null) {
if (mediaPlayer != null && holder.isValid() && !release) {
mediaPlayer.setSurface(holder);
}
//if (surface != null) surface.release();
surface = holder;
}
}
@Override
public void setNeedMute(boolean needMute) {//是否静音
if (mediaPlayer != null && !release) {
if (needMute) {
mediaPlayer.setVolume(0, 0);
} else mediaPlayer.setVolume(1, 1);
}
}
@Override
public void releaseSurface() {
if (surface != null) {
surface.release();
surface = null;
}
}
@Override
public void release() {
if (mediaPlayer != null) {
release = true;
mediaPlayer.release();
}
}
@Override
public int getBufferedPercentage() {
if (mediaPlayer == null) return -1;
else return (int) mediaPlayer.getMediaPlayer().getBufferDuration();
}
@Override
public long getNetSpeed() {
//if (mediaPlayer == null)
return 0;
}
@Override
public void setSpeedPlaying(float speed, boolean soundTouch) {
}
@Override
public boolean isSurfaceSupportLockCanvas() {
return false;
}
@Override
public void setSpeed(float speed, boolean soundTouch) {
setSpeed(speed);
}
private void setSpeed(float speed) {
if (release) {
return;
}
if (mediaPlayer != null && mediaPlayer.getMediaPlayer() != null && mediaPlayer.isPlayable()) {
mediaPlayer.getMediaPlayer().setRate(speed);
}
}
@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 0;
else return mediaPlayer.getVideoWidth();
}
@Override
public int getVideoHeight() {
if (mediaPlayer == null) return 0;
else return mediaPlayer.getVideoHeight();
}
@Override
public boolean isPlaying() {
if (mediaPlayer == null) return false;
else return mediaPlayer.isPlaying();
}
@Override
public void seekTo(long time) {
if (mediaPlayer == null) return;
else mediaPlayer.seekTo(time);
}
@Override
public long getCurrentPosition() {
if (mediaPlayer == null) return 0;
else return mediaPlayer.getCurrentPosition();
}
@Override
public long getDuration() {
if (mediaPlayer == null) return 0;
else return mediaPlayer.getDuration();
}
@Override
public int getVideoSarNum() {
if (mediaPlayer == null) return 0;
else return mediaPlayer.getVideoSarNum();
}
@Override
public int getVideoSarDen() {
if (mediaPlayer == null) return 0;
else return mediaPlayer.getVideoSarDen();
}
}
initVideoPlayer用于初始化mediaPlayer ,mediaPlayer 是视频播放的核心,那么这儿也就少不了使用腾讯的mediaPlayer 。
QQMediaPlayer.java
package com.shopshops.cn.player;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.view.Surface;
import android.view.SurfaceHolder;
import com.shopshops.cn.BuildConfig;
import com.shopshops.cn.base.AppConstant;
import com.shopshops.mylibrary.Logger;
import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXVodPlayer;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.Map;
import tv.danmaku.ijk.media.player.AbstractMediaPlayer;
import tv.danmaku.ijk.media.player.MediaInfo;
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
public class QQMediaPlayer extends AbstractMediaPlayer {
private TXVodPlayer txVodPlayer;
private MediaInfo mediaInfo;
private boolean mIsReleased;
private boolean isPause;
private String url;
private Surface surface;
private boolean canStart;
private long progress_ms;//播放进度
private long duration_ms_total;//视频总长
private Context mContext;
//notifyOnError
public QQMediaPlayer(Context context, boolean enableHardware) {
this.mContext = context;
txVodPlayer = new TXVodPlayer(context);
txVodPlayer.enableHardwareDecode(enableHardware);
txVodPlayer.setVodListener(new ITXVodPlayListener() {
@Override
public void onPlayEvent(TXVodPlayer txVodPlayer, int event, Bundle param) {
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "--event--" + event);
if (event == TXLiveConstants.PLAY_EVT_PLAY_BEGIN) {//视频播放开始
notifyOnPrepared();
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "视频播放开始");
} else if (event == TXLiveConstants.PLAY_EVT_VOD_LOADING_END) {//loadingEnd
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "loadingEnd");
//没有这个事件,发一个广播出去
LocalBroadcastManager.getInstance(mContext).sendBroadcast(new Intent(AppConstant.PLAY_EVT_VOD_LOADING_END));
} else if (event == TXLiveConstants.PLAY_EVT_PLAY_PROGRESS) {//视频播放进度
// 加载进度, 单位是毫秒
int duration_ms = param.getInt(TXLiveConstants.EVT_PLAYABLE_DURATION_MS);
// 播放进度, 单位是毫秒
progress_ms = param.getInt(TXLiveConstants.EVT_PLAY_PROGRESS_MS);
// 视频总长, 单位是毫秒
duration_ms_total = param.getInt(TXLiveConstants.EVT_PLAY_DURATION_MS);
if (BuildConfig.DEBUG) {
Logger.i("--xcc--QQMediaPlayer", "播放进度:" + param.getInt(TXLiveConstants.EVT_PLAY_PROGRESS_MS));
}
notifyOnBufferingUpdate(duration_ms);
} else if (event == TXLiveConstants.PLAY_EVT_PLAY_END) {//视频播放结束
notifyOnCompletion();
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "视频播放结束");
} else if (event == TXLiveConstants.PLAY_ERR_NET_DISCONNECT || event == TXLiveConstants.PLAY_WARNING_RECONNECT) {//网络断连
notifyOnError(event, 1);
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "网络断连");
} else if (event == TXLiveConstants.PLAY_WARNING_VIDEO_DECODE_FAIL) {//当前视频帧解码失败
notifyOnError(event, 1);
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "当前视频帧解码失败");
} else if (event == TXLiveConstants.PLAY_WARNING_AUDIO_DECODE_FAIL) {//当前音频帧解码失败
notifyOnError(event, 1);
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "当前音频帧解码失败");
} else if (event == TXLiveConstants.PLAY_WARNING_HW_ACCELERATION_FAIL) {//硬解失败
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "硬解失败");
} else if (event == TXLiveConstants.PLAY_EVT_CHANGE_RESOLUTION) {//视频分辨率改变
notifyOnVideoSizeChanged(param.getInt(TXLiveConstants.EVT_PARAM1), param.getInt(TXLiveConstants.EVT_PARAM2), getVideoSarNum(), getVideoSarNum());
if (BuildConfig.DEBUG) Logger.i("--xcc--QQMediaPlayer", "视频分辨率改变");
}
}
@Override
public void onNetStatus(TXVodPlayer txVodPlayer, Bundle bundle) {
}
});
}
@Override
public void setDisplay(SurfaceHolder sh) {
Surface surface = sh.getSurface();
setSurface(surface);
}
@Override
public void setDataSource(Context context, Uri uri) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
this.url = uri.getPath();
}
@Override
public void setDataSource(Context context, Uri uri, Map<String, String> map) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
this.url = uri.toString();
}
@Override
public void setDataSource(FileDescriptor fileDescriptor) throws IOException, IllegalArgumentException, IllegalStateException {
}
@Override
public void setDataSource(String url) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
this.url = url;
}
@Override
public String getDataSource() {
return url;
}
@Override
public void prepareAsync() throws IllegalStateException {
notifyOnPrepared();
}
@Override
public void start() throws IllegalStateException {
if (isPause) {//暂停后恢复播放
isPause = false;
txVodPlayer.resume();
} else {
if (TextUtils.isEmpty(url) || surface == null) {
canStart = true;
return;
}
this.txVodPlayer.startPlay(url);
}
}
@Override
public void stop() throws IllegalStateException {
isPause = false;
this.txVodPlayer.stopPlay(false);
}
@Override
public void pause() throws IllegalStateException {
isPause = true;
this.txVodPlayer.pause();
}
@Override
public void setScreenOnWhilePlaying(boolean screenOn) {
//txVodPlayer.setScreenOnWhilePlaying(screenOn);
}
@Override
public int getVideoWidth() {
return txVodPlayer.getWidth();
}
@Override
public int getVideoHeight() {
return txVodPlayer.getHeight();
}
@Override
public boolean isPlaying() {
return txVodPlayer.isPlaying();
}
@Override
public void seekTo(long msec) throws IllegalStateException {
float v = msec / 1000.0f;
this.txVodPlayer.seek(v);//腾讯这儿是百分比
}
@Override
public long getCurrentPosition() {
return progress_ms;
//return (long) txVodPlayer.getCurrentPlaybackTime();
}
@Override
public long getDuration() {
return duration_ms_total;
//float duration = txVodPlayer.getDuration();
//return (long) duration;
}
@Override
public void release() {
txVodPlayer.stopPlay(true);
this.mIsReleased = true;
this.resetListeners();
}
@Override
public void reset() {
//txVodPlayer.resume();//这个是恢复播放的
this.resetListeners();
}
@Override
public void setVolume(float leftVolume, float rightVolume) {
txVodPlayer.setMute(leftVolume + rightVolume == 0);
}
@Override
public int getAudioSessionId() {
return 0;
}
@Override
public MediaInfo getMediaInfo() {
if (mediaInfo == null) {
MediaInfo module = new MediaInfo();
module.mVideoDecoder = "QQMediaPlayer";
module.mVideoDecoderImpl = "HW";
module.mAudioDecoder = "QQMediaPlayer";
module.mAudioDecoderImpl = "HW";
mediaInfo = module;
}
return mediaInfo;
}
@Override
public void setLogEnabled(boolean b) {
}
@Override
public boolean isPlayable() {
return true;
}
@Override
public void setAudioStreamType(int streamtype) {
}
@Override
public void setKeepInBackground(boolean keepInBackground) {
}
@Override
public int getVideoSarNum() {
return 1;
}
@Override
public int getVideoSarDen() {
return 1;
}
@Override
public void setWakeMode(Context context, int mode) {
}
@Override
public void setLooping(boolean b) {
txVodPlayer.setLoop(b);
}
@Override
public boolean isLooping() {
return txVodPlayer.isLoop();
}
@Override
public ITrackInfo[] getTrackInfo() {
return new ITrackInfo[0];
}
@Override
public void setSurface(Surface surface) {
if (surface == this.surface) return;
this.surface = surface;
/*if (surface == null) {
if (!isPause) pause();
}*/
txVodPlayer.setSurface(surface);
if (surface == null) return;
if (TextUtils.isEmpty(url)) return;
if (canStart) {
canStart = false;
start();
/*} else if (isPause) {
start();*/
}
}
public TXVodPlayer getMediaPlayer() {
return txVodPlayer;
}
}
QQMediaPlayer需要继承AbstractMediaPlayer,实现里面抽象方法即可,同时TXVodPlayer是腾讯播放器的核心。这样做就可以让原先使用gsyVideoPlayer的项目,更快的切换到QQMediaPlayer。下一篇讲为什么要使用腾讯播放器,原先的播放器为什么不可以,以及如何同时使用两个播放器。