Android播放器——VitamioPlayer

  • vitamio是一个开源的播放器,在Android端和ios端都有相应的库,支持硬解码,api与Android原生播放器的api类似

  • Vitamio 能够流畅播放720P甚至1080P高清MKV,FLV,MP4,MOV,TS,RMVB等常见格式的视频,还可以在 Android 与 iOS 上跨平台支持 MMS, RTSP, RTMP, HLS(m3u8) 等常见的多种视频流媒体协议,包括点播与直播(官方介绍)。官网地址为:https://www.vitamio.org/

  • 本文主要介绍使用vitamio进行视频播放,包括切换声道、切换音轨、软硬解码的使用。

demo part1下载地址:http://download.csdn.net/detail/sapce_fish/9618279
demo part2下载地址:http://download.csdn.net/detail/sapce_fish/9618281

1.新建Android项目后引入vitamio库

vitamio库

2.编写播放回调接口

package com.space.vitamio;
public interface IMediaCallback
{
    /**
     * 开始播放
     */
    public void onMediaStart();
    /**
     * 播放异常
     */
    public void onMediaError();
    /**
     * 播放完成
     */
    public void onMediaFinished();
}

3.编写播放器父类(方便以后扩展其他播放器)

package com.space.vitamio;
import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.util.DisplayMetrics;
import android.webkit.JavascriptInterface;
public abstract class PlayerInterface
{
    public static final String CHANNEL_LEFT = "Left";// 左声道
    public static final String CHANNEL_RIGHT = "Right";// 右声道
    public static final String CHANNEL_STEREO = "Stereo";// 立体声
    protected Activity mAct;
    /** 播放器事件的回调 */
    protected IMediaCallback mMediaCallback;
    /** 声音管理器 */
    protected AudioManager audioManager;
    /** 屏幕宽度 */
    protected int mScreenWidth;
    /** 屏幕高度 */
    protected int mScreenHeight;
    public PlayerInterface(Activity act, IMediaCallback callback)
    {
        this.mAct = act;
        this.mMediaCallback = callback;
        audioManager = (AudioManager) mAct.getSystemService(Context.AUDIO_SERVICE);
        // 获取屏幕宽高
        DisplayMetrics dpm = new DisplayMetrics();
      act.getWindowManager().getDefaultDisplay().getMetrics(dpm);
        mScreenWidth = dpm.widthPixels;
        mScreenHeight = dpm.heightPixels;
    }
    /**
     * 以全屏方式初始化播放器,设置播放地址,并开始播放
     *
     * @param url
     *            视频播放地址
     */
    public abstract void initMediaPlayer(final String url);
    /**
     * 以小视频方式初始化播放器,设置视频位置和大小,设置播放地址,并开始播放
     *
     * @param url
     *            视频播放地址
     * @param left
     *            
     * @param top
     *            视频top坐标
     * @param width
     *            视频宽度
     * @param height
     *            视频高度
     */
    public abstract void initMediaPlayer(final String url, final int left, final int top, final int width,
                                         final int height);
    public abstract void initMediaPlayer(String url, int left, int top, int width, int height, boolean preferHWDecoder);
    /**
     * 停止播放
     */
    public abstract void stop();
    /**
     * 暂停播放
     */
    public abstract void pause();
    /**
     * 从快进、快退、暂停等状态中恢复播放
     */
    public abstract void resume();
    /**
     * 切换音频声道
     */
    public abstract void switchAudioChannel();
    /** 切换音轨 */
    public abstract void switchTrack();
    /**
     * 获取当前声道,返回值可能是“Left”、“Right”、“Stereo”
     */
    public abstract String getCurrentAudioChannel();
    /**
     * 获取当前音轨
     * @return
     */
    public abstract int getCurrentTrack();
    /**
     * 设置或者取消静音
     *
     * @param muteFlag
     *            静音标志,0表示有声(默认),1表示静音
     */
    public abstract void setMuteFlag(int muteFlag);
    /**
     * 获取当前播放的秒数,注意单位是毫秒!
     *
     * @return
     */
    public abstract long getCurrentPlayTime();
    /**
     * 获取视频的总秒数,注意单位是毫秒!
     *
     * @return
     */
    public abstract long getMediaDuration();
    /**
     * 判断是否正在播放视频
     *
     * @return
     */
    public abstract boolean isPlaying();
    public abstract void playByTime(long seconds);
    /**
     * 开始播放的回调
     */
    protected void jsOnStart()
    {
        if (mAct != null)
        {
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (mMediaCallback != null)
                    {
                        mMediaCallback.onMediaStart();
                    }
                }
            });
        }
    }
    /**
     * 播放错误的回调
     */
    protected void jsOnError()
    {
        if (mAct != null)
        {
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (mMediaCallback != null)
                    {
                        mMediaCallback.onMediaError();
                    }
                }
            });
        }
    }
    /**
     * 播放完成的回调
     */
    protected void jsOnFinished()
    {
        if (mAct != null)
        {
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (mMediaCallback != null)
                    {
                        mMediaCallback.onMediaFinished();
                    }
                }
            });
        }
    }
}

4.编写vitamio播放器类

package com.space.vitamio;

import android.app.Activity;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;

import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
import io.vov.vitamio.MediaPlayer.OnCompletionListener;
import io.vov.vitamio.MediaPlayer.OnErrorListener;
import io.vov.vitamio.MediaPlayer.OnInfoListener;
import io.vov.vitamio.MediaPlayer.OnPreparedListener;
import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener;
import io.vov.vitamio.Vitamio;

/**
 *
 * @author space
 */
public class VitamioPlayer extends PlayerInterface
{
    /** 播放器状态未知 */
    private static final int PLAYER_STATUS_UNKNOW = 0;
    /** 播放器正在初始化 */
    private static final int PLAYER_STATUS_INITING = 1;
    /** 播放器准备好了 */
    private static final int PLAYER_STATUS_PREPARED = 2;
    /** 播放器正在播放... */
    private static final int PLAYER_STATUS_PLAYING = 3;

    /** 当前资源的播放地址 */
    private String mResourceUrl;
    /** 从mPosition处开始播放*/
    private long mPosition = -1;

    /** 视频左边边距 */
    private int mLeft;
    /** 视频上边边距 */
    private int mTop;
    /** 视频的宽度 */
    private int mWidth;
    /** 视频的高度 */
    private int mHeight;

    /** 播放控制类 */
    private MediaPlayer mPlayer;

    /** 主布局 */
    private FrameLayout mMainLayout;
    /** loading圈圈的布局 */
    private View mLoadingLayout;
    /** 播放视频的画布 */
    private SurfaceView mSurfaceView;
    /** 播放视频的surfaceHolder */
    private SurfaceHolder mSurfaceHolder;
    /** 当前是否被调用了停止播放事件 */
    private boolean mIsRequestStoped = false;

    /** 播放器的状态 */
    private int mPlayerStatus;
    /** 当前声道 */
    private String mCurrentChannel = CHANNEL_STEREO;
    /** 是否使用硬解码 */
    private boolean mIsHWDecode;

    /** 音轨map */
    private MediaPlayer.TrackInfo[] mTrackInfo;
    /** 当前音轨 */
    private int mCurrentTrack=0;

    public VitamioPlayer(Activity act, IMediaCallback callback, FrameLayout mainLayout,
                         View loadingLayout)
    {
        super(act, callback);
        mMainLayout = mainLayout;
        mLoadingLayout = loadingLayout;
        mSurfaceView = new SurfaceView(mAct);
        mMainLayout.addView(mSurfaceView, 0);
    }

    /**
     * 以全屏方式初始化播放器,设置播放地址,并开始播放
     *
     * @param url 视频播放地址
     */
    @Override
    public void initMediaPlayer(String url) {
        createPlayerAndPlay(url,0, 0, -1, -1);
    }

    /**
     * 以小视频方式初始化播放器,设置视频位置和大小,设置播放地址,并开始播放
     *
     * @param url    视频播放地址
     * @param left
     * @param top    视频top坐标
     * @param width  视频宽度
     * @param height
     */
    @Override
    public void initMediaPlayer(String url, int left, int top, int width, int height) {
        createPlayerAndPlay(url, left, top, width, height);
    }

    @Override
    public void initMediaPlayer(String url, int left, int top, int width, int height, boolean preferHWDecoder) {
        this.mIsHWDecode = preferHWDecoder;
        createPlayerAndPlay(url, left, top, width, height);
    }

    /**
     * 初始化、创建播放器、画布等,并在创建完成后播放资源
     * @param url
     *            视频播放的地址
     * @param left
     *            距离屏幕左边界距离
     * @param top
     *            距离屏幕上边界距离
     * @param width
     *            小视频的宽度
     * @param height
     *            小视频的高度
     */
    private void createPlayerAndPlay(String url, final int left, final int top, final int width,
                                     final int height)
    {
        if (mAct != null && !mIsRequestStoped)
        {
            // 检查Vitamio是否初始化完成
            if (!Vitamio.isInitialized(mAct))
            {
                return;
            }
            mPlayerStatus = PLAYER_STATUS_INITING;
            // 保存一下参数
            mLeft = left;
            mTop = top;
            mWidth = width;
            mHeight = height;
            mResourceUrl = url;

            // 停止并释放掉播放器
            stopPlayer();
            releasePlayer();
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    // 移除并销毁SurfaceView
                    removeSurfaceView();
                    doCleanUp();

                    // 显示隐藏进度
                    showLoadingLayout(true);
                    // 初始化画布,在surfaceCreated后,再createMediaPlayer
                    boolean isSvCreated = createSurfaceView(mLeft, mTop, mWidth, mHeight);
                    // 如果初始化播放器异常,则通知播放错误
                    if (!isSvCreated)
                    {
                        jsOnError();
                    }
                }
            });
        }
    }
    /**
     * 创建播放器的画布SurfaceView
     */
    @SuppressWarnings("deprecation")
    private boolean createSurfaceView(int leftMargin, int topMargin, int width, int height)
    {
        if (mAct != null && mMainLayout != null)
        {
            width = (width == -1 ? mScreenWidth : width);
            height = (height == -1 ? mScreenHeight : height);

            // 添加新的surfaceView进行播放
            mSurfaceView = new SurfaceView(mAct);
            mMainLayout.addView(mSurfaceView);

            // 获取位置参数
            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mSurfaceView.getLayoutParams();
            if (lp == null)
            {
                lp = new FrameLayout.LayoutParams(width, height);
            }
            else
            {
                lp.width = width;
                lp.height = height;
            }
            // 计算surfaceView的位置
            lp.leftMargin = leftMargin;
            lp.topMargin = topMargin;
            // 改变宽高
            mSurfaceView.setLayoutParams(lp);
            mSurfaceHolder = mSurfaceView.getHolder();
            mSurfaceHolder.addCallback(mCallback);
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);

            return true;
        }
        return false;
    }

    /**
     * 隐藏、移除并销毁surfaceView <br/>
     */
    private void removeSurfaceView()
    {
        if (mMainLayout != null && mSurfaceView != null)
        {
            mSurfaceView.setVisibility(View.GONE);
            mMainLayout.removeView(mSurfaceView);
            mSurfaceView = null;
            mSurfaceHolder = null;
        }
    }

    private SurfaceHolder.Callback mCallback = new Callback()
    {
        @Override
        public void surfaceCreated(SurfaceHolder holder)
        {
            Log.i("space","surfaceView 创建完了");
            mSurfaceHolder = holder;
            createPlayer(mResourceUrl);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
        { }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder)
        {
            mSurfaceHolder = null;
        }
    };

    /**
     * 创建视频播放器
     *
     * @param url
     *            播放地址
     */
    private void createPlayer(String url)
    {
        if (url != null)
        {
            try
            {
                Log.i("space","创建播放器"+url);
                mPlayerStatus = PLAYER_STATUS_INITING;
//                mPlayer = new MediaPlayer(mAct);
                if(mIsHWDecode){
                    mPlayer = new MediaPlayer(mAct,true);
                }else{
                    mPlayer = new MediaPlayer(mAct);
                }
                mPlayer.setDisplay(mSurfaceHolder);
                mPlayer.setDataSource(url);
                mPlayer.prepareAsync();
                mPlayer.setOnBufferingUpdateListener(onBufferUpdateListener);
                mPlayer.setOnCompletionListener(onCompletionListener);
                mPlayer.setOnPreparedListener(onPreparedListener);
                mPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener);
                mPlayer.setOnErrorListener(onErrorListener);
                mPlayer.setOnInfoListener(onInfoListener);

                // 设置视频相关参数
                mPlayer.setVideoChroma(MediaPlayer.VIDEOCHROMA_RGBA);
                mAct.setVolumeControlStream(AudioManager.STREAM_MUSIC);
            }
            catch (Exception e)
            {
                mPlayerStatus = PLAYER_STATUS_UNKNOW;
                // 通知播放异常
                jsOnError();
                e.printStackTrace();
            }
        }
    }

    /**
     * 开始播放视频
     *
     */
    private void startPlay() {
        if (mPlayer != null) {
            // 开始播放
            mPlayer.start();
            mPlayerStatus = PLAYER_STATUS_PLAYING;
            //获取音轨信息
            mTrackInfo = mPlayer.getTrackInfo();

            // 隐藏显示进度
            showLoadingLayout(false);
            // 如果mPosition不为-1,则seek至mPosition处开始播放
            if (mPosition != -1 && mPosition < mPlayer.getDuration())
            {
                mPlayer.seekTo(mPosition);
            }
            jsOnStart();
        }
    }


    /**
     * 停止播放
     *
     */
    @Override
    public void stop()
    {
        // 停止的时候改变一下播放状态
        if (mPlayerStatus != PLAYER_STATUS_UNKNOW)
        {
            mIsRequestStoped = true;
        }

        if (mAct != null)
        {
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (mPlayer != null)
                    {
                        stopPlayer();
                        releasePlayer();
                        mPlayer = null;
                    }
                    mPlayerStatus = PLAYER_STATUS_UNKNOW;
                    mIsRequestStoped = false;

                    removeSurfaceView();
                }
            });
        }
    }

    /**
     * 暂停播放
     *
     */
    public void pause()
    {
        if (mAct != null)
        {
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (mPlayer != null)
                    {
                        mPlayer.pause();
                    }
                }
            });
        }
    }

    /**
     * 当停止的时候继续播放
     *
     */
    public void resume()
    {
        if (mAct != null)
        {
            mAct.runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    if (mPlayer != null)
                    {
                        mPlayer.start();
                    }
                }
            });
        }
    }

    /**
     * 从指定时间开始播放
     *
     * @param seconds
     *            单位为秒
     */
    public void playByTime(long seconds)
    {
        if (mPlayer != null)
        {
            mPlayer.seekTo(seconds);
        }
    }

    /**
     * 获取当前声道,这里只有立体声和左声道,立体声是原唱,左声道是伴唱
     */
    public String getCurrentAudioChannel()
    {
        return mCurrentChannel;
    }

    /**
     * 设置静音
     *
     * @param muteFlag
     * @throws
     */
    public void setMuteFlag(int muteFlag)
    {
        if (mPlayer != null)
        {
            if (muteFlag == 1)
            {
                mPlayer.setVolume(0.0f, 0.0f);
            }
            else if (muteFlag == 0)
            {
                mPlayer.setVolume(1.0f, 1.0f);
            }
        }
    }

    /**
     * 获取当前播放时间
     *
     * @return
     */
    public long getCurrentPlayTime() {
        if (!mIsRequestStoped && mPlayer != null
                && (mPlayerStatus == PLAYER_STATUS_PREPARED || mPlayerStatus == PLAYER_STATUS_PLAYING)) {
            return mPlayer.getCurrentPosition();
        }
        return 0;
    }

    /**
     * 获取播放的总时长
     * @return
     * @throws
     */
    public long getMediaDuration() {
        if (!mIsRequestStoped && mPlayer != null
                && (mPlayerStatus == PLAYER_STATUS_PREPARED || mPlayerStatus == PLAYER_STATUS_PLAYING)) {
            return mPlayer.getDuration();
        }
        return 0;
    }

    /**
     * 停止播放, 并将播放状态置为停止状态
     *
     */
    private void stopPlayer() {
        if (mPlayer != null)
        {
            mPlayer.stop();
            mPlayerStatus = PLAYER_STATUS_UNKNOW;
        }
    }

    /**
     * 释放播放器,并将播放器的播放状态置为停止状态
     *
     */
    private void releasePlayer()
    {
        if (mPlayer != null)
        {
            mPlayer.setDisplay(null);
            mPlayer.release();
            mPlayer = null;
        }
    }

    /**
     * 清除播放参数,并将他们置为初始化状态
     *
     */
    private void doCleanUp()
    {
        /** 视频设置为未准备好 */
        mPlayerStatus = PLAYER_STATUS_UNKNOW;
        /** 标识当前播放类型为原唱 */
        mCurrentChannel = CHANNEL_STEREO;
        /** 将surfaceView的播放器设置null */
        mSurfaceView = null;
        /** 将surfaceHolder置为空 */
        mSurfaceHolder = null;
    }

    private OnPreparedListener onPreparedListener = new OnPreparedListener()
    {

        @Override
        public void onPrepared(MediaPlayer mp)
        {
            Log.i("space","播放器准备好了");
            mPlayerStatus = PLAYER_STATUS_PREPARED;
            // 只有在没有请求停止的信息挂起状态时才能执行播放
            if (!mIsRequestStoped)
            {
                startPlay();
            }
            else
            {
                // 如果停止事件被触发,则不允许再进行播放了
                stop();
                mIsRequestStoped = false;
            }
        }
    };

    private OnErrorListener onErrorListener = new OnErrorListener()
    {

        @Override
        public boolean onError(MediaPlayer mp, int what, int extra)
        {
            mIsRequestStoped = false;
            mPlayerStatus = PLAYER_STATUS_UNKNOW;
            // 隐藏显示进度
            showLoadingLayout(false);
            jsOnError();
            return false;
        }
    };

    private OnVideoSizeChangedListener onVideoSizeChangedListener = new OnVideoSizeChangedListener()
    {

        @Override
        public void onVideoSizeChanged(MediaPlayer mp, int width, int height)
        {
        }
    };

    private OnCompletionListener onCompletionListener = new OnCompletionListener()
    {

        @Override
        public void onCompletion(MediaPlayer mp)
        {
            // 满足时间长度相等,则认为是完成播放
            jsOnFinished();
        }
    };

    private OnBufferingUpdateListener onBufferUpdateListener = new OnBufferingUpdateListener()
    {

        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent)
        {
        }
    };

    private OnInfoListener onInfoListener = new OnInfoListener()
    {

        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra)
        {
            /*
             * switch (what) { case MediaPlayer.MEDIA_INFO_BUFFERING_START: //
             * 开始缓存,暂停播放 // mPlayer.pause(); break; case
             * MediaPlayer.MEDIA_INFO_BUFFERING_END: // 缓存完成,继续播放 //
             * mPlayer.start(); break; case
             * MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED: // 显示 下载速度 break; }
             */
            if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START)
            {
                // 正在缓冲,显示loading圈圈
                showLoadingLayout(true);
            }
            else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
                showLoadingLayout(false);
            }
            return false;
        }
    };

    /**
     * 是否正在播放
     *
     * @return
     */
    public boolean isPlaying()
    {
        if (mPlayer != null && (mPlayerStatus == PLAYER_STATUS_PREPARED || mPlayerStatus == PLAYER_STATUS_PLAYING))
        {
            return mPlayer.isPlaying();
        }

        return false;
    }

    /**
     * 重新开始播放
     */
    public void replay()
    {
        if (mResourceUrl != null)
        {
            createPlayerAndPlay(mResourceUrl, mLeft, mTop, mWidth, mHeight);
        }
    }

    /**
     * 切换音轨
     */
    @Override
    public void switchTrack(){
        if(mPlayer != null && mTrackInfo != null && mTrackInfo.length >0){

            mCurrentTrack = (mCurrentTrack+1)%mTrackInfo.length;

            mPlayer.selectTrack(mCurrentTrack);
        }
    }

    /**
     * 获取当前音轨
     * @return
     */
    @Override
    public int getCurrentTrack(){
        return mCurrentTrack;
    }

    /**
     */
    @Override
    public void switchAudioChannel()
    {
        if (mPlayer != null)
        {
            // 如果当前为原唱状态,则切换到伴唱状态
            if (mCurrentChannel.equals(CHANNEL_STEREO))
            {
                mPlayer.setVolume(1.0f, 0f);
                mCurrentChannel = CHANNEL_LEFT;
            }
            else if(mCurrentChannel.equals(CHANNEL_LEFT)){
                mPlayer.setVolume(0f, 1.0f);
                mCurrentChannel = CHANNEL_RIGHT;
            }
            else
            {
                // 如果当前为伴唱状态,则切换为原唱状态
                mPlayer.setVolume(1.0f, 1.0f);
                mCurrentChannel = CHANNEL_STEREO;
            }
        }
    }


    public void switchAudioChannel(String type){
        switchAudioChannel();
    }


    /**
     * 显示加载等待布局
     *
     * @param isShow
     *            是否显示
     */
    private void showLoadingLayout(boolean isShow)
    {
        if (mLoadingLayout != null)
        {
            if (isShow)
            {
                mLoadingLayout.setVisibility(View.VISIBLE);
            }
            else
            {
                mLoadingLayout.setVisibility(View.GONE);
            }
        }
    }

}

到这里vitamio库已经封装好了,接下来编写界面测试

5.编写测试界面(MainActivity)

package com.space.vitamio;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

import io.vov.vitamio.LibsChecker;
import io.vov.vitamio.utils.Log;

public class MainActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener{
    private FrameLayout mFlayout;

    private Switch mSwDecode;
    private Switch mSwLoop;
    private TextView mTvVideoUrl;

    private TextView mTvVitamioStartTime;
    private TextView mTvVitamioEndTime;

    private LinearLayout mLayoutControl;
    private boolean mIsShow = true;

    private SeekBar mSbVitamio;

    /** 屏幕宽度 */
    protected int mScreenWidth;
    /** 屏幕高度 */
    protected int mScreenHeight;

    /**是否循环播放*/
    private boolean mIsLoop = true;
    /** 使用硬解码 */
    private boolean mIsHWDecode = false;
    /** 视频地址index */
    private int mCurIndex = 0;

    private String[] mVideoUrlArr = new String[]{
            "/storage/sdcard0/i_am_not_yours.ts",
            "/storage/sdcard0/CP0934900049.ts"
    };

    private PlayerInterface mVitamioPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.activity_main);

        // 异步初始化vitamio
        LibsChecker.checkVitamioLibs(this);

        initView();

        initData();
    }

    @Override
    protected void onPause() {
        stopPlayer();
        super.onPause();
    }

    private void initView() {
        mFlayout = (FrameLayout) findViewById(R.id.flayout);

        mLayoutControl = (LinearLayout) findViewById(R.id.ll_control);

        mSwDecode = (Switch) findViewById(R.id.decode);
        mSwLoop = (Switch) findViewById(R.id.loop);

        mTvVideoUrl = (TextView) findViewById(R.id.video_url);
        mTvVitamioStartTime = (TextView) findViewById(R.id.tv_sTime_vitamio);
        mTvVitamioEndTime = (TextView) findViewById(R.id.tv_eTime_vitamio);

        mSbVitamio = (SeekBar) findViewById(R.id.seekbar_vitamio);

        mSwDecode.setOnCheckedChangeListener(this);
        mSwLoop.setOnCheckedChangeListener(this);
    }

    private void initData() {
        // 获取屏幕宽高
        DisplayMetrics dpm = new DisplayMetrics();
        this.getWindowManager().getDefaultDisplay().getMetrics(dpm);
        mScreenWidth = dpm.widthPixels;
        mScreenHeight = dpm.heightPixels;
        mVitamioPlayer = new VitamioPlayer(this,mediaCallback,mFlayout,null);
    }


    //-1初始状态,0正在播放,1暂停
    private int playerStatus = -1;
    public void onClick(View v){
        switch (v.getId()){
            case R.id.flayout:
                if(mIsShow){
                    mLayoutControl.setVisibility(View.GONE);
                    mTvVideoUrl.setVisibility(View.GONE);
                    mIsShow = false;
                }else{
                    mLayoutControl.setVisibility(View.VISIBLE);
                    mTvVideoUrl.setVisibility(View.VISIBLE);
                    mIsShow = true;
                }
                break;
            //播放
            case R.id.player:
                if(playerStatus == 0){
                    if(mVitamioPlayer != null){
                        mVitamioPlayer.pause();
                    }
                    playerStatus = 1;
                    ((Button)findViewById(R.id.player)).setText("播放");
                }else if(playerStatus == 1){

                    if(mVitamioPlayer != null){
                        mVitamioPlayer.resume();
                    }
                    ((Button)findViewById(R.id.player)).setText("暂停");
                    playerStatus = 0;
                }else{
                    startPlayer();
                    ((Button)findViewById(R.id.player)).setText("暂停");
                }
                break;
            //停止
            case R.id.stop:
                Log.i("space","this is stop button");
                stopPlayer();
                break;
            //下一首
            case R.id.next:
                Log.i("space","this is next button");
                playNext();
                break;
            //切换声道
            case R.id.switch_channel:
                mVitamioPlayer.switchAudioChannel();
                Toast.makeText(this,"声道:"+mVitamioPlayer.getCurrentAudioChannel(),Toast.LENGTH_LONG).show();
                break;
            //切换音轨
            case R.id.switch_track:
                mVitamioPlayer.switchTrack();
                Toast.makeText(this,"音轨:"+mVitamioPlayer.getCurrentTrack(),Toast.LENGTH_LONG).show();
                break;
            //快退
            case R.id.rewind:
                if(playerStatus == 0){
                    optionSpeed(10,false);

                }else{
                    Toast.makeText(this,"当前视频不在播放状态,不允许快退",Toast.LENGTH_LONG).show();
                }
                break;
            //快进
            case R.id.fast:
                if(playerStatus == 0){
                    optionSpeed(10,true);
                }else{
                    Toast.makeText(this,"当前视频不在播放状态,不允许快进",Toast.LENGTH_LONG).show();
                }
                break;
        }
    }


    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        switch (buttonView.getId()){
            case R.id.decode:
                if(isChecked){
                    Log.i("space","this is decode 切换为硬解码");
                    Toast.makeText(this,"切换为硬解码",Toast.LENGTH_LONG).show();
                    mIsHWDecode = true;
                    startPlayer();
                }else{
                    Log.i("space","this is decode 切换为软解码");
                    Toast.makeText(this,"切换为软解码",Toast.LENGTH_LONG).show();
                    mIsHWDecode = false;
                    startPlayer();
                }
                break;
            case R.id.loop:
                if(isChecked){
                    Log.i("space","this is loop 设置为列表循环");
                    Toast.makeText(this,"设置为列表循环",Toast.LENGTH_LONG).show();
                    mIsLoop = true;
                }else{
                    Log.i("space","this is loop 设置为单曲循环");
                    Toast.makeText(this,"设置为单曲循环",Toast.LENGTH_LONG).show();
                    mIsLoop = false;

                }
                break;
        }
    }

    private IMediaCallback mediaCallback = new IMediaCallback() {
        @Override
        public void onMediaStart() {
            Log.i("space","onMediaStart()");
        }

        @Override
        public void onMediaError() {
            Log.i("space","onMediaError()");
        }

        @Override
        public void onMediaFinished() {
            if(mIsLoop){
                playNext();
            }else{
                startPlayer();
            }
            Log.i("space","onMediaFinished()");
        }
    };

    private void stopPlayer(){
        if(mVitamioPlayer != null){
            mVitamioPlayer.stop();
        }
        mTvVideoUrl.setText("http://xxxx");
        ((Button)findViewById(R.id.player)).setText("播放");
        playerStatus = -1;
    }

    private void startPlayer(){
        mVitamioPlayer.initMediaPlayer(mVideoUrlArr[mCurIndex],0,0,mScreenWidth,mScreenHeight,mIsHWDecode);
        mTvVideoUrl.setText(mVideoUrlArr[mCurIndex]);
        playerStatus = 0;
        ((Button)findViewById(R.id.player)).setText("暂停");
        refreshSpeed();

    }


    private void playNext(){
        mCurIndex = (mCurIndex+1)%mVideoUrlArr.length;
        startPlayer();
    }

    /**
     * 操作视频快进或快退
     * @param speed 快进或快退进度 单位秒
     * @param isFast true 快进 ,false 快退
     */
    private void optionSpeed(int speed,boolean isFast){
        speed = speed * 1000;
        long dur = mVitamioPlayer.getMediaDuration();
        long cur = mVitamioPlayer.getCurrentPlayTime();
        if(isFast){
            if(cur+speed < dur){
                if(mVitamioPlayer != null){
                    mVitamioPlayer.playByTime(cur+speed);
                }
                Toast.makeText(this,"快进"+(speed/1000)+"s",Toast.LENGTH_SHORT).show();
            }
        }else{
            if(cur-speed > 0){
                if(mVitamioPlayer != null){
                    mVitamioPlayer.playByTime(cur-speed);
                }
                Toast.makeText(this,"快退"+(speed/1000)+"s",Toast.LENGTH_SHORT).show();
            }
        }

    }

    private void refreshSpeed(){
        //设置总时间
        mTvVitamioEndTime.setText(formatTime(mVitamioPlayer.getMediaDuration()));
        long curTime = mVitamioPlayer.getCurrentPlayTime();
        //设置当前时间
        mTvVitamioStartTime.setText(formatTime(curTime));
        mSbVitamio.setMax(1000);
        int speed = 0;
        long max = mSbVitamio.getMax();
        long durat = mVitamioPlayer.getMediaDuration();
        if(durat > 0){
            speed = (int) (curTime*max/durat);
            mSbVitamio.setProgress(speed);
        }
        if(playerStatus != -1){
            mHandle.sendEmptyMessageDelayed(10,1000);
        }
    }

    Handler mHandle = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == 10){
                refreshSpeed();
            }
        }
    };

    /**
     * 将时间为秒的格式化为 分钟:秒
     * @param time 需格式化的时间,单位为毫秒
     * @return
     */
    private String formatTime(long time){
        int t = (int) (time/1000);
        String result = "00:00";
        if(t < 1){
            return result;
        }
        int m = t/60;
        int s = t%60;
        if((m+"").length()==1){
            result = "0"+m;
        }else{
            result = ""+m;
        }
        if((s+"").length()==1){
            result += ":0"+s;
        }else{
            result += ":"+s;
        }
        return result;
    }

}

6.MainActivity布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/video_url"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:gravity="center_vertical"
        android:text="http://xxxxxx"
        android:layout_centerHorizontal="true"
        android:background="#e0dbdb" />

    <FrameLayout
        android:id="@+id/flayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:onClick="onClick"
        android:layout_below="@+id/video_url"
        android:layout_above="@+id/ll_control">
    </FrameLayout>

    <LinearLayout
        android:id="@+id/ll_control"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:visibility="visible">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:background="@android:color/white"
            android:gravity="center_vertical" >
            <TextView
                android:id="@+id/tv_sTime_vitamio"
                android:layout_width="50dp"
                android:layout_height="match_parent"
                android:gravity="center"
                android:background="@android:color/white"
                android:layout_marginLeft="5dp"
                android:text="00:00"
                android:textColor="@android:color/black"
                android:textSize="18dp"/>
            <SeekBar
                android:id="@+id/seekbar_vitamio"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:focusable="true"/>
            <TextView
                android:id="@+id/tv_eTime_vitamio"
                android:layout_width="50dp"
                android:layout_weight="0"
                android:layout_height="match_parent"
                android:gravity="center"
                android:background="@android:color/white"
                android:text="00:00"
                android:textColor="@android:color/black"
                android:layout_marginRight="5dp"
                android:textSize="18dp"/>
        </LinearLayout>

        <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="#7ca491">

            <LinearLayout
                android:id="@+id/rl_control"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/rewind"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:onClick="onClick"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:text="快退" />

                <Button
                    android:id="@+id/player"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:onClick="onClick"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:text="播放" />

                <Button
                    android:id="@+id/fast"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:onClick="onClick"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:text="快进" />
                <Button
                    android:id="@+id/stop"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:onClick="onClick"
                    android:text="停止"/>

                <Button
                    android:id="@+id/next"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:onClick="onClick"
                    android:text="下一首"/>

                <Button
                    android:id="@+id/switch_channel"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:onClick="onClick"
                    android:text="切换声道"/>

                <Button
                    android:id="@+id/switch_track"
                    android:layout_width="80dp"
                    android:layout_height="40dp"
                    android:layout_marginLeft="5dp"
                    android:gravity="center"
                    android:background="@drawable/button_shap"
                    android:onClick="onClick"
                    android:text="切换音轨"/>


                <Switch
                    android:id="@+id/decode"
                    android:layout_width="150dp"
                    android:layout_height="50dp"
                    android:textOff="软解码"
                    android:textOn="硬解码"
                    android:showText="true"
                    android:gravity="center"
                    android:thumb="@drawable/switch_select" />

                <Switch
                    android:id="@+id/loop"
                    android:layout_width="150dp"
                    android:layout_height="50dp"
                    android:textOff="单曲循环"
                    android:textOn="列表循环"
                    android:gravity="center"
                    android:showText="true"
                    android:checked="true"
                    android:layout_marginLeft="10dp"
                    android:thumb="@drawable/switch_select" />
            </LinearLayout>
        </HorizontalScrollView>
    </LinearLayout>

</RelativeLayout>

7.最后别忘了加上权限

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

最后附上两张播放截图
播放截图
这里写图片描述
这里写图片描述

到这里已经介绍了开源播放器vitamio的使用
另外如果有不明白的地方可以留言。有写错或者不好的地方欢迎指正

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值