zoukankan      html  css  js  c++  java
  • Android开发学习之路--基于vitamio的视频播放器(一)

      之前也试过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;
    
        @Override
        protected void initParams() {
            binding = DataBindingUtil.setContentView(getActivity(), R.layout.activity_main);
        }
    
        @Override
        protected 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() {
                @Override
                public void onCheckedChanged(RadioGroup group, int checkedId) {
                    int i = bts.indexOf(checkedId);
                    if (i != -1) {
                        selectTitle(checkedId);
                        binding.viewpager.setCurrentItem(i);
                    }
                }
            });
        }
    
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    
        }
    
        @Override
        public void onPageSelected(int position) {
            selectTitle(bts.get(position));
    
            binding.rgTab.check(bts.get(position));
        }
    
        @Override
        public 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);
            }
    
            @Override
            public int getCount() {
                return list.size();
            }
    
            @Override
            public Fragment getItem(int position) {
                return list.get(position);
            }
        }
    }

      代码其实比较简单,主要实现了viewpager,然后LocalVideoFragment和InternetVideoFragment两个fragment,第一个是本地的界面,第二个是网络(这里暂时不实现),好了,主要的代码都在LocalVideoFragment里了。那么就接着看这个Frament的代码了。

      既然要播放视频,首先是需要实现扫描所有视频文件。先看这一段代码吧:

    private class ScanVideoTask extends AsyncTask<Void, File, Void> {
    
            @Override
            protected Void doInBackground(Void... params) {
                eachAllMedias(Environment.getExternalStorageDirectory());
                return null;
            }
    
            @Override
            protected 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看起来,代码写得比较挫,还没有整理过,为了实现功能而写。

  • 相关阅读:
    垂直渐变的Button
    winform下重画ListBox
    分享一个 C# Winfrom 下的 OutlookBar 控件的使用
    颜色下拉菜单(combox)
    Robot Framework 使用技巧 快捷键
    Batch 拷贝远程机器文件到本机指定目录下
    JMeter常用函数 使用图解
    SoapUI报ClientProtocolException错误
    Setup Script in SoapUI
    邮件自动回复
  • 原文地址:https://www.cnblogs.com/wuyida/p/6299936.html
Copyright © 2011-2022 走看看