gsyVideoPlayer直播短視頻回放,集成騰訊播放器

前言

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章