Android 在线视频播放器(Vitamio)

概述

Vitamio 是一款 Android 与 iOS 平台上的全能多媒体开发框架,全面支持硬件解码与 GPU 渲染,底层音视频解码原理基于FFmpeg开发。Vitamio 凭借其简洁易用的 API 接口赢得了全球众多开发者的青睐。到目前,全球已经有超过一万款应用在使用 Vitamio,覆盖用户超过 5亿。 
Vitamio 能够流畅播放720P甚至1080P高清MKV,FLV,MP4,MOV,TS,RMVB等常见格式的视频,还可以在 Android 上支持 MMS, RTSP, RTMP, HLS(m3u8) 等常见的多种视频流媒体协议,包括点播与直播。 
支持 ARMv6 和 ARMv7 两种 ARM CPU,同时对 VFP, VFPv3, NEON 等指令集都做相应优化。 
支持 Android 2.1+ 系统,支持超过 95% 的 Android 市场。同时 Android 2.1 之前的系统也基本支持,不过没做详细测试。 
开源项目下载地址:https://github.com/yixia/VitamioBundle

配置Vitamio

导包

开源项目下载后目录结构如下: 
这里写图片描述 
其中的VitamioListActivity是官方提供的demo,而我们要导入的包是InitActivity。 
Eclipse用户很简单,直接添加InitActivity为依赖工程即可。 
Studio用户下载Studio Vitamio包,作为Module导入Project,然后修改以下信息: 
app目录下的build.gradle,在dependencies 中添加依赖 compile project(‘:vitamio’) 如果你导入module中更改过名字的话 要改成修改后的名字 如图: 
这里写图片描述 
按照app目录下的build.gradle配置vitamio目录下的build.gradle(注意不是vitamio文件夹下app下的) 
这里写图片描述

AndroidManifest配置

注册io.vov.vitamio.activity.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" />
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

添加权限:

<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" />
 
 
  • 1
  • 2
  • 3
  • 4

使用Vitamio

VideoView控件的使用

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:background="#696969"
    tools:context="com.hx.vitamio.MainActivity" >

    <io.vov.vitamio.widget.CenterLayout
        android:id="@+id/dd"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <io.vov.vitamio.widget.VideoView
            android:id="@+id/vitamio"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true" />
    </io.vov.vitamio.widget.CenterLayout>

    <TextView
        android:id="@+id/buffer_percent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/dd"
        android:layout_marginLeft="12dp"
        android:textColor="#e6ff01" />

    <TextView
        android:id="@+id/net_speed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/dd"
        android:layout_marginLeft="12dp"
        android:layout_toRightOf="@id/buffer_percent"
        android:textColor="#04fa00" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="@mipmap/mediacontroller_sreen_size_100"
        android:onClick="changeLayout" />

</RelativeLayout>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
public class MainActivity extends Activity {
    private VideoView videoView;
    private TextView percentTv;
    private TextView netSpeedTv;
    private int mVideoLayout = 0;
    private String url1 = "http://112.253.22.157/17/z/z/y/u/zzyuasjwufnqerzvyxgkuigrkcatxr/hc.yinyuetai.com/D046015255134077DDB3ACA0D7E68D45.flv";
    private String url2 = "http://flashmedia.eastday.com/newdate/news/2016-11/shznews1125-19.mp4";
    private String url3 = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov";
    private String url4 = "http://42.96.249.166/live/388.m3u8";
    private String url5 = "http://live.3gv.ifeng.com/zixun.m3u8";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //检查vitamio框架是否可用
        if (!LibsChecker.checkVitamioLibs(this)) {
            return;
        }
        setContentView(R.layout.activity_main);
        //显示缓冲百分比的TextView
        percentTv = (TextView) findViewById(R.id.buffer_percent);
        //显示下载网速的TextView
        netSpeedTv = (TextView) findViewById(R.id.net_speed);
        //初始化加载库文件
        if (Vitamio.isInitialized(this)) {
            videoView = (VideoView) findViewById(R.id.vitamio);
            videoView.setVideoURI(Uri.parse(url1));
            videoView.setVideoQuality(MediaPlayer.VIDEOQUALITY_HIGH);
            MediaController controller = new MediaController(this);
            videoView.setMediaController(controller);
            videoView.setBufferSize(10240); //设置视频缓冲大小。默认1024KB,单位byte
            videoView.requestFocus();
            videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    // optional need Vitamio 4.0
                    mediaPlayer.setPlaybackSpeed(1.0f);
                  //mediaPlayer.setLooping(true);
                }
            });

            videoView.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
                @Override
                public void onBufferingUpdate(MediaPlayer mp, int percent) {
                    percentTv.setText("已缓冲:" + percent + "%");
                }
            });
            videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                @Override
                public boolean onInfo(MediaPlayer mp, int what, int extra) {
                    switch (what) {
                        //开始缓冲
                        case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                            percentTv.setVisibility(View.VISIBLE);
                            netSpeedTv.setVisibility(View.VISIBLE);
                            mp.pause();
                            break;
                        //缓冲结束
                        case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                            percentTv.setVisibility(View.GONE);
                            netSpeedTv.setVisibility(View.GONE);
                            mp.start(); //缓冲结束再播放
                            break;
                        //正在缓冲
                        case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
                            netSpeedTv.setText("当前网速:" + extra + "kb/s");
                            break;
                    }
                    return true;
                }
            });
        }
    }

    public void changeLayout(View view) {
        mVideoLayout++;
        if (mVideoLayout == 4) {
            mVideoLayout = 0;
        }
        switch (mVideoLayout) {
            case 0:
                mVideoLayout = VideoView.VIDEO_LAYOUT_ORIGIN;
                view.setBackgroundResource(R.mipmap.mediacontroller_sreen_size_100);
                break;
            case 1:
                mVideoLayout = VideoView.VIDEO_LAYOUT_SCALE;
                view.setBackgroundResource(R.mipmap.mediacontroller_screen_fit);
                break;
            case 2:
                mVideoLayout = VideoView.VIDEO_LAYOUT_STRETCH;
                view.setBackgroundResource(R.mipmap.mediacontroller_screen_size);
                break;
            case 3:
                mVideoLayout = VideoView.VIDEO_LAYOUT_ZOOM;
                view.setBackgroundResource(R.mipmap.mediacontroller_sreen_size_crop);

                break;
        }
        videoView.setVideoLayout(mVideoLayout, 0);
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

注:网速慢的情况下,视频可能会缓冲很久才会播放,这时候可以通过setBufferSize设置视频缓冲大小。默认1024KB,我们可以给它改小点。

VideoView常用函数

/**
 * 获取扫描视频的Uri。
 * 参数layout(缩放参数)参见MediaPlayer的常量:VIDEO_LAYOUT_ORIGIN(原始大小)、VIDEO_LAYOUT_SCALE(画面全屏)、VIDEO_LAYOUT_STRETCH(画面拉伸)、VIDEO_LAYOUT_ZOOM(画面裁剪)、VIDEO_LAYOUT_FIT_PARENT(画面铺满)
 * 参数aspectRation(宽高比),为0将自动检测
 */
public void setVideoLayout(int layout,float aspectRatio);
//Surface是否有效。 参见Surface的isValid方法。
public boolean isValid();
//设置视频路径。
public void setVideoPath(String path);
//设置视频URI。(可以是网络视频地址)
public void setVideoURI(Uri uri);
//停止视频播放,并释放资源。
public void stopPlayback();
/**
 * 设置媒体控制器。
 * 参数controller:媒体控制器,注意是io.vov.vitamio.widget.MediaController。
 */
public void setMediaController(MediaController controller);    
//注册一个回调函数,在视频预处理完成后调用。在视频预处理完成后被调用。此时视频的宽度、高度、宽高比信息已经获取到,此时可调用seekTo让视频从指定位置开始播放。
public void setOnPreparedListener(OnPreparedListener l);
//获取当前播放位置。
public long getCurrentPosition();
//设置播放位置。单位毫秒
public void seekTo(long msec);
//是否正在播放。
public boolean isPlaying();
//获取缓冲百分比。
public int getBufferPercentage();
/**
 * 设置视频质量。
 * 参数quality参见MediaPlayer的常量:VIDEOQUALITY_LOW(流畅)、VIDEOQUALITY_MEDIUM(普通)、VIDEOQUALITY_HIGH(高质)
 */
public void setVideoQuality(int quality);
//设置视频缓冲大小。默认1024KB,单位byte
public void setBufferSize(int bufSize);
//检测是否缓冲完毕。
public boolean isBuffering();
//设置元数据编码。例如:UTF-8
public void setMetaEncoding(String encoding);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

更多方法参见:http://www.cnblogs.com/over140/archive/2012/08/30/2663243.html

Vitamio支持的流

Android RTMP流

Real Time Messaging Protocol (RTMP)是一个Adobe Systems所拥有的一个协议。该协议是Adobe公司拥有的开发音视频流的flash player。后来该协议的部分被公开,供公众使用。这个协议大多用于IPTV和实时视频点播流,但它也用于其他领用。 
在android上,标准的VideoView不支持RTMP播放。但WebView可以播放RTMP流。这解决了播放RTMP流的问题,但是我认为web apps 不能提供一个很好的界面和体验。因此这个android RTMP例子中我们将运用第三方库-Vitamio 直播RTMP流的流媒体。

Android RTSP流

实时流协议(RTSP)通过多媒体服务器传输内容,例如YouTube使用RTSP流发布内容。关于RTSP流比较容易的部分是,它可以通过android标准的VideoView来完成。 
但是如果你使用Vitamio库,可以更好的播放RTSP流。事实上Vitamio也支持RTSP流的回播。

Android m3u8流

“如何在android上播放m3u8视频”是android开发者最常见的问题之一。通过Http 协议进行视频流直播最简单的办法就是使用标准的 VideoView. 但只能在android3.0以上的设备上播放m3u8流。因为在Android 3.0引入HTTP/ HTTPS直播和HTTP/ HTTPS渐进式流媒体协议,在android3.1完全支持HTTPS。 
如果你希望在早期的版本上实现支持android m3u8流的HTTP实时流媒体 (HLS)。应该考虑使用Vitamio库,这个库支持在android API7以上播放m3u8。

Android MMS流

Vitamio库是一个强大的库,还支持Microsoft媒体服务器(MMS)流中的播放。 MMS是网络流媒体协议,主要用于网络广播和电台直播。

注:Vitamio是一个强大的多平台库(ios and android)。通过使用Vitamio库能播放多种类型的视频格式和协议如RTMP, RTSP, HTTP Live, HTTP渐进式流协议。另外一个很好的功能是,vitamio支持字幕和多音轨的播放。Vitamio的唯一的缺点是,它不是完全的开源。您可能需要购买许可证来使用它。

基于Vitamio实现的播放器

下面将Vitamio的视频控制器(MediaController)界面进行自定义,同时支持视频亮度、音量的调节,话不多说,先上效果图。 
这里写图片描述

功能:

  • 使用Vitamio的VideoView进行视频播放
  • 显示加载进度和当前网速
  • 视频左侧界面(左1/4以内)上下滑动调节亮度
  • 视频右侧界面(右3/4以外)上下滑动调节声音
  • 双击播放/暂停
  • 中间播放按钮也可以控制播放/暂停
  • 进度显示,并可以拖动调节当前播放进度

(1)播放视频

public class MainActivity extends Activity {
    private VideoView mVideoView;
    private TextView downloadRateView, loadRateView;
    private ProgressBar pb;
    private CustomMediaController mCustomMediaController;
    private String url1 = "http://112.253.22.157/17/z/z/y/u/zzyuasjwufnqerzvyxgkuigrkcatxr/hc.yinyuetai.com/D046015255134077DDB3ACA0D7E68D45.flv";
    private String url2 = "http://flashmedia.eastday.com/newdate/news/2016-11/shznews1125-19.mp4";
    private String url3 = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov";
    private String url4 = "http://42.96.249.166/live/24035.m3u8";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //定义全屏参数
        int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
        //获得当前窗体对象
        Window window = MainActivity.this.getWindow();
        //设置当前窗体为全屏显示
        window.setFlags(flag, flag);
        //检查vitamio框架是否可用
        if (!LibsChecker.checkVitamioLibs(this)) {
            return;
        }
        setContentView(R.layout.activity_main);
        pb = (ProgressBar) findViewById(R.id.probar);
        downloadRateView = (TextView) findViewById(R.id.download_rate);
        loadRateView = (TextView) findViewById(R.id.load_rate);
        mVideoView = (VideoView) findViewById(R.id.buffer);

        mCustomMediaController = new CustomMediaController(this,mVideoView,this);
        mCustomMediaController.setVideoName("蓝莲花");
        mCustomMediaController.show(5000); //5s隐藏

        //初始化加载库文件
        if (Vitamio.isInitialized(this)) {
            mVideoView.setVideoURI(Uri.parse(url1));
            mVideoView.setVideoQuality(MediaPlayer.VIDEOQUALITY_HIGH);
            mVideoView.setMediaController(mCustomMediaController);
            mVideoView.setBufferSize(10240); //设置视频缓冲大小
            mVideoView.requestFocus();
            mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    // optional need Vitamio 4.0
                    mediaPlayer.setPlaybackSpeed(1.0f);
                }
            });

            mVideoView.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
                @Override
                public void onBufferingUpdate(MediaPlayer mp, int percent) {
                    loadRateView.setText(percent + "%");
                }
            });
            mVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                @Override
                public 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;
                }
            });
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        //屏幕切换时,设置全屏
        if (mVideoView != null){
            mVideoView.setVideoLayout(VideoView.VIDEO_LAYOUT_SCALE, 0);
        }
        super.onConfigurationChanged(newConfig);
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

(2)视频界面

<?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>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

(3)视频控制器

/**
 * 自定义视频控制器
 */
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;
    //设置mediaController高度为了使横屏时top显示在屏幕顶端
    private int controllerWidth = 0;

    private View mVolumeBrightnessLayout;
    //提示窗口
    private ImageView mOperationBg;
    //提示图片
    private TextView mOperationTv;
    //提示文字
    private AudioManager mAudioManager;
    //最大声音
    private int mMaxVolume;
    // 当前声音
    private int mVolume = -1;
    //当前亮度
    private float mBrightness = -1f;

    private Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case HIDEFRAM:
                    //隐藏提示窗口
                    mVolumeBrightnessLayout.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());
    }

    @Override
    protected View makeControllerView() {
        //此处的mymediacontroller为我们自定义控制器的布局文件名称
        View v = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mymediacontroller, this);
        v.setMinimumHeight(controllerWidth);
        //获取控件
        img_back = (ImageButton) v.findViewById(R.id.mediacontroller_top_back);
        mFileName = (TextView) v.findViewById(R.id.mediacontroller_filename);
        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);
        //声音控制
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        //注册事件监听
        img_back.setOnClickListener(backListener);
        return v;
    }

    //返回监听
    private View.OnClickListener backListener = new View.OnClickListener() {
        public void onClick(View v) {
            if (activity != null) {
                activity.finish();
            }
        }
    };

    @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, 500);
    }

    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }

        /**
         * 因为使用的是自定义的mediaController 当显示后,mediaController会铺满屏幕,
         * 所以VideoView的点击事件会被拦截,所以重写控制器的手势事件,
         * 将全部的操作全部写在控制器中,
         * 因为点击事件被控制器拦截,无法传递到下层的VideoView,
         * 所以原来的单击隐藏会失效,作为代替,
         * 在手势监听中onSingleTapConfirmed()添加自定义的隐藏/显示,
         *
         * @param e
         * @return
         */
        @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);
        }
        int index = (int) (percent * mMaxVolume) + mVolume;
        if (index > mMaxVolume) {
            index = mMaxVolume;
        } else if (index < 0) {
            index = 0;
        }
        //变更声音
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
        mOperationTv.setText((int) (((double) index / mMaxVolume) * 100) + "%");
        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);
        }
    }

    /**
     * 滑动改变亮度
     *
     * @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);
        }
        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();
            }
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290

(4)视频控制器界面

<?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: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/play_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:textColor="#ffffff"
                android:textSize="12sp" />
        </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>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126

(5)Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hx.vitamio">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:screenOrientation="sensorLandscape">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 必须初始化 -->
        <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" />
    </application>

    <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" />

</manifest>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

具体就不一一分析了,大家需要直接看代码吧。

一些电视台的直播地址

下面是我记录的一些电视台的直播地址,奉献给大家: 
CCTV: rtmp://203.207.99.19:1935/live/CCTV5 
注:后面的数字可以自己修改为中央几台 
凤凰卫视:http://zv.3gv.ifeng.com/live/zhongwen800k.m3u8

Demo下载地址 
Part1… 
Part2… 
Part3…

请将三部分全部下载完毕后再进行解压。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值