概述

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,单位bytepublic void setBufferSize(int bufSize);//检测是否缓冲完毕。public boolean isBuffering();//设置元数据编码。例如:UTF-8public 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. Rexsee API介绍:Android照片、视频拍摄,Camera扩展
  2. Android本地视频播放器开发--ffmpeg解码视频文件中的音频(1)
  3. Android中播放GIF动画
  4. Android(安卓)VideoView如何播放RTSP的流
  5. Android利用硬解硬编和OpenGLES来高效的处理MP4视频
  6. 一个使用FFmpeg库读取3gp视频的例子-Android中使用FFmpeg媒体库(
  7. android之播放多媒体文件一(播放音频)
  8. android视频桌面源码,酒店应用源码等
  9. Android音频系统探究——从SoundPool到AudioHardware

随机推荐

  1. 个人仿制android QQ、android大作业
  2. Android开发:android studio启动后,报错:Cou
  3. Android获取设备ID、型号及其它信息
  4. 从android游戏框架看其生命周期!
  5. Android 可显示左上右下Drawable的TextVi
  6. android字体小结
  7. Android中日历控件的使用
  8. Android 开发技巧之 手动拖动滚动条快速
  9. 安卓标签
  10. android 开发环境搭建