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对网络资源进行读取的方式和本地资源类似,只是资源名称的形式不同。如:
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文件中添加用户权限:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
程序中用到的String变量封装在了string.xml中:
<resources>
<string name="app_name">VideoView0803</string> <string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string> <string name="startCard">PlayCard</string>
<string name="pauseCard">StopCard</string>
<string name="startUri">PlayUri</string>
<string name="pauseUri">StopUri</string>
</resources>
界面上的组件由一个VideoView、两个Button,一个TextView组成,布局文件代码如下:
<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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/startCard"
android:id="@+id/startCard"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:textColor="#00f" /> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/startUri"
android:id="@+id/startUri"
android:layout_alignBottom="@+id/startCard"
android:layout_alignParentEnd="true"
android:textColor="#f00" /> <VideoView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/videoView"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_above="@+id/startUri"
android:layout_centerHorizontal="true" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Resource Path"
android:id="@+id/fileName"
android:layout_alignTop="@+id/startCard"
android:layout_alignParentBottom="true"
android:layout_toEndOf="@+id/startCard"
android:gravity="center_vertical"
android:textColor="#000"/> </RelativeLayout>
其中,VideoView组件videoView用于视频内容的播放,Button组件startFile和startUri分别以File和Uri形式打开视频文件,TextView组件fileName用于显示完整路径名(标注资源的来历,对于该例子没这个必要)。运行前的界面图:

主文件MainActivity完整代码如下:
package com.dylan_wang.videoview0803; import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.VideoView; import java.io.File; public class MainActivity extends Activity { private String filename = null;
private Button startCard = null;
private Button startUri = null;
private TextView fileName = null;
private VideoView video = null;
private MediaController media = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); filename = Environment.getExternalStorageDirectory() + "/Pictures/video.mp4"; startCard = (Button)findViewById(R.id.startCard);
startUri = (Button)findViewById(R.id.startUri);
fileName = (TextView)findViewById(R.id.fileName);
video = (VideoView)findViewById(R.id.videoView);
media = new MediaController(MainActivity.this); startCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playVideoFromFile();
}
}); startUri.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openVideoFromUri();
}
});
} private void playVideoFromFile(){
if(startCard.getText().toString().equals("PlayCard")) {
File file = new File(filename);
if (file.exists()) {
//将VideoView与MediaController进行关联
video.setVideoPath(file.getAbsolutePath());
video.setMediaController(media);
media.setMediaPlayer(video);
//让VideoView获取焦点
video.requestFocus();
video.start();
startCard.setText(R.string.pauseCard);
fileName.setText(filename);
}
}
else {
video.pause();
startCard.setText(R.string.startCard);
}
} private void openVideoFromUri(){
if(startUri.getText().toString().equals("PlayUri")) {
Uri uri = Uri.parse(filename);
video.setVideoURI(uri);
video.setMediaController(media);
media.setMediaPlayer(video);
//同上
video.requestFocus();
video.start();
startUri.setText(R.string.pauseUri);
fileName.setText(filename);
}
else {
video.pause();
startUri.setText(R.string.startUri);
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
}
}
3、运行结果分析
OK,现在点击界面上的任何一个按钮就可以播放视频文件了。由于两个按钮的响应只是读取资源的方式不同,播放效果是一样的,所以下面只给出点击左边按钮PLAYCARD后的播放图:

左边这张为程序运行后,没有任何操作的图片,右边是正在播放视频的图片。
可以发现两个有趣的现象:
1、在布局文件activity_main.xml中已将videoView组件在父容器中的设置为水平居中(android:layout_centerHorizontal="true"),而且运行初始界面也是正常的,但是视频播放后,该组件就偏向了左边;
2、播放过程中会有系统的控制栏出现在下方,可以点击进行视屏的播放控制,但是在测试很不稳定,出现一两秒就会消失;
针对第一个问题,查了一些资料,有人说是因为默认情况下,如果视频分辨率小于设备的屏幕分辨率,VideoView在播放视频时都是在左上角显示的,将VideoView组件的gravity属性设置为center即可。但是在xml文件及UI编辑属性栏均没有找到VideoView组件有该属性,难道和版本有关?也有人说和底层的Player有关,虽然没有进行替换测试,但感觉这个原因比较靠谱。至于第二个问题,暂时没有找到合理的解释,以后继续找吧。
有知道真实原因的大神,欢迎一起讨论啊!
Android视频播放之VideoView的更多相关文章
- Android 视频播放器 VideoView 的使用,播放本地视频 和 网络 视频
1.布局文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:and ...
- Android 视频播放器 (一):使用VideoView播放视频
一.简介 作为Android开发,我们不可避免的会接触到视频播放,VideoView做为最简单的播放器,我们是不应该不会的. 下面简单介绍一下VideoView: VideoView是使用MediaP ...
- Android 视频播放器 (二):使用MediaPlayer播放视频
在 Android 视频播放器 (一):使用VideoView播放视频 我们讲了一下如何使用VideoView播放视频,了解了基本的播放器的一些知识和内容.也知道VideoView内部封装的就是Med ...
- Android MediaPlayer和VideoView的使用
MediaPlayer MediaPlayer类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码和播放音视频.它支持三种不同的媒体来源: 本地资源 内部 ...
- Android 视频播放器切换到下个视频时残留上个视频画面的解决办法
最近在做一个Android视频播放器,遇到一个问题:切换到下一个视频时,中间会停留上一个视频的残存画面. 这是怎么回事? 我在网上找了很多资料,终于找到了原因:我是用自定义一个surfacev ...
- android视频播放器开发
http://blog.csdn.net/u010181592/article/details/49301703 http://blog.csdn.net/qq_33291295/article/de ...
- android视频播放心得体会
android视频播放主要是两种方式1.系统封装好的videoplayer,有前进.后退.暂停/播放.拉动最基本的功能,够一般使用,操作办法也很简单,如果需要自定义程度高就需要用到第二种方法:Surf ...
- Android视频播放软解与硬解的区别
硬解,用自带播放器播放,android中的VideoView 软解,使用音视频解码库,比如FFmpeg 一.硬解码 硬解:就是调用GPU的专门模块编码来解,减少CPU运算,对CPU等硬件要求也相对低点 ...
- android视频播放器系列(二)——VideoView
最近在学习视频相关的知识,现在也是在按部就班的一步步的来,如果有同样需求的同学可以跟着大家一起促进学习. 上一节说到了可以使用系统播放器以及浏览器播放本地以及网络视频,但是这在很大程度上并不能满足我们 ...
随机推荐
- coursera机器学习-支持向量机SVM
#对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...
- MySQL 调优基础(五) Linux网络
1. TCP/IP模型 我们一般知道OSI的网络参考模型是分为7层:“应表会传网数物”——应用层,表示层,会话层,传输层,网络层,数据链路层,物理层.而实际的Linux网络层协议是参照了OSI标准,但 ...
- linux文件分发脚本
1.说明 此脚本可分发两类文件,1.固定内容文件,2.(每台被分发主机)内容不同的文件 ppp.sh为拨号脚本,每台被分发主机内容不同 根据分发文件名字不同(ppp.sh和其他文件)自动选择分发方式 ...
- C#基础---IComparable用法,实现List<T>.sort()排序
List<T>.sort()可以实现对T的排序,比如List<int>.sort()执行后集合会按照int从小到大排序.如果T是一个自定义的Object,可是我们想按照自己的方 ...
- 微信支付 总提示get_brand_wcpay_request:fail 也不跳转支付页面 的解决方案
最近在做微信支付,帮客户部署好环境后,测试微信支付,发现点击支付后老是提示: get_brand_wcpay_request:fail, 于是找到代码中调用微信支付的代码段: WeixinJSBrid ...
- WPF学习笔记(一):数据绑定之元素到元素绑定
前言 作为一只菜鸟,之前学了一段时间的WPF,但是没有总结,过了一学期发现好多东西都忘记了,很多东西还是需要记下来,以备后续复习. 数据绑定在事件中应用非常广泛,可以有效地减少代码量,那么什么是数据绑 ...
- NOIP2012pj文化之旅[floyd]
描述 有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超过一次,即如果他学习了某种文化,则他就不能到达其他有这种文化的国家.不同的国家可能有相同的文化.不同文化的国家 ...
- Linux常用命令学习
1.ls命令 就是list的缩写,通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限)查看目录信息等等 常用参数搭配: ls -a 列出目录所有文 ...
- 如何在Kali Linux下编译Windows Exploit
前言 微软的Windows在企业或是个人应用领域占据着最大的市场份额,在渗透测试过程中你会经常遇到很多Windows的工作站和服务器.另一方面,大多数渗透测试人员主要使用基于Linux的发行版渗透测试 ...
- url编码base编码解码十六进制
0x25346425353425343525333525343325366125343525373725346425353125366625373825346425343425363725346225 ...