前言
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。下一篇講爲什麼要使用騰訊播放器,原先的播放器爲什麼不可以,以及如何同時使用兩個播放器。