Android视频播放之VideoView

打印 上一主题 下一主题

主题 1058|帖子 1058|积分 3174

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1、VideoView类先容
  Android的VideoView组件可以从不同的来源(例如资源文件或内容提供器)读取图像,计算和维护视频的画面尺寸以使其适用于任何布局管理器,并提供一些诸如缩放、着色之类的显示选项,包罗在widget下面:android.widget.VideoView。Android中视屏播放框架如下图:


  从图中可以看出,VideoView组件进行视频播放的过程可以分为三步:
    (1)JAVA Framework层,应用程序进来之后到VideoView,再颠末Surface;
    (2)Native Framework层,先到SurfaceFlinger,然后到OverlayHal,同时借助了PVPlayer;
    (3)Driver层,利用Main framebuffer和Video Plane进行播放;
  VideoView组件的类继承与接口实现环境为:
    继承:public class VideoView extends SurfaceView
    接口:implements MediaController.MediaPlayerControl
  而从Object开始的继承层次如下:
    java.lang.Object
      android.view.View
        android.view.SurfaceView
          android.widget.VideoView
  VideoView类的构造函数有三个:
  (1)public VideoView(Context context),创建一个默认属性的VideoView实例。参数context为视图运行的应用程序上下文,通过它可以访问当前主题、资源等等。注:以下描述中重复参数的表明就不给出了。
  (2)public VideoView(Context context, AttributeSet attrs),创建一个带有attrs属性的VideoView实例。attrs用于视图的 XML 标签属性集合。
  (3)public VideoView(Context context, AttributeSet attrs, int defStyle),创建一个带有attrs属性,并且指定其默认样式的VideoView实例。参数defStyle为应用到视图的默认风格,如果为 0 则不应用(包罗当前主题中的)风格,该值可以是当前主题中的属性资源,也可以是明白的风格资源ID。
  比较常用的共有方法有播放start()、暂停pause()等,详细描述与用法见后面测试部分。
2、视频播放代码

       先给出一个简单的测试案例,程序中以File和Uri两种形式来给VideoView组件加载手机SD卡中的视频资源。资源类型为MP4,利用手机自带摄像机录制,完整路径名为“/mnt/sdcard/Pictures/video.mp4”。在代码采用的是读取体系路径的方式:Environment.getExternalStorageDirectory() + "/Pictures/video.mp4"。
  别的说明一点,利用Uri对网络资源进行读取的方式和当地资源类似,只是资源名称的形式不同。如:
  1. Uri uri = Uri.parse("rtsp://v2.cache2.c.youtube.com/CjgLENy73wIaLwm3JbT_%ED%AF%80%ED%B0%819HqWohMYESARFEIJbXYtZ29vZ2xlSARSB3Jlc3VsdHNg_vSmsbeSyd5JDA==/0/0/0/video.3gp");
复制代码
  文件格式3gp也是VideoView组件支持格式中的一种。
  由于要对手机中的文件进行读取,以是必须在AndroidManifest.xml文件中添加用户权限:
  1. 1 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  2. 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  3. 3 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
复制代码
      程序中用到的String变量封装在了string.xml中:
  1. 1 <resources>
  2. 2     <string name="app_name">VideoView0803</string>
  3. 3
  4. 4     <string name="hello_world">Hello world!</string>
  5. 5     <string name="action_settings">Settings</string>
  6. 6
  7. 7     <string name="startCard">PlayCard</string>
  8. 8     <string name="pauseCard">StopCard</string>
  9. 9     <string name="startUri">PlayUri</string>
  10. 10     <string name="pauseUri">StopUri</string>
  11. 11 </resources>
复制代码
  界面上的组件由一个VideoView、两个Button,一个TextView构成,布局文件代码如下:
  1. 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. 2     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. 3     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  4. 4     android:paddingRight="@dimen/activity_horizontal_margin"
  5. 5     android:paddingTop="@dimen/activity_vertical_margin"
  6. 6     android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
  7. 7
  8. 8     <Button
  9. 9         android:layout_width="wrap_content"
  10. 10         android:layout_height="wrap_content"
  11. 11         android:text="@string/startCard"
  12. 12         android:id="@+id/startCard"
  13. 13         android:layout_alignParentBottom="true"
  14. 14         android:layout_alignParentStart="true"
  15. 15         android:textColor="#00f" />
  16. 16
  17. 17     <Button
  18. 18         android:layout_width="wrap_content"
  19. 19         android:layout_height="wrap_content"
  20. 20         android:text="@string/startUri"
  21. 21         android:id="@+id/startUri"
  22. 22         android:layout_alignBottom="@+id/startCard"
  23. 23         android:layout_alignParentEnd="true"
  24. 24         android:textColor="#f00" />
  25. 25
  26. 26     <VideoView
  27. 27         android:layout_width="wrap_content"
  28. 28         android:layout_height="wrap_content"
  29. 29         android:id="@+id/videoView"
  30. 30         android:layout_alignParentStart="true"
  31. 31         android:layout_alignParentTop="true"
  32. 32         android:layout_above="@+id/startUri"
  33. 33         android:layout_centerHorizontal="true" />
  34. 34
  35. 35     <TextView
  36. 36         android:layout_width="wrap_content"
  37. 37         android:layout_height="wrap_content"
  38. 38         android:textAppearance="?android:attr/textAppearanceMedium"
  39. 39         android:text="Resource Path"
  40. 40         android:id="@+id/fileName"
  41. 41         android:layout_alignTop="@+id/startCard"
  42. 42         android:layout_alignParentBottom="true"
  43. 43         android:layout_toEndOf="@+id/startCard"
  44. 44         android:gravity="center_vertical"
  45. 45         android:textColor="#000"/>
  46. 46
  47. 47 </RelativeLayout>
复制代码
  此中,VideoView组件videoView用于视频内容的播放,Button组件startFile和startUri分别以File和Uri形式打开视频文件,TextView组件fileName用于显示完整路径名(标注资源的来源,对于该例子没这个须要)。运行前的界面图:


       主文件MainActivity完整代码如下:
  1.   1 package com.dylan_wang.videoview0803;
  2.   2
  3.   3 import android.app.Activity;
  4.   4 import android.net.Uri;
  5.   5 import android.os.Bundle;
  6.   6 import android.os.Environment;
  7.   7 import android.view.Menu;
  8.   8 import android.view.MenuItem;
  9.   9 import android.view.View;
  10. 10 import android.widget.Button;
  11. 11 import android.widget.MediaController;
  12. 12 import android.widget.TextView;
  13. 13 import android.widget.VideoView;
  14. 14
  15. 15 import java.io.File;
  16. 16
  17. 17
  18. 18 public class MainActivity extends Activity {
  19. 19
  20. 20     private String filename = null;
  21. 21     private Button startCard = null;
  22. 22     private Button startUri = null;
  23. 23     private TextView fileName = null;
  24. 24     private VideoView video = null;
  25. 25     private MediaController media = null;
  26. 26
  27. 27     @Override
  28. 28     protected void onCreate(Bundle savedInstanceState) {
  29. 29         super.onCreate(savedInstanceState);
  30. 30         setContentView(R.layout.activity_main);
  31. 31
  32. 32         filename = Environment.getExternalStorageDirectory() + "/Pictures/video.mp4";
  33. 33
  34. 34         startCard = (Button)findViewById(R.id.startCard);
  35. 35         startUri = (Button)findViewById(R.id.startUri);
  36. 36         fileName = (TextView)findViewById(R.id.fileName);
  37. 37         video = (VideoView)findViewById(R.id.videoView);
  38. 38         media = new MediaController(MainActivity.this);
  39. 39
  40. 40         startCard.setOnClickListener(new View.OnClickListener() {
  41. 41             @Override
  42. 42             public void onClick(View v) {
  43. 43                 playVideoFromFile();
  44. 44             }
  45. 45         });
  46. 46
  47. 47         startUri.setOnClickListener(new View.OnClickListener() {
  48. 48             @Override
  49. 49             public void onClick(View v) {
  50. 50                 openVideoFromUri();
  51. 51             }
  52. 52         });
  53. 53     }
  54. 54
  55. 55     private void playVideoFromFile(){
  56. 56         if(startCard.getText().toString().equals("PlayCard")) {
  57. 57             File file = new File(filename);
  58. 58             if (file.exists()) {
  59. 59                 //将VideoView与MediaController进行关联
  60. 60                 video.setVideoPath(file.getAbsolutePath());
  61. 61                 video.setMediaController(media);
  62. 62                 media.setMediaPlayer(video);
  63. 63                 //让VideoView获取焦点
  64. 64                 video.requestFocus();
  65. 65                 video.start();
  66. 66                 startCard.setText(R.string.pauseCard);
  67. 67                 fileName.setText(filename);
  68. 68             }
  69. 69         }
  70. 70         else {
  71. 71             video.pause();
  72. 72             startCard.setText(R.string.startCard);
  73. 73         }
  74. 74     }
  75. 75
  76. 76     private void openVideoFromUri(){
  77. 77         if(startUri.getText().toString().equals("PlayUri")) {
  78. 78             Uri uri = Uri.parse(filename);
  79. 79             video.setVideoURI(uri);
  80. 80             video.setMediaController(media);
  81. 81             media.setMediaPlayer(video);
  82. 82             //同上
  83. 83             video.requestFocus();
  84. 84             video.start();
  85. 85             startUri.setText(R.string.pauseUri);
  86. 86             fileName.setText(filename);
  87. 87         }
  88. 88         else {
  89. 89             video.pause();
  90. 90             startUri.setText(R.string.startUri);
  91. 91         }
  92. 92     }
  93. 93
  94. 94     @Override
  95. 95     public boolean onCreateOptionsMenu(Menu menu) {
  96. 96         // Inflate the menu; this adds items to the action bar if it is present.
  97. 97         getMenuInflater().inflate(R.menu.menu_main, menu);
  98. 98         return true;
  99. 99     }
  100. 100
  101. 101     @Override
  102. 102     public boolean onOptionsItemSelected(MenuItem item) {
  103. 103         // Handle action bar item clicks here. The action bar will
  104. 104         // automatically handle clicks on the Home/Up button, so long
  105. 105         // as you specify a parent activity in AndroidManifest.xml.
  106. 106         int id = item.getItemId();
  107. 107
  108. 108         //noinspection SimplifiableIfStatement
  109. 109         if (id == R.id.action_settings) {
  110. 110             return true;
  111. 111         }
  112. 112
  113. 113         return super.onOptionsItemSelected(item);
  114. 114     }
  115. 115 }
复制代码
3、运行结果分析
  OK,如今点击界面上的任何一个按钮就可以播放视频文件了。由于两个按钮的响应只是读取资源的方式不同,播放结果是一样的,以是下面只给出点击左边按钮PLAYCARD后的播放图:
  

    

  左边这张为程序运行后,没有任何操纵的图片,右边是正在播放视频的图片。
  可以发现两个有趣的征象:
    1、在布局文件activity_main.xml中已将videoView组件在父容器中的设置为水平居中(android:layout_centerHorizontal="true"),而且运行初始界面也是正常的,但是视频播放后,该组件就偏向了左边;
    2、播放过程中会有体系的控制栏出如今下方,可以点击进行视屏的播放控制,但是在测试很不稳定,出现一两秒就会消散;
  针对第一个问题,查了一些资料,有人说是由于默认环境下,如果视频分辨率小于设备的屏幕分辨率,VideoView在播放视频时都是在左上角显示的,将VideoView组件的gravity属性设置为center即可。但是在xml文件及UI编辑属性栏均没有找到VideoView组件有该属性,难道和版本有关?也有人说和底层的Player有关,固然没有进行替换测试,但感觉这个原因比较靠谱。至于第二个问题,暂时没有找到合理的表明,以后继续找吧。
  有知道真实原因的大神,欢迎一起讨论啊!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

自由的羽毛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表