开源全能播放器Vitamio的使用
原文链接:简书@jxnk25,http://www.jianshu.com/p/d50a67ba253c
Vitamio简介:Vitamio是一个支持所有Android设备的多媒体框架。Vitamio与Android默认的MediaPlayer工作方式相似,但包含更加强大的功能!(注意:Vitamio商业化后个人免费、公司收费)
vitamio官网:https://www.vitamio.org
vitamio SDK地址:https://github.com/yixia/VitamioBundle
之前开发一个视频播放类的项目,需要实现在线播放的功能,找了很多视频播放框架,觉得Vitamio视频播放框架还不错,也相对稳定,但是在网上找了很多教程都少之又少,Vitamio官网写的教程也不是很清晰,所以就自己就把Vitamio在github上的demo进行研究,花了点时间写了个demo出来并且将Vitamio的视频控制器界面进行自定义,支持视频亮度、音量的调节,话不多说,先上效果图。
自定义视频控制器
目前,作者只实现了自定义手势调节亮度、音量的加减以及播放控制的功能,更多的功能等待着大家一起去挖掘。
使用步骤
1、引入vitamio SDK的方式有两种:
- 直接以module的方式引入
- 通过Complie的方式引入
作者是采用的第一种方式,下面是一些需要注意的地方:
清单文件配置,权限设置:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
application配置:
<!-- 必须初始化 -->
<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" />
主要代码
播放视频代码
package com.stx.vitamiodemo;import android.content.res.Configuration;import android.net.Uri;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.ProgressBar;import android.widget.TextView;import io.vov.vitamio.LibsChecker;import io.vov.vitamio.MediaPlayer;import io.vov.vitamio.Vitamio;import io.vov.vitamio.widget.MediaController;import io.vov.vitamio.widget.VideoView;/*** Vitamio视频播放框架Demo*/public class MainActivity extends AppCompatActivity implements MediaPlayer.OnInfoListener,MediaPlayer.OnBufferingUpdateListener{//视频地址private String path = "http://baobab.wdjcdn.com/145076769089714.mp4";private Uri uri;private ProgressBar pb;private TextView downloadRateView, loadRateView;private MediaController mMediaController;private CustomMediaController mCustomMediaController;private VideoView mVideoView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//定义全屏参数int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;//获得当前窗体对象Window window = MainActivity.this.getWindow();//设置当前窗体为全屏显示window.setFlags(flag, flag);//必须写这个,初始化加载库文件Vitamio.initialize(this);//设置视频解码监听if (!LibsChecker.checkVitamioLibs(this)) {return;}setContentView(R.layout.activity_main);initView();initData();}//初始化控件private void initView() {mVideoView = (VideoView) findViewById(R.id.buffer);mMediaController= new MediaController(this);mCustomMediaController=new CustomMediaController(this,mVideoView,this);mCustomMediaController.setVideoName("白火锅 x 红火锅");pb = (ProgressBar) findViewById(R.id.probar);downloadRateView = (TextView) findViewById(R.id.download_rate);loadRateView = (TextView) findViewById(R.id.load_rate);}//初始化数据private void initData() {uri = Uri.parse(path);mVideoView.setVideoURI(uri);//设置视频播放地址mVideoView.setMediaController(mCustomMediaController);mVideoView.setVideoQuality(MediaPlayer.VIDEOQUALITY_HIGH);//高画质mMediaController.show(5000);mVideoView.requestFocus();mVideoView.setOnInfoListener(this);mVideoView.setOnBufferingUpdateListener(this);mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mediaPlayer) {mediaPlayer.setPlaybackSpeed(1.0f);}});}@Overridepublic boolean onInfo(MediaPlayer mp, int what, int extra) {switch (what) {case MediaPlayer.MEDIA_INFO_BUFFERING_START:if (mVideoView.isPlaying()) {mVideoView.pause();pb.setVisibility(View.VISIBLE);downloadRateView.setText("");loadRateView.setText("");downloadRateView.setVisibility(View.VISIBLE);loadRateView.setVisibility(View.VISIBLE);}break;case MediaPlayer.MEDIA_INFO_BUFFERING_END:mVideoView.start();pb.setVisibility(View.GONE);downloadRateView.setVisibility(View.GONE);loadRateView.setVisibility(View.GONE);break;case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:downloadRateView.setText("" + extra + "kb/s" + " ");break;}return true;}@Overridepublic void onBufferingUpdate(MediaPlayer mp, int percent) {loadRateView.setText(percent + "%");}@Overridepublic void onConfigurationChanged(Configuration newConfig) {//屏幕切换时,设置全屏if (mVideoView != null){mVideoView.setVideoLayout(VideoView.VIDEO_LAYOUT_SCALE, 0);}super.onConfigurationChanged(newConfig);}}
自定义视频控制器
主要实现了手势调节视频亮度、音量的加减控制。
package com.stx.vitamiodemo;import android.app.Activity;import android.content.Context;import android.media.AudioManager;import android.os.Handler;import android.os.Message;import android.view.Display;import android.view.GestureDetector;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.ImageButton;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.SeekBar;import android.widget.TextView;import io.vov.vitamio.widget.MediaController;import io.vov.vitamio.widget.VideoView;/*** Created by xhb on 2016/3/1.* 自定义视频控制器*/public class CustomMediaController extends MediaController {private static final int HIDEFRAM = 0;//控制提示窗口的显示private GestureDetector mGestureDetector;private ImageButton img_back;//返回按钮private TextView mFileName;//文件名private VideoView videoView;private Activity activity;private Context context;private String videoname;//视频名称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() {@Overridepublic void handleMessage(Message msg) {long pos;switch (msg.what) {case HIDEFRAM://隐藏提示窗口mVolumeBrightnessLayout.setVisibility(View.GONE);mOperationTv.setVisibility(View.GONE);break;}}};//videoview 用于对视频进行控制的等,activity为了退出public CustomMediaController(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());}@Overrideprotected View makeControllerView() {//此处的 mymediacontroller 为我们自定义控制器的布局文件名称View v = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(getResources().getIdentifier("mymediacontroller", "layout", getContext().getPackageName()), this);v.setMinimumHeight(controllerWidth);//获取控件img_back = (ImageButton) v.findViewById(getResources().getIdentifier("mediacontroller_top_back", "id",context.getPackageName()));mFileName = (TextView) v.findViewById(getResources().getIdentifier("mediacontroller_filename", "id",context.getPackageName()));if (mFileName != null) {mFileName.setText(videoname);}//声音控制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);//注册事件监听img_back.setOnClickListener(backListener);return v;}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {System.out.println("MYApp-MyMediaController-dispatchKeyEvent");return true;}@Overridepublic 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 {@Overridepublic boolean onSingleTapUp(MotionEvent e) {return false;}/*** 因为使用的是自定义的mediaController 当显示后,mediaController会铺满屏幕,* 所以VideoView的点击事件会被拦截,所以重写控制器的手势事件,* 将全部的操作全部写在控制器中,* 因为点击事件被控制器拦截,无法传递到下层的VideoView,* 所以 原来的单机隐藏会失效,作为代替,* 在手势监听中onSingleTapConfirmed()添加自定义的隐藏/显示,** @param e* @return*/@Overridepublic boolean onSingleTapConfirmed(MotionEvent e) {//当手势结束,并且是单击结束时,控制器隐藏/显示toggleMediaControlsVisiblity();return super.onSingleTapConfirmed(e);}@Overridepublic boolean onDown(MotionEvent e) {return true;}//滑动事件监听@Overridepublic 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/4onVolumeSlide((mOldY - y) / windowHeight);} else if (mOldX < windowWidth * 1.0 / 4.0) {// 左边滑动 屏幕 1/4onBrightnessSlide((mOldY - y) / windowHeight);}return super.onScroll(e1, e2, distanceX, distanceY);}@Overridepublic boolean onDoubleTap(MotionEvent e) {playOrPause();return true;}@Overridepublic 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;// 显示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);}}/*** 设置视频文件名** @param name*/public void setVideoName(String name) {videoname = name;if (mFileName != null) {mFileName.setText(name);}}/*** 隐藏或显示*/private void toggleMediaControlsVisiblity() {if (isShowing()) {hide();} else {show();}}/*** 播放/暂停*/private void playOrPause() {if (videoView != null)if (videoView.isPlaying()) {videoView.pause();} else {videoView.start();}}}
自定义控制器布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/video_player_bg_color"android:orientation="vertical"><RelativeLayout
android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayout
android:layout_width="match_parent"android:layout_height="34dp"android:background="#77000000"><ImageButton
android:id="@+id/mediacontroller_top_back"android:layout_width="50dp"android:layout_height="match_parent"android:layout_alignParentLeft="true"android:background="@null"android:src="@drawable/ic_player_close_white"/><TextView
android:id="@+id/mediacontroller_filename"style="@style/MediaController_Text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="5dp"android:layout_toRightOf="@+id/mediacontroller_top_back"android:ellipsize="marquee"android:singleLine="true"android:text="file name"/><ImageButton
android:id="@+id/mediacontroller_share"android:layout_width="50dp"android:layout_height="match_parent"android:layout_alignParentRight="true"android:background="@null"android:src="@drawable/ic_action_share_without_padding"/><ImageButton
android:id="@+id/mediacontroller_favorite"android:layout_width="50dp"android:layout_height="match_parent"android:layout_toLeftOf="@id/mediacontroller_share"android:background="@null"android:src="@drawable/ic_action_favorites"/></RelativeLayout><ImageButton
android:id="@+id/mediacontroller_play_pause"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@null"android:src="@drawable/paly_selector"/><RelativeLayout
android:id="@+id/operation_volume_brightness"android:layout_width="150dp"android:layout_height="75dp"android:layout_centerInParent="true"android:background="@drawable/videobg"android:orientation="horizontal"android:padding="0dip"android:visibility="gone"><ImageView
android:id="@+id/operation_bg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:src="@drawable/video_volumn_bg"/><TextView
android:id="@+id/operation_tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBottom="@+id/operation_bg"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:text="32:22/45:00"android:textColor="#ffffff"android:textSize="10sp"android:visibility="gone"/></RelativeLayout><RelativeLayout
android:layout_width="match_parent"android:layout_height="50dp"android:layout_alignParentBottom="true"android:background="#77000000"><TextView
android:id="@+id/mediacontroller_time_current"style="@style/MediaController_Text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="15dp"android:text="33:33:33"/><TextView
android:id="@+id/mediacontroller_time_total"style="@style/MediaController_Text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginRight="15dp"android:text="33:33:33"/><SeekBar
android:id="@+id/mediacontroller_seekbar"style="@style/MediaController_SeekBar"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_toLeftOf="@id/mediacontroller_time_total"android:layout_toRightOf="@id/mediacontroller_time_current"android:focusable="true"android:max="1000"/></RelativeLayout></RelativeLayout>
</LinearLayout>
视频播放界面布局
<?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.CenterLayout
android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><io.vov.vitamio.widget.VideoView
android:id="@+id/buffer"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_centerHorizontal="true"android:layout_centerVertical="true"/></io.vov.vitamio.widget.CenterLayout><LinearLayout
android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:orientation="horizontal"><ProgressBar
android:id="@+id/probar"style="?android:attr/progressBarStyleLarge"android:layout_width="50dp"android:layout_height="50dp"/><TextView
android:id="@+id/download_rate"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text=""android:textColor="#FFFFFF"/><TextView
android:id="@+id/load_rate"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text=""android:textColor="#FFFFFF"/></LinearLayout>
</RelativeLayout>
Vitamio Demo Github地址
开源全能播放器Vitamio的使用相关推荐
- java开源播放器_JavaFX/Java8开发的开源音乐播放器
往期精彩推荐 : 很难找的java开源音乐播放器,英文比较简单,也不翻译了, . github开源地址: https://github.com/Mpmart08/MusicPlayer Desktop ...
- linux开源视频播放器_什么定义了Linux的顶级开源音乐播放器?
linux开源视频播放器 在我撰写此音乐专栏的两年左右的时间里,Linux发烧友的世界得到了发展. 出现了新的Linux发行版和开源音频播放器,旧的已经消失了,随着高质量的数字下载,新的和高质量的播放 ...
- 开源音乐播放器_如何选择开源音乐播放器
开源音乐播放器 Linux提供了大量的音乐播放器. 您如何选择使用哪一个? 早在2016年6月,我就写了我最喜欢的开源音乐播放器Guayadeque显然逝世的文章. 我描述了我对Guayadeque真 ...
- 草莓tv 无法播放_草莓:高质量的声音,开源音乐播放器
草莓tv 无法播放 我最近收到了乔纳斯·克文格 ( Jonas Kvinge )发来的电子邮件,该电子邮件分叉了Clementine开源音乐播放器 . 乔纳斯写道: 我已经在2013年开始开发Clem ...
- cantata测试工具_我如何构建和维护开源音乐播放器Cantata
cantata测试工具 这是与开发和维护开源音乐播放器的开发人员进行的一系列对话的第三部分. Craig Drummond是Cantata的开发者和维护者, Cantata是一种开源音乐播放器,充当M ...
- 好用工具第4期:全能播放器PotPlayer
好用工具第4期:全能播放器PotPlayer Global Potplayer 是一款 Windows 平台的全能播放器.支持几乎所有的视频格式,音频格式,以及在线播放全世界的电视直播. 其官网是: ...
- windows media player 成为全能播放器
windows media player 成为全能播放器 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:offi ...
- 影音全能播放器-KMPlayer提供下载
Kmplayer来自韩国的影音全能播放器,与Mplayer一样从linux平台移植而来的Kmplayer(简称KMP)几乎可以播放您系统上所有的影音文件.KMPlaye通过各种插件扩展KMP可以支持层 ...
- linux开源视频播放器_8个适用于Linux的开源音乐播放器
linux开源视频播放器 在本系列的第一部分中,我写了一个发烧友数字音乐播放器的关键要求,并分享了我用来评估开源音乐播放器的标准. 在第二部分中,我将使用这些条件来帮助您选择适合您需求的软件. 首先, ...
最新文章
- 专访 | 融资4.1亿美元,估值15亿美元,这家AI初创公司凭什么“这么贵”?
- Python:打印目录下最大的十个文件
- 美团医美发起“至美行动”,单月拦截六万余条虚假医美评价
- 在SAP WebIDE Database Explorer里操作hdi实例
- Windows Live Messenger 新功能预览
- hibernate3连接mysql8报错_MySQL的8小时连接超时时间,导致系统过夜即崩溃,报错Could not roll back Hibernate transaction...
- NVIDIA ECCV18论文:超像素采样网络助力语义分割与光流估计(代码将开源)
- Codeforces Ilya and Queries
- 个人博客系统需求文档
- 近期币圈与美股的相关性
- redhat linux 无线网卡,RedHat Linux 6.4安装RTL8188CUS无线网卡驱动
- 《学习之道》第二章专注思维和发散思维
- 48 Fixing relationship Problems with Humor 用幽默解决人际关系问题
- 实体(Entity)
- Apple Configurator 2 修复M1 Macbook 时报错 0x15
- petalinux2018.3安装步骤
- python图片转换成文字的手机软件_手机如何将图片转换成文字?用这两种方法转换很简单...
- javax.naming.OperationNotSupportedException: Context is read only
- Java基础动态初始化二维数组
- 华为十年技术总监教你如何学好Jmeter接口测试+压力测试!!!