之前也试过vitamio这个库,后来不知道被什么事情给耽搁了,就没继续下去。近来觉得视频还是需要学习一下的,谁让直播那么火呢,就想着写一个简单的视频播放的app先吧。好了那就开始吧,暂时取名为JPlayer,后续慢慢改进,源码也在github上(https://github.com/imchenjianneng/JPlayer),后续不断更新吧。
首先新建工程JPlayer,然后新建个主界面吧:
<layout><data class="MainBinding"></data><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/coordinator_layout"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.design.widget.AppBarLayout
android:id="@+id/appbar_layout"android:layout_width="match_parent"android:layout_height="wrap_content"android:fitsSystemWindows="true"><RelativeLayout
android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.Toolbar
android:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="@color/colorPrimary"android:fitsSystemWindows="true"android:minHeight="?attr/actionBarSize"app:contentInsetLeft="0dp"app:contentInsetStart="0dp"><!--app:layout_scrollFlags="scroll|enterAlways"--><RelativeLayout
android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="12dp"android:paddingRight="12dp"><RadioGroup
android:id="@+id/rg_tab"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:orientation="horizontal"><RadioButton
android:id="@+id/rb_local"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:button="@null"android:gravity="center"android:text="本地"android:textColor="@drawable/top_tab_text_color"android:textSize="16sp" /><RadioButton
android:id="@+id/rb_intenet"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:button="@null"android:gravity="center"android:text="网络"android:textColor="@drawable/top_tab_text_color"android:textSize="16sp" /></RadioGroup></RelativeLayout></android.support.v7.widget.Toolbar></RelativeLayout></android.support.design.widget.AppBarLayout><android.support.v4.view.ViewPager
android:id="@+id/viewpager"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_behavior="@string/appbar_scrolling_view_behavior" /></android.support.design.widget.CoordinatorLayout>
</layout>
这里简单简绍下,具体可以看源码,界面由是两个radiobutton,一个viewpager组成,比较简陋,后续再改吧,我们先实现功能要紧。真实项目一般ui都会提供好界面的。
既然界面搭建好了,那么继续开始代码实现吧:
public class MainActivity extends BaseActivity implements ViewPager.OnPageChangeListener {private MainBinding binding;private List<Integer> bts = Arrays.asList(R.id.rb_local,R.id.rb_intenet);private float normalSize, normalSelected;@Overrideprotected void initParams() {binding = DataBindingUtil.setContentView(getActivity(), R.layout.activity_main);}@Overrideprotected void initViews() {super.initViews();normalSize = getResources().getDimension(R.dimen.normal_size);normalSelected = getResources().getDimension(R.dimen.selected_size);binding.viewpager.setOffscreenPageLimit(2);binding.viewpager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager()));initTabPagerListener();binding.rgTab.check(bts.get(0));}private void initTabPagerListener() {binding.viewpager.addOnPageChangeListener(this);binding.rgTab.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {int i = bts.indexOf(checkedId);if (i != -1) {selectTitle(checkedId);binding.viewpager.setCurrentItem(i);}}});}@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {selectTitle(bts.get(position));binding.rgTab.check(bts.get(position));}@Overridepublic void onPageScrollStateChanged(int state) {}private void selectTitle(int selectResId) {binding.rbLocal.setTextSize(TypedValue.COMPLEX_UNIT_PX, normalSize);binding.rbIntenet.setTextSize(TypedValue.COMPLEX_UNIT_PX, normalSize);((TextView)findViewById(selectResId)).setTextSize(TypedValue.COMPLEX_UNIT_PX,normalSelected);}public class MyFragmentPagerAdapter extends FragmentPagerAdapter {LocalVideoFragment localVideoFragment = new LocalVideoFragment();InternetVideoFragment internetVideoFragment = new InternetVideoFragment();private List<? extends Fragment> list = Arrays.asList(localVideoFragment,internetVideoFragment);public MyFragmentPagerAdapter(FragmentManager fm) {super(fm);}@Overridepublic int getCount() {return list.size();}@Overridepublic Fragment getItem(int position) {return list.get(position);}}
}
代码其实比较简单,主要实现了viewpager,然后LocalVideoFragment和InternetVideoFragment两个fragment,第一个是本地的界面,第二个是网络(这里暂时不实现),好了,主要的代码都在LocalVideoFragment里了。那么就接着看这个Frament的代码了。
既然要播放视频,首先是需要实现扫描所有视频文件。先看这一段代码吧:
private class ScanVideoTask extends AsyncTask<Void, File, Void> {@Overrideprotected Void doInBackground(Void... params) {eachAllMedias(Environment.getExternalStorageDirectory());return null;}@Overrideprotected void onProgressUpdate(File... values) {LocalSource localSource = new LocalSource();localSource.setName(values[0].getName());localSource.setUrl(values[0].getAbsolutePath());localSource.setBitmap(getVideoThumbnail(localSource, localSource.getUrl()));localSource.setBitmap(getVideoThumbnail(localSource.getUrl()));Log.d("LocalVideoFragment", "hhh"+localSource.getName()+":"+localSource.getUrl());fileAdapter.appendItem(localSource);fileAdapter.notifyDataSetChanged();}/** 遍历所有文件夹,查找出视频文件 */public void eachAllMedias(File f) {if (f != null && f.exists() && f.isDirectory()) {File[] files = f.listFiles();if (files != null) {for (File file : f.listFiles()) {if (file.isDirectory()) {eachAllMedias(file);} else if (file.exists() && file.canRead() && isVideo(file)) {publishProgress(file);}}}}}}
扫描需要花费比较长的时间,所以这里放到一个异步task中去处理,深度优先的搜索所有的文件,扫描到了文件判断是否为视频文件,若是的话,那就直接加到recycleview中去。对于是否是视频文件,这里仅仅是判断后缀名,更合理的方式应该是解码一部分,然后判断头文件的信息的,之类就偷懒了一下,具体可以参考源码。
既然已经扫描出了文件,那么接下来就需要这个播放列表了,因为我们要显示视频的缩略图,视频的文件名,以及播放时长和大小。用到了MediaMetadataRetriever类,通过extractMetadata方法来获取视频的相关信息,看下代码吧:
public Bitmap getVideoThumbnail(LocalSource localSource, String filePath) {Bitmap bitmap = null;MediaMetadataRetriever retriever = new MediaMetadataRetriever();try {retriever.setDataSource(filePath);bitmap = retriever.getFrameAtTime(0);localSource.setAuthor(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_AUTHOR));localSource.setDuration(Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)));localSource.setDate(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE));localSource.setBitrate(Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE)));} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();}return bitmap;}
这通过retriever.getFrameAtTime来获取一帧的图像bitmap用来当缩略图,然后通过MediaMetadataRetriever.METADATA_KEY_DURATION获取播放时长。通过MediaMetadataRetriever.METADATA_KEY_BITRATE获取比特率,计算就可以得到所需要的文件大小。
要上班去了,接下去的话就是重点了,怎么使用vitamio,下次继续了,想直接看代码的话可以直接github看起来,代码写得比较挫,还没有整理过,为了实现功能而写。