本博客用Android studio集成了vitamio的自定义视频播放器,同时可以在文件管理中选择播放,想要一个自己的视频播放器这边便可以满足
实现具体功能如下:
1.sd卡内存视频文件的点击播放;
2.视频时间进度条;
3.屏幕亮度的手势滑动;
4.视频音量的手势滑动;
5.多点手势效果
6.自定义存储视频url播放
想要的重要的代码,我懂得:
------------------------------软件工程结构图:
最重要的是依赖上vitamio库:
-------------------------工具类FileUtil,检查文件格式是否属于自己定义的格式:
public class FileUtil { public static final String[] VIDEO_EXTENSIONS = { "3gp", "amv", "avb", "avd", "avi", "flh", "fli", "flv", "flx", "gvi", "gvp", "hdmov", "hkm", "ifo", "imovi", "imovi", "iva", "ivf", "ivr", "m4v", "m75", "meta", "mgv", "mj2", "mjp", "mjpg", "mkv", "mmv", "mnv", "mod", "modd", "moff", "moi", "moov", "mov", "movie", "mp21", "mp21", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg4", "mpf", "mpg", "mpg2", "mpgin", "mpl", "mpls", "mpv", "mpv2", "mqv", "msdvd", "msh", "mswmm", "mts", "mtv", "mvb", "mvc", "mvd", "mve", "mvp", "mxf", "mys", "ncor", "nsv", "nvc", "ogm", "ogv", "ogx", "osp", "par", "pds", "pgi", "piv", "playlist", "pmf", "prel", "pro", "prproj", "psh", "pva", "pvr", "pxv", "qt", "qtch", "qtl", "qtm", "qtz", "rcproject", "rdb", "rec", "rm", "rmd", "rmp", "rms", "rmvb", "roq", "rp", "rts", "rts", "rum", "rv", "sbk", "sbt", "scm", "scm", "scn", "sec", "seq", "sfvidcap", "smil", "smk", "sml", "smv", "spl", "ssm", "str", "stx", "svi", "swf", "swi", "swt", "tda3mt", "tivo", "tix", "tod", "tp", "tp0", "tpd", "tpr", "trp", "ts", "tvs", "vc1", "vcr", "vcv", "vdo", "vdr", "veg", "vem", "vf", "vfw", "vfz", "vgz", "vid", "viewlet", "viv", "vivo", "wma" }; //集合放置所有支持视频格式 private static final List<String> listvideo = new ArrayList<>( Arrays.asList(VIDEO_EXTENSIONS)); // 检测是否是视频文件 public static boolean isVideo(String path) { path=getFileExtension(path); return listvideo.contains(path); } // 获取文件后缀名 public static String getFileExtension(String path) { if (null != path) { // 后缀点 的位置 int dex = path.lastIndexOf("."); // 截取后缀名 return path.substring(dex + 1); } return null; } }
--------------------工具类FileUtil,检查文件格式是否属于自己定义的格式:
public class LocUtil { // 获取所有存储路径 public static List<String> getDirs(Context context) { List<String> dirs = new ArrayList<String>(); StorageManager storageManager = (StorageManager) context .getSystemService(Context.STORAGE_SERVICE); try { Class[] paramClasses = {}; Method getVolumePathsMethod = StorageManager.class.getMethod( "getVolumePaths", paramClasses); getVolumePathsMethod.setAccessible(true); Object[] params = {}; Object invoke = getVolumePathsMethod.invoke(storageManager, params); for (int i = 0; i < ((String[]) invoke).length; i++) { // System.out.println(((String[])invoke)[i]); dirs.add(((String[]) invoke)[i]); } } catch (Exception e) { e.printStackTrace(); } return dirs; } //获取最大音量 public static int getMaxVolume(Context context) { return ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)) .getStreamMaxVolume(AudioManager.STREAM_MUSIC); } // 获取当前音量 public static int getCurVolume(Context context) { return ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)) .getStreamVolume(AudioManager.STREAM_MUSIC); } // 设置当前音量 public static void setCurVolume(Context context, int index) { ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)) .setStreamVolume(AudioManager.STREAM_MUSIC, index, 0); } // 获取屏幕像素 public static ScreenBean getScreenPix(Context context) { Display dplay = ((VideoPlay) context).getWindowManager() .getDefaultDisplay(); return new ScreenBean(dplay.getWidth(),dplay.getHeight()); } }
-------------实体类屏幕的宽高ScreenBean,保存视频宽高:
public class ScreenBean { private int sWidth; private int sHeight; public ScreenBean(int sWidth, int sHeight) { super(); this.sWidth = sWidth; this.sHeight = sHeight; } public int getsWidth() { return sWidth; } public void setsWidth(int sWidth) { this.sWidth = sWidth; } public int getsHeight() { return sHeight; } public void setsHeight(int sHeight) { this.sHeight = sHeight; } }
----------------------中转传递界面MainActivity类:
public class MainActivity extends AppCompatActivity { String Path; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent getPath=getIntent(); String action = getPath.getAction(); if(getPath.ACTION_VIEW.equals(action)){ Path=getPath.getDataString(); }else { Path= Environment.getExternalStorageDirectory() + "/test.mp4"; } Intent intent = new Intent(this, VideoPlay.class); intent.putExtra("videoURL",Path); startActivity(intent); finish(); } }
这个界面是中转,开发时一般自己定义,
Path=getPath.getDataString();//获取sd卡的视频文件url路径
Path= Environment.getExternalStorageDirectory() + "/test.mp4"; //程序存储的路径,可以扫描手机内存视频存储到数据库,这种视频列表简单自己写.
----------------------视频播放Activity类:
public class VideoPlay extends Activity { /** 当前视频路径 */ private String path; /** 当前声音 */ private int mVolume = -1; /** 最大音量 */ private int mMaxVolume; /** 当前亮度 */ private float mBrightness = -1f; /** 手势数目 */ private int finNum=0; private View mVolumeBrightnessLayout; private ImageView mOperationBg; private ImageView mOperationPercent; private VideoView mVideoView; private GestureDetector gestDetector; private ScaleGestureDetector scaleDetector; private ScreenBean screenBean; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); if (!LibsChecker.checkVitamioLibs(this)) return; requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_video); Intent getPath=getIntent(); path=getPath.getStringExtra("videoURL"); init(); } private void init() { mVideoView = (VideoView) findViewById(R.id.surface_view); mVolumeBrightnessLayout = findViewById(R.id.operation_volume_brightness); mOperationBg = (ImageView) findViewById(R.id.operation_bg); mOperationPercent = (ImageView) findViewById(R.id.operation_percent); mMaxVolume = LocUtil.getMaxVolume(this); gestDetector = new GestureDetector(this, new SingleGestureListener()); scaleDetector = new ScaleGestureDetector(this, new MultiGestureListener()); screenBean = LocUtil.getScreenPix(this); if (path == "") { return; } else { mVideoView.setVideoPath(path); mVideoView.setMediaController(new MediaController(this)); mVideoView.requestFocus(); mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.setPlaybackSpeed(1.0f); } }); } } /** 定时隐藏 */ private Handler mDismissHandler = new Handler() { @Override public void handleMessage(Message msg) { mVolumeBrightnessLayout.setVisibility(View.GONE); } }; @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub finNum=event.getPointerCount(); if (1 == finNum) { gestDetector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: endGesture(); } } else if (2 ==finNum) { scaleDetector.onTouchEvent(event); } return true; } /** 手势结束 */ private void endGesture() { mVolume = -1; mBrightness = -1f; // 隐藏 mDismissHandler.removeMessages(0); mDismissHandler.sendEmptyMessageDelayed(0, 500); } /** * 视频缩放 */ public void changeLayout(int size) { mVideoView.setVideoLayout(size, 0); } /** * 声音大小 * */ public void changeVolume(float percent) { if (mVolume == -1) { mVolume = LocUtil.getCurVolume(this); if (mVolume < 0) mVolume = 0; // 显示 mOperationBg.setImageResource(R.drawable.video_volumn_bg); mVolumeBrightnessLayout.setVisibility(View.VISIBLE); } int index = (int) (percent * mMaxVolume) + mVolume; if (index > mMaxVolume) index = mMaxVolume; else if (index < 0) index = 0; // 变更声音 LocUtil.setCurVolume(this, index); // 变更进度条 ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume; mOperationPercent.setLayoutParams(lp); } /** * 亮度大小 * * @param percent */ public void changeBrightness(float percent) { if (mBrightness < 0) { mBrightness = 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); } WindowManager.LayoutParams lpa = 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; getWindow().setAttributes(lpa); ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness); mOperationPercent.setLayoutParams(lp); } /** * 单点触屏 */ private class SingleGestureListener implements GestureDetector.OnGestureListener { @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub Log.d("Fling", velocityY); return false; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub if(2==finNum){ return false; } float moldX = e1.getX(); float moldY = e1.getY(); float y = e2.getY(); if (moldX > screenBean.getsWidth() * 9.0 / 10)// 右边滑动 changeVolume((moldY - y) / screenBean.getsHeight()); else if (moldX < screenBean.getsWidth() / 10.0)// 左边滑动 changeBrightness((moldY - y) / screenBean.getsHeight()); return false; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return false; } } //多点手势控制 private class MultiGestureListener implements OnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { // TODO Auto-generated method stub return false; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { // TODO Auto-generated method stub // 返回true ,才能进入onscale()函数 return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { // TODO Auto-generated method stub float oldDis = detector.getPreviousSpan(); float curDis = detector.getCurrentSpan(); if (oldDis - curDis > 50) { // 缩小 changeLayout(0); Toast.makeText(VideoPlay.this, "缩小", Toast.LENGTH_LONG).show(); } else if (oldDis - curDis < -50) { // 放大 changeLayout(1); Toast.makeText(VideoPlay.this, "放大", Toast.LENGTH_LONG).show(); } } } }------------视频布局activity_video(activity_main里面没写省略):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <io.vov.vitamio.widget.VideoView android:id="@+id/surface_view" android:layout_centerInParent="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <FrameLayout android:id="@+id/operation_volume_brightness" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#00000000" android:orientation="horizontal" android:padding="0dip" android:visibility="invisible" > <ImageView android:id="@+id/operation_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/video_volumn_bg" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:paddingBottom="25dip" > <ImageView android:id="@+id/operation_full" android:layout_width="94dip" android:layout_height="wrap_content" android:layout_gravity="left" android:src="@drawable/video_num_bg" /> <ImageView android:id="@+id/operation_percent" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_gravity="left" android:scaleType="matrix" android:src="@drawable/video_num_front" /> </FrameLayout> </FrameLayout> </RelativeLayout>-------------Androidmanifest清单文件(4个注意点):
1.权限:<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="23" /> <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" />2.注意初始化vitamio的InitActivity:
<!-- Don't forgot InitActivity --> <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" />3.添加intent隐式意图,对sd卡支持的文件格式添加本程序的打开方式:
<activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW"></action> <category android:name="android.intent.category.DEFAULT"></category> <data android:mimeType="video/*"/> <data android:mimeType="application/mp4"/> <data android:mimeType="*/rmvb"/> <data android:mimeType="*/avi"/> <data android:mimeType="*/mkv"/> <data android:mimeType="audio/x-pn-realaudio"/> <data android:mimeType="video/x-ms-asf"/> <data android:mimeType="video/quicktime"/> <data android:mimeType="application/mpeg*"/> <data android:mimeType="application/vnd.rn-realmedia*"/> <data android:mimeType="application/3gpp*"/> <data android:mimeType="application/vnd.3gp*"/> <data android:mimeType="application/vnd.dvb*"/> <data android:mimeType="application/vnd.dolby*"/> <data android:mimeType="application/octet-stream"/> </intent-filter> </activity>4.添加视频播放控制的Activity:
<activity android:name=".VideoPlay" android:screenOrientation="landscape" > </activity>-------库和图片资源路径:
个人网盘链接:http://pan.baidu.com/s/1jHSoZSM 密码:03hm视频项目完整代码或者编写出问题的可以给我评论留言,我后面会解答
时间: 2024-10-06 04:42:39