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库
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的使用
另外如果有不明白的地方可以留言。有写错或者不好的地方欢迎指正