Vitamio是一个优秀的Android视频框架,很多人也在用,所以这篇文章就是带大家接入Vitamio并且使用的

首先我们要明白一个需求就是,我们需要做一个视频播放器,那这样的话,我们首先想到的就是VideView,但是VideoView说实话,不支持很多视频格式,所以我们换成Vitamio,可以明确的说,Vitamio的使用方式基本上和VideoView是一样的,这也便于我们更好的封装

我们先看下他的官网:​​https://www.vitamio.org/​

这些介绍我就不多BB了,直接点击下载中心可以看到,他提供了两个示例代码:

Android Vitamio演示(eclipse)
Android Vitamio演示(Android Studio)

我们首先推荐的也是Android Studio:​​https://github.com/yixia/VitamioBundleStudio​

你只需要把代码下载下来,我们就可以开始集成了

一.集成踩坑

集成的话,还是万般简单的,你只需要解压下载下来的zip,我们是以 model 的方式集成,也就是vitamio这个包
Vitamio使用篇,打造强悍的视频播放器_android
然后再我们的Android Studio中,点击File - New - Import Model 即可

导入之后就开始我们得到踩坑之旅了

如果你发现无法集成model,你需要在在项目的settings.gradle里配置一下

include ':app',":vitamio"

然后在 app/build.gradle中配置如下

android{
defaultConfig{
ndk{
abiFilters 'armeabi', 'x86','armeabi-v7a'
}
}
}

以及

//Vitamio
implementation project(':vitamio')

相信这些都不是什么问题吧,紧接着我们要配置一下vitamio的build.gradle里

android {
compileSdkVersion 28
//buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
defaultConfig {
minSdkVersion 16
targetSdkVersion 22
}
}

总的来讲就是需要配置

  • compileSdkVersion
  • minSdkVersion
  • targetSdkVersion

至于这三个的版本号,你只需要和app/build.gradle保持一致就行,这里的一个坑就是targetSdkVersion 了,targetSdkVersion 必须<=22,不然某些机型会报错,至于什么原因,你自己去搜索下。

最后我们就可以配置清单文件了,在主工程的清单文件中添加如下:

<!--Vitamio-->
<activity
android:name="io.vov.vitamio.activity.InitActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:launchMode="singleTop"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="stateAlwaysHidden" />

对了,记得配置权限:

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

现在我们就可以开始封装了

二.封装Vitamio

使用方法跟VideoView一样,所以很好的封装

import android.net.Uri;
import android.os.Handler;
import android.os.Message;

import com.xt.gtlauncher.utils.L;

import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.widget.VideoView;

public class VideoManager {

private io.vov.vitamio.widget.VideoView mVideoView;

private OnVideoProgressListener listener;

private static final int H_PROGRESS = 1001;

private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case H_PROGRESS:
if (listener != null) {
//获取当前时长
long currentDuration = getCurrentPosition();
listener.onProgress(currentDuration);
mHandler.sendEmptyMessageDelayed(H_PROGRESS, 1000);
}
break;
}
return false;
}
});

public VideoManager(VideoView mVideoView) {
this.mVideoView = mVideoView;
}

/**
* 设置文件路径
*
* @param path
*/
public void setVideoPath(String path) {
mVideoView.setVideoPath(path);
}

/**
* 设置网络路径
*
* @param uri
*/
public void setVideoURI(Uri uri) {
mVideoView.setVideoURI(uri);
}

/**
* 设置倍数 [0.5 - 2.0]
*
* @param mediaPlayer
* @param speed
*/
public void setPlaybackSpeed(MediaPlayer mediaPlayer, float speed) {
mediaPlayer.setPlaybackSpeed(speed);
}

/**
* 获取当前播放的位置
*
* @return
*/
public long getCurrentPosition() {
return mVideoView.getCurrentPosition();
}

/**
* 获取当前的视频总长度
*
* @return
*/
public long getDuration() {
return mVideoView.getDuration();
}

/**
* 是否播放
*
* @return
*/
public boolean isPlaying() {
return mVideoView.isPlaying();
}

/**
* 播放
*/
public void start() {
mVideoView.start();
//mVideoView.requestFocus();
mHandler.sendEmptyMessage(H_PROGRESS);
}

/**
* 暂停
*/
public void pause() {
mVideoView.pause();
}

/**
* 重新播放
*/
public void resume() {
mVideoView.resume();
}

/**
* 停止播放 释放资源
*/
public void stopPlayback() {
mVideoView.stopPlayback();
mHandler.removeMessages(H_PROGRESS);
}

/**
* 从第几毫秒开始播放
*
* @param msec
*/
public void seekTo(int msec) {
mVideoView.seekTo(msec);
}

/**
* 设置控制器
*
* @param controller
*/
public void setMediaController(io.vov.vitamio.widget.MediaController controller) {
mVideoView.setMediaController(controller);
}

/**
* 监听播放完毕
*
* @param l
*/
public void setOnCompletionListener(io.vov.vitamio.MediaPlayer.OnCompletionListener l) {
mVideoView.setOnCompletionListener(l);
}

/**
* 监听发生错误
*
* @param l
*/
public void setOnErrorListener(io.vov.vitamio.MediaPlayer.OnErrorListener l) {
mVideoView.setOnErrorListener(l);
}

/**
* 监听视频装载完成
*
* @param l
*/
public void setOnPreparedListener(io.vov.vitamio.MediaPlayer.OnPreparedListener l) {
mVideoView.setOnPreparedListener(l);
}

/**
* 监听进度
*
* @param listener
*/
public void setOnVideoProgress(OnVideoProgressListener listener) {
this.listener = listener;
}

public interface OnVideoProgressListener {
void onProgress(long progress);
}
}

这里特别注意一下,我封装的过程中增加了进度的反馈,所以大家可以根据更方便的更新进度条

三.Vitamio的使用

先看下我的界面吧

<?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">

<io.vov.vitamio.widget.VideoView
android:id="@+id/mVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<!--标题-->
<LinearLayout
android:gravity="center_vertical"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/iv_back"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:text="--"
android:id="@+id/tv_video_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

<!--控制-->
<LinearLayout
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<SeekBar
android:thumb="@drawable/img_seekbar_tum"
android:id="@+id/mSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<LinearLayout
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<ImageView
android:id="@+id/iv_control"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:text="--"
android:id="@+id/tv_video_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

</LinearLayout>

</RelativeLayout>

Vitamio使用篇,打造强悍的视频播放器_android_02
这个界面很简单,上面一个返回键和一个标题,下面一个控制键和一个时间显示

再来看下代码是如何实现的

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

import io.vov.vitamio.Vitamio;
import io.vov.vitamio.widget.VideoView;

public class VideoActivity extends BaseActivity implements View.OnClickListener {

private VideoView mVideoView;
private TextView tv_video_name;
private SeekBar mSeekBar;
private TextView tv_video_time;
private ImageView iv_back;
private ImageView iv_control;

private VideoManager mVideoManager;

private String videoName;
private String videoPath;
private String videoAllDuration;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);

initView();
}

private void initView() {

Intent intent = getIntent();
videoName = intent.getStringExtra("name");
videoPath = intent.getStringExtra("path");

//Test
videoName = "Test";
videoPath = "/sdcard/Test.mp4";

mVideoView = (VideoView) findViewById(R.id.mVideoView);
tv_video_name = (TextView) findViewById(R.id.tv_video_name);
mSeekBar = (SeekBar) findViewById(R.id.mSeekBar);
tv_video_time = (TextView) findViewById(R.id.tv_video_time);
iv_back = (ImageView) findViewById(R.id.iv_back);
iv_control = (ImageView) findViewById(R.id.iv_control);

iv_control.setOnClickListener(this);
iv_back.setOnClickListener(this);

tv_video_name.setText(videoName);

initVideo();
}

private void initVideo() {

mVideoManager = new VideoManager(mVideoView);
mVideoManager.setVideoPath(videoPath);

mVideoManager.setOnPreparedListener(new io.vov.vitamio.MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(io.vov.vitamio.MediaPlayer mp) {
L.i("onPrepared");
mVideoManager.setPlaybackSpeed(mp, 1.0f);
long allDuration = mVideoManager.getDuration();
videoAllDuration = CommonUtils.formatDuring(allDuration);
mSeekBar.setMax((int) allDuration);
mVideoManager.start();
}
});

mVideoManager.setOnCompletionListener(new io.vov.vitamio.MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(io.vov.vitamio.MediaPlayer mediaPlayer) {
L.i("onCompletion");
}
});

mVideoManager.setOnVideoProgress(new VideoManager.OnVideoProgressListener() {
@Override
public void onProgress(long progress) {
mSeekBar.setProgress((int) progress);
tv_video_time.setText(CommonUtils.formatDuring(progress) + "/" + videoAllDuration);
}
});

mVideoManager.setOnErrorListener(new io.vov.vitamio.MediaPlayer.OnErrorListener() {
@Override
public boolean onError(io.vov.vitamio.MediaPlayer mediaPlayer, int i, int i1) {
L.e("i:" + i + "i1" + i1);
return false;
}
});

mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {

}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mVideoManager.seekTo(mSeekBar.getProgress());
}
});
}

@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_back:
finish();
break;
case R.id.iv_control:
if(mVideoManager.isPlaying()){
mVideoManager.pause();
}else{
mVideoManager.start();
}
break;
}
}

@Override
protected void onResume() {
super.onResume();
mVideoManager.resume();
}

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

@Override
protected void onDestroy() {
super.onDestroy();
mVideoManager.stopPlayback();
}
}

这份代码可谓是很精简了,大概的流程我说下:

首先VideoManager初始化后设置路径,这里不光可以设置本地File路径也可以是网络路径,就需要setVideoURI即可。然后设置各种监听:

setOnPreparedListener设置就是当加载好视频之后的回调,这个时候我可以设置一下播放倍数,以及获取总时长和设置进度的总时长,然后开始播放视频

setOnCompletionListener 监听播放完成

setOnVideoProgress 不断通知刷新进度

setOnErrorListener 播放错误

setOnSeekBarChangeListener 进度条的拖拽 这里我调用了seekTo实现进度拖拽

最后绑定了一下生命周期即可了,这里用到了一个毫秒转换时长的方法

public class CommonUtils {

/**
* 毫秒转换成小时
* @param mss
* @return
*/
public static String formatDuring(long mss) {
long hours = (mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60);
long seconds = (mss % (1000 * 60)) / 1000;

String h = "";
String m = "";
String s = "";
if(hours < 10){
h = "0" + hours;
}else{
h = hours + "";
}

if(minutes < 10){
m = "0" + minutes;
}else{
m = minutes + "";
}

if(seconds < 10){
s = "0" + seconds;
}else{
s = seconds + "";
}

return h + ":" + m + ":" + s;
}
}

到这里就本文就结束了,来看下最终的效果吧
Vitamio使用篇,打造强悍的视频播放器_android_03