概覽
簡介
Vitamio 能夠流暢播放720P甚至1080P高清MKV,FLV,MP4,MOV,TS,RMVB等常見格式的視頻,還可以在 Android 與 iOS 上跨平臺支持 MMS, RTSP, RTMP, HLS(m3u8) 等常見的多種視頻流媒體協議,包括點播與直播。
Vitamio 憑藉其簡潔易用的 API 接口贏得了全球衆多開發者的青睞,到目前,全球已經有超過 10,000 種應用在使用 Vitamio,覆蓋用戶超過5億。
最近更新較少,上一次更新(2017-04-01)已經是兩年前了,但是這並不妨礙它是一個優秀的框架。
Vitamio 官網:http://www.vitamio.org
github: https://github.com/yixia/VitamioBundle
使用博客:農民伯伯:http://www.cnblogs.com/over140/category/409230.html(開發者之一,有大量的文檔)
本文內容
本文對其使用進行了一些擴展和功能的豐富,將其整理後彙總。除集成外,擴展功能如下:
- 雙擊暫停,開始播放
- 全屏播放
- 倍速播放
- 左邊上下滑動調節亮度
- 右邊上下滑動調節聲音
- 左右滑動快進快退
- 退出時保留播放進度
- 全屏播放時根據手機方向變化,屏幕自動旋轉
- 進度條控件大小和位置的設置
注意事項
個人使用免費,商用需要授權
大家如果商用的話,別忘了去要授權……
集成
導入
github地址: https://github.com/yixia/VitamioBundle
首先從github上下載源文件,然後以 module的方式導入工程中,即可開始使用。
- 導入module,在Android Studio 中依次點擊 File -->New --> Import Module…,然後在彈出框中選擇文件的路徑。
- 添加依賴,打開Project Structure選項卡,點擊左上角的’+'按鈕,然後按照提示添加即可。
目前爲止,github上的代碼已經很久沒有維護了,上次維護應該還是 [2014-04-18] 發佈的 4.2.2 版本。所以並不推薦用在公司項目中,一是很久沒有維護了,二是需要授權。
- 打開app/src/main目錄下的AndroidManifest.xml,註冊io.vov.vitamio.activity.InitActivity
注意:這個InitActivity存在於vitamio/src/對應的目錄下,不需要用戶編寫.
<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" />
至此,vitamio導入完畢.
擴展功能
需求。左側上下滑動調節亮度,右側上下滑動調節聲音,中間添加提示:
界面文件,因爲點擊之後控制器會佈滿屏幕,所及監聽和顯示組件都要添加到 MediaController中
在這裏我們採用手勢去處理
1. 雙擊暫停,開始播放
//播放與暫停
private void playOrPause(){
if (videoView != null)
if (videoView.isPlaying()) {
videoView.pause();
} else {
videoView.start();
}
}
2. 全屏播放
全屏播放,點擊按鈕後隱藏其他控件,重設尺寸即可
半屏播放同理
3. 倍速播放
Vitamio 支持倍速播放,可以根據項目需求進行設置
4. 左邊上下滑動調節亮度
/**
* 滑動改變亮度
*
* @param percent
*/
private void onBrightnessSlide(float percent) {
if (mBrightness < 0) {
mBrightness = activity.getWindow().getAttributes().screenBrightness;
if (mBrightness <= 0.00f)
mBrightness = 0.50f;
if (mBrightness < 0.01f)
mBrightness = 0.01f;
// 顯示
//mOperationBg.setImageResource(R.drawable.video_brightness_bg);
mVolumeBrightnessLayout.setVisibility(View.VISIBLE);
mOperationTv.setVisibility(VISIBLE);
}
5. 右邊上下滑動調節聲音
/**
* 滑動改變聲音大小
*
* @param percent
*/
private void onVolumeSlide(float percent) {
if (mVolume == -1) {
mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
if (mVolume < 0)
mVolume = 0;
// 顯示
mVolumeBrightnessLayout.setVisibility(View.VISIBLE);
mOperationTv.setVisibility(VISIBLE);
}
int index = (int) (percent * mMaxVolume) + mVolume;
if (index > mMaxVolume)
index = mMaxVolume;
else if (index < 0)
index = 0;
if (index >= 10) {
mOperationBg.setImageResource(R.drawable.volmn_100);
} else if (index >= 5 && index < 10) {
mOperationBg.setImageResource(R.drawable.volmn_60);
} else if (index > 0 && index < 5) {
mOperationBg.setImageResource(R.drawable.volmn_30);
} else {
mOperationBg.setImageResource(R.drawable.volmn_no);
}
//DecimalFormat df = new DecimalFormat("######0.00");
mOperationTv.setText((int) (((double) index / mMaxVolume)*100)+"%");
// 變更聲音
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
}
6. 左右滑動快進快退
//滑動監聽
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
float mOldX = e1.getX(), mOldY = e1.getY();
int y = (int) e2.getRawY();
int x = (int) e2.getRawX();
Display disp = activity.getWindowManager().getDefaultDisplay();
int windowWidth = disp.getWidth();
int windowHeight = disp.getHeight();
if (mOldX > windowWidth * 3.0 / 4.0) {// 右邊滑動 屏幕 3/4
onVolumeSlide((mOldY - y) / windowHeight);
} else if (mOldX < windowWidth * 1.0 / 4.0) {// 左邊滑動 屏幕 1/4
onBrightnessSlide((mOldY - y) / windowHeight);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
7. 退出時保留播放進度
當頁面失去焦點時,保存當前播放進度數值,然後當恢復播放的時候,重新設置進度
8. 全屏播放時根據手機方向變化,屏幕自動旋轉
首先確定開始收集轉屏,然後頁面設置中設置爲響應屏幕方向的變化,即可自動切換
9. 進度條控件大小和位置的設置
@Override
protected View makeControllerView() {
View v = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(getResources().getIdentifier("mymediacontroller", "layout", getContext().getPackageName()), this);
v.setMinimumHeight(controllerWidth);
... // 省略其他代碼
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mMaxVolume = mAudioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
return v;
}
完整代碼
public class MyMediaController extends MediaController {
private static final int HIDEFRAM = 0;//控制提示窗口的顯示
private static final int SHOW_PROGRESS = 2;
private GestureDetector mGestureDetector;//手勢監聽類
private ImageButton img_back;//返回鍵
private ImageView img_Battery;//電池電量顯示
private TextView textViewTime;//時間提示
private TextView textViewBattery;//文字顯示電池
private VideoView videoView;
private Activity activity;
private Context context;
private int controllerWidth = 0;//設置mediaController高度爲了使橫屏時top顯示在屏幕頂端
private View mVolumeBrightnessLayout;//提示窗口
private ImageView mOperationBg;//提示圖片
private TextView mOperationTv;//提示文字
private AudioManager mAudioManager;
private SeekBar progress;
private boolean mDragging;
private MediaPlayerControl player;
//最大聲音
private int mMaxVolume;
// 當前聲音
private int mVolume = -1;
//當前亮度
private float mBrightness = -1f;
//返回監聽
private View.OnClickListener backListener = new View.OnClickListener() {
public void onClick(View v) {
if(activity != null){
activity.finish();
}
}
};
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
long pos;
switch (msg.what) {
case HIDEFRAM://隱藏提示窗口
mVolumeBrightnessLayout.setVisibility(View.GONE);
mOperationTv.setVisibility(View.GONE);
break;
}
}
};
//videoview 用於對視頻進行控制的等,activity爲了退出
public MyMediaController(Context context, VideoView videoView , Activity activity) {
super(context);
this.context = context;
this.videoView = videoView;
this.activity = activity;
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
controllerWidth = wm.getDefaultDisplay().getWidth();
mGestureDetector = new GestureDetector(context, new MyGestureListener());
}
@Override
protected View makeControllerView() {
View v = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(getResources().getIdentifier("mymediacontroller", "layout", getContext().getPackageName()), this);
v.setMinimumHeight(controllerWidth);
//TOP
// img_back = (ImageButton) v.findViewById(getResources().getIdentifier("mediacontroller_top_back", "id", context.getPackageName()));
// img_Battery = (ImageView) v.findViewById(getResources().getIdentifier("mediacontroller_imgBattery", "id", context.getPackageName()));
// img_back.setOnClickListener(backListener);
// textViewBattery = (TextView)v.findViewById(getResources().getIdentifier("mediacontroller_Battery", "id", context.getPackageName()));
// textViewTime = (TextView)v.findViewById(getResources().getIdentifier("mediacontroller_time", "id", context.getPackageName()));
img_back = (ImageButton) v.findViewById(R.id.mediacontroller_top_back);
img_Battery = (ImageView) v.findViewById(R.id.mediacontroller_imgBattery);
img_back.setOnClickListener(backListener);
textViewBattery = (TextView)v.findViewById(R.id.mediacontroller_Battery);
textViewTime = (TextView)v.findViewById(R.id.mediacontroller_time);
progress = (SeekBar)v.findViewById(R.id.mediacontroller_seekbar);
//mid
mVolumeBrightnessLayout = (RelativeLayout)v.findViewById(R.id.operation_volume_brightness);
mOperationBg = (ImageView)v.findViewById(R.id.operation_bg);
mOperationTv = (TextView) v.findViewById(R.id.operation_tv);
mOperationTv.setVisibility(View.GONE);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mMaxVolume = mAudioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
return v;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
System.out.println("MYApp-MyMediaController-dispatchKeyEvent");
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGestureDetector.onTouchEvent(event)) return true;
// 處理手勢結束
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
endGesture();
break;
}
return super.onTouchEvent(event);
}
/**
* 手勢結束
*/
private void endGesture() {
mVolume = -1;
mBrightness = -1f;
// 隱藏
myHandler.removeMessages(HIDEFRAM);
myHandler.sendEmptyMessageDelayed(HIDEFRAM, 1);
}
private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
//當收拾結束,並且是單擊結束時,控制器隱藏/顯示
toggleMediaControlsVisiblity();
return super.onSingleTapConfirmed(e);
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
//滑動監聽
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
float mOldX = e1.getX(), mOldY = e1.getY();
int y = (int) e2.getRawY();
int x = (int) e2.getRawX();
Display disp = activity.getWindowManager().getDefaultDisplay();
int windowWidth = disp.getWidth();
int windowHeight = disp.getHeight();
if (mOldX > windowWidth * 3.0 / 4.0) {// 右邊滑動 屏幕 3/4
onVolumeSlide((mOldY - y) / windowHeight);
} else if (mOldX < windowWidth * 1.0 / 4.0) {// 左邊滑動 屏幕 1/4
onBrightnessSlide((mOldY - y) / windowHeight);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
//雙擊暫停或開始
@Override
public boolean onDoubleTap(MotionEvent e) {
playOrPause();
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return super.onFling(e1, e2, velocityX, velocityY);
}
}
/**
* 滑動改變聲音大小
*
* @param percent
*/
private void onVolumeSlide(float percent) {
if (mVolume == -1) {
mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
if (mVolume < 0)
mVolume = 0;
// 顯示
mVolumeBrightnessLayout.setVisibility(View.VISIBLE);
mOperationTv.setVisibility(VISIBLE);
}
int index = (int) (percent * mMaxVolume) + mVolume;
if (index > mMaxVolume)
index = mMaxVolume;
else if (index < 0)
index = 0;
if (index >= 10) {
mOperationBg.setImageResource(R.drawable.volmn_100);
} else if (index >= 5 && index < 10) {
mOperationBg.setImageResource(R.drawable.volmn_60);
} else if (index > 0 && index < 5) {
mOperationBg.setImageResource(R.drawable.volmn_30);
} else {
mOperationBg.setImageResource(R.drawable.volmn_no);
}
//DecimalFormat df = new DecimalFormat("######0.00");
mOperationTv.setText((int) (((double) index / mMaxVolume)*100)+"%");
// 變更聲音
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
}
/**
* 滑動改變亮度
*
* @param percent
*/
private void onBrightnessSlide(float percent) {
if (mBrightness < 0) {
mBrightness = activity.getWindow().getAttributes().screenBrightness;
if (mBrightness <= 0.00f)
mBrightness = 0.50f;
if (mBrightness < 0.01f)
mBrightness = 0.01f;
// 顯示
//mOperationBg.setImageResource(R.drawable.video_brightness_bg);
mVolumeBrightnessLayout.setVisibility(View.VISIBLE);
mOperationTv.setVisibility(VISIBLE);
}
WindowManager.LayoutParams lpa = activity.getWindow().getAttributes();
lpa.screenBrightness = mBrightness + percent;
if (lpa.screenBrightness > 1.0f)
lpa.screenBrightness = 1.0f;
else if (lpa.screenBrightness < 0.01f)
lpa.screenBrightness = 0.01f;
activity.getWindow().setAttributes(lpa);
mOperationTv.setText((int) (lpa.screenBrightness * 100) + "%");
if (lpa.screenBrightness * 100 >= 90) {
mOperationBg.setImageResource(R.drawable.light_100);
} else if (lpa.screenBrightness * 100 >= 80 && lpa.screenBrightness * 100 < 90) {
mOperationBg.setImageResource(R.drawable.light_90);
} else if (lpa.screenBrightness * 100 >= 70 && lpa.screenBrightness * 100 < 80) {
mOperationBg.setImageResource(R.drawable.light_80);
} else if (lpa.screenBrightness * 100 >= 60 && lpa.screenBrightness * 100 < 70) {
mOperationBg.setImageResource(R.drawable.light_70);
} else if (lpa.screenBrightness * 100 >= 50 && lpa.screenBrightness * 100 < 60) {
mOperationBg.setImageResource(R.drawable.light_60);
} else if (lpa.screenBrightness * 100 >= 40 && lpa.screenBrightness * 100 < 50) {
mOperationBg.setImageResource(R.drawable.light_50);
} else if (lpa.screenBrightness * 100 >= 30 && lpa.screenBrightness * 100 < 40) {
mOperationBg.setImageResource(R.drawable.light_40);
} else if (lpa.screenBrightness * 100 >= 20 && lpa.screenBrightness * 100 < 20) {
mOperationBg.setImageResource(R.drawable.light_30);
} else if (lpa.screenBrightness * 100 >= 10 && lpa.screenBrightness * 100 < 20) {
mOperationBg.setImageResource(R.drawable.light_20);
}
}
public void setTime(String time){
if (textViewTime != null)
textViewTime.setText(time);
}
//顯示電量,
public void setBattery(String stringBattery){
if(textViewTime != null && img_Battery != null){
textViewBattery.setText(stringBattery + "%");
int battery = Integer.valueOf(stringBattery);
if(battery < 15)img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_15));
if(battery < 30 && battery >= 15)img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_15));
if(battery < 45 && battery >= 30)img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_30));
if(battery < 60 && battery >= 45)img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_45));
if(battery < 75 && battery >= 60)img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_60));
if(battery < 90 && battery >= 75)img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_75));
if(battery > 90 )img_Battery.setImageDrawable(getResources().getDrawable(R.drawable.battery_90));
}
}
//隱藏/顯示
private void toggleMediaControlsVisiblity(){
if (isShowing()) {
hide();
} else {
show();
}
}
//播放與暫停
private void playOrPause(){
if (videoView != null)
if (videoView.isPlaying()) {
videoView.pause();
} else {
videoView.start();
}
}
}