zoukankan      html  css  js  c++  java
  • Android视频播放之VideoView

    Android视频播放之VideoView

     

    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 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    3 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

          程序中用到的String变量封装在了string.xml中:

     1 <resources>
     2     <string name="app_name">VideoView0803</string>
     3 
     4     <string name="hello_world">Hello world!</string>
     5     <string name="action_settings">Settings</string>
     6 
     7     <string name="startCard">PlayCard</string>
     8     <string name="pauseCard">StopCard</string>
     9     <string name="startUri">PlayUri</string>
    10     <string name="pauseUri">StopUri</string>
    11 </resources>

      界面上的组件由一个VideoView、两个Button,一个TextView组成,布局文件代码如下:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
     3     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
     4     android:paddingRight="@dimen/activity_horizontal_margin"
     5     android:paddingTop="@dimen/activity_vertical_margin"
     6     android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
     7 
     8     <Button
     9         android:layout_width="wrap_content"
    10         android:layout_height="wrap_content"
    11         android:text="@string/startCard"
    12         android:id="@+id/startCard"
    13         android:layout_alignParentBottom="true"
    14         android:layout_alignParentStart="true"
    15         android:textColor="#00f" />
    16 
    17     <Button
    18         android:layout_width="wrap_content"
    19         android:layout_height="wrap_content"
    20         android:text="@string/startUri"
    21         android:id="@+id/startUri"
    22         android:layout_alignBottom="@+id/startCard"
    23         android:layout_alignParentEnd="true"
    24         android:textColor="#f00" />
    25 
    26     <VideoView
    27         android:layout_width="wrap_content"
    28         android:layout_height="wrap_content"
    29         android:id="@+id/videoView"
    30         android:layout_alignParentStart="true"
    31         android:layout_alignParentTop="true"
    32         android:layout_above="@+id/startUri"
    33         android:layout_centerHorizontal="true" />
    34 
    35     <TextView
    36         android:layout_width="wrap_content"
    37         android:layout_height="wrap_content"
    38         android:textAppearance="?android:attr/textAppearanceMedium"
    39         android:text="Resource Path"
    40         android:id="@+id/fileName"
    41         android:layout_alignTop="@+id/startCard"
    42         android:layout_alignParentBottom="true"
    43         android:layout_toEndOf="@+id/startCard"
    44         android:gravity="center_vertical"
    45         android:textColor="#000"/>
    46 
    47 </RelativeLayout>

      其中,VideoView组件videoView用于视频内容的播放,Button组件startFile和startUri分别以File和Uri形式打开视频文件,TextView组件fileName用于显示完整路径名(标注资源的来历,对于该例子没这个必要)。运行前的界面图:

           主文件MainActivity完整代码如下:

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

      

    3、运行结果分析

      OK,现在点击界面上的任何一个按钮就可以播放视频文件了。由于两个按钮的响应只是读取资源的方式不同,播放效果是一样的,所以下面只给出点击左边按钮PLAYCARD后的播放图:

          

      左边这张为程序运行后,没有任何操作的图片,右边是正在播放视频的图片。

      可以发现两个有趣的现象:

        1、在布局文件activity_main.xml中已将videoView组件在父容器中的设置为水平居中(android:layout_centerHorizontal="true"),而且运行初始界面也是正常的,但是视频播放后,该组件就偏向了左边;

        2、播放过程中会有系统的控制栏出现在下方,可以点击进行视屏的播放控制,但是在测试很不稳定,出现一两秒就会消失;

      针对第一个问题,查了一些资料,有人说是因为默认情况下,如果视频分辨率小于设备的屏幕分辨率,VideoView在播放视频时都是在左上角显示的,将VideoView组件的gravity属性设置为center即可。但是在xml文件及UI编辑属性栏均没有找到VideoView组件有该属性,难道和版本有关?也有人说和底层的Player有关,虽然没有进行替换测试,但感觉这个原因比较靠谱。至于第二个问题,暂时没有找到合理的解释,以后继续找吧。

      有知道真实原因的大神,欢迎一起讨论啊!

  • 相关阅读:
    JQuery Ajax 在asp.net中使用总结
    直接拿来用!最火的Android开源项目(一)
    专访邓凡平:Android开发路上的快速学习之道
    C/C++使用心得:enum与int的相互转换
    学习汇编的第一步
    《汇编程序》王爽实验9的解法(显示的问题)
    《汇编程序》王爽实验10.2的解法
    GDB调试精粹及使用实例
    aptget 使用详解
    《汇编程序》王爽实验10.3的解法
  • 原文地址:https://www.cnblogs.com/tgyf/p/4700177.html
Copyright © 2011-2022 走看看