1.概念及扩展

  VideoView 是android 系统提供的一个媒体播放显示和控制的控件。其结构层次如下:

  原型:VideoView extends SurfaceView implements MediaController.MediaPlayerControl

  类结构:

      java.lang.Object

        ↳ android.view.View

          ↳ android.view.SurfaceView

            ↳ android.widget.VideoView

  通过VideoView 的原型可知:如果构建更为复杂和有特色个性的视频View,需要继承SurfaceView 和实现MediaPlayerControl接口。其中SurfaceView 为显示提供支持,MediaPlayerControl则为媒体控制提供了支持。

2.案例

1)VideoView案例

(我们没有管理MediaPalyer的各种状态,这些状态都让VideoView给封装了,并且,当VideoView创建的时候,MediaPalyer对象将会创建,当VideoView对象销毁的时候,MediaPlayer对象将会释放。)

布局文件

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"     android:layout_height="fill_parent"> <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"     android:layout_centerInParent="true" /> </LinearLayout>

主程序:

public class VideoPlayer extends Activity implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
public static final String TAG = "VideoPlayer";
private VideoView mVideoView;
private Uri mUri;
private int mPositionWhenPaused = -1; private MediaController mMediaController; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.main); //Set the screen to landscape.
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mVideoView = (VideoView)findViewById(R.id.video_view); //Video file
mUri = Uri.parse(Environment.getExternalStorageDirectory() + "/1.3gp"); //Create media controller,组件可以控制视频的播放,暂停,回复,seek等操作,不需要你实现
mMediaController = new MediaController(this);
mVideoView.setMediaController(mMediaController);
} public void onStart() {
// Play Video
mVideoView.setVideoURI(mUri);
mVideoView.start(); super.onStart();
} public void onPause() {
// Stop video when the activity is pause.
mPositionWhenPaused = mVideoView.getCurrentPosition();
mVideoView.stopPlayback(); super.onPause();
} public void onResume() {
// Resume video player
if(mPositionWhenPaused >= 0) {
mVideoView.seekTo(mPositionWhenPaused);
mPositionWhenPaused = -1;
} super.onResume();
} public boolean onError(MediaPlayer player, int arg1, int arg2) {
return false;
} public void onCompletion(MediaPlayer mp) {
this.finish();
}
}

2)自定义VideoView

和VideoView实现类似,继承了SurfaceView并且实现了MediaPlayerControl。

public class CustomerVideoView extends SurfaceView implements
MediaPlayerControl {
private static String TAG = "customer.videoplayer";
private boolean pause;
private boolean seekBackward;
private boolean seekForward;
private Uri videoUri;
private MediaPlayer mediaPlayer;
private Context context;
private OnPreparedListener onPreparedListener;
private int videoWidth;
private int videoHeight;
private MediaController mediaController;
protected SurfaceHolder surfaceHolder;
private Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
public void surfaceChanged(SurfaceHolder holder, int format, int w,
int h) {
}
public void surfaceCreated(SurfaceHolder holder) {
surfaceHolder = holder;
if (mediaPlayer != null) {
mediaPlayer.setDisplay(surfaceHolder);
resume();
} else {
openVideo();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceHolder = null;
if (mediaController != null) {
mediaController.hide();
}
release(true);
}
};
private void release(boolean cleartargetstate) {
if (mediaPlayer != null) {
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
public void resume() {
if (surfaceHolder == null) {
return;
}
if (mediaPlayer != null) {
return;
}
openVideo();
}
public CustomerVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
this.initVideoView();
}
public CustomerVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.initVideoView();
}
public CustomerVideoView(Context context) {
super(context);
this.context = context;
this.initVideoView();
}
@Override
public boolean canPause() {
return this.pause;
}
@Override
public boolean canSeekBackward() {
return this.seekBackward;
}
@Override
public boolean canSeekForward() {
return this.seekForward;
}
@Override
public int getBufferPercentage() {
return 0;
}
@Override
public int getCurrentPosition() {
return mediaPlayer!=null?mediaPlayer.getCurrentPosition():0;
}
@Override
public int getDuration() {
return mediaPlayer!=null?mediaPlayer.getDuration():0;
}
@Override
public boolean isPlaying() {
return false;
}
@Override
public void pause() {
}
@Override
public void seekTo(int mSec) {
}
@Override
public void start() {
}
public void setVideoURI(Uri uri) {
this.videoUri = uri;
openVideo();
requestLayout();
invalidate();
}
private void openVideo() {
this.mediaPlayer = new MediaPlayer();
try {
this.mediaPlayer.setDataSource(this.context, this.videoUri);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
throw new RuntimeException(e);
}
this.mediaPlayer.prepareAsync();
this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
this.mediaPlayer.setOnPreparedListener(onPreparedListener);
attachMediaController();
}
private void attachMediaController() {
if (mediaPlayer != null && mediaController != null) {
mediaController.setMediaPlayer(this);
View anchorView = this.getParent() instanceof View ? (View) this
.getParent() : this;
mediaController.setAnchorView(anchorView);
mediaController.setEnabled(true);
}
}
public void setMediaController(MediaController controller) {
if (mediaController != null) {
mediaController.hide();
}
mediaController = controller;
attachMediaController();
}
public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
this.onPreparedListener = onPreparedListener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(videoWidth, widthMeasureSpec);
int height = getDefaultSize(videoHeight, heightMeasureSpec);
if (videoWidth > 0 && videoHeight > 0) {
if (videoWidth * height > width * videoHeight) {
height = width * videoHeight / videoWidth;
} else if (videoWidth * height < width * videoHeight) {
width = height * videoWidth / videoHeight;
}
}
Log.i(TAG, "setting size: " + width + ‘x’ + height);
setMeasuredDimension(width, height);
}
private void initVideoView() {
videoWidth = 0;
videoHeight = 0;
getHolder().addCallback(surfaceHolderCallback);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
}
}

一般情况下,android界面的绘制和更新,要交给主ui线程来操作,通过Handler机制。但是播放视频,需要比较优先和实时的改变和绘制界面。android提供了使用单独线程绘制UI的机制,就是SurfaceView。使用SurfaceView,需要实现SurfaceHolder.Callback接口:

  • surfaceCreated,在Surface(SurfaceView内部包含一个Surface实例)创建后,会立即调用该方法,可在该方法中做绘制界面相关的初始化工作;
  • surfaceChanged,当Surface的状态发生变化,比如大小,会调用该方法,在surfaceCreated方法调用过至少会调用一次该方法;
  • surfaceDestroyed,当销毁Surface的时候调用。

  开发者不能直接操作Surface实例,要通过SurfaceHandler,在SurfaceView中可以通过getHandler方法获取到SurfaceHandler实例。 SurfaceHander有一些类型,用来标识Surface实例界面数据来源,可以通过setType来操作:

  • SURFACE_TYPE_NORMAL:RAM缓存的原生数据
  • SURFACE_TYPE_HARDWARE:通过DMA,direct memory access,就是直接写屏技术获取到的数据,或者其他硬件加速的数据
  • SURFACE_TYPE_GPU:通过GPU加速的数据
  • SURFACE_TYPE_PUSH_BUFFERS:标识数据来源于其他对象,比如照相机,比如视频播放服务器(android内部有视频播放的服务器,所有播放视频相当于客户端)

  CustomerVideoView的构造方法,使用超类的构造方法。都会执行initVideoView()方法用来初始化界面和参数。另外一个主要的内容是openVideo()方法:

  • mediaPlayer.prepareAsync(),用来异步准备播放,另外还有个prepare()方法,是同步的,也就是全部下载完毕才能播放,显然,在播放网上视频的时候需要用前者;
  • 通过attachMediaController()方法,把控制条附加到播放视频的SurfaceView上,这里实现的不完全,因此还不能使用,仅仅是把MediaPlayerControl实例通过setMediaPlayer方法设置一下,供OnPreparedListener用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。

android之VideoView和视频播放View的扩展的更多相关文章

  1. Android开发 VideoView视频播放详解

    前言 VideoView是Android主要的视频播放View,它其实是对MediaPlayer的再次封装.如果你已经了解过MediaPlayer在使用VideoView是十分简单的.如果你想先了解M ...

  2. Android下VideoView的研究

    VideoView继承自SurfaceView,实现了MediaController.MediaPlayerControl的接口.在android系统中的包名为android.widget.Video ...

  3. android中VideoView播放sd卡上面的视频

    (1)videoView组件只支持MP4和3gp格式的视屏播放,如果想播放其它视屏格式的文件,还得开发能够播放的视屏播放器 (2)videoView组件功能比较单一,如果想开发功能丰富的播放器,还得重 ...

  4. android 修改videoview的宽度和高度

    如果直接用android的videoview.他是不允许你随意的修改宽度和高度的,所以我们要重写videoview! package com.hysmarthotel.view; import and ...

  5. android采用videoView播放视频(包装)

    //android播放视频.用法:于androidManifest.xml添加activity, // <activity android:name=".PlayVideo" ...

  6. Android查缺补漏(View篇)--自定义 View 的基本流程

    View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...

  7. Android使用VideoView播放本地视频及网络视频Demo

    1.xm文件 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:and ...

  8. Android开发艺术探索笔记——View(二)

    Android开发艺术探索笔记--View(二) View的事件分发机制 学习资料: 1.Understanding Android Input Touch Events System Framewo ...

  9. Android开发艺术探索笔记—— View(一)

    Android开发艺术探索笔记 --View(一) View的基础知识 什么是View View是Android中所有控件的基类.是一种界面层控件的抽象. View的位置参数 参数名 获取方式 含义 ...

随机推荐

  1. Linux 服务器配置JDK

    1. 查看java版本 [root@plttestap5 ~]# java -versionjava version "1.8.0_121"Java(TM) SE Runtime ...

  2. 【BZOJ1226】[SDOI2009]学校食堂Dining 状压DP

    [BZOJ1226][SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满 ...

  3. 九度OJ 1250:矩阵变换 (矩阵运算)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:95 解决:47 题目描述: 对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一, 现给出一正数矩 ...

  4. ibatis实现Iterate的使用 (转)

    <iterate         property="" /*可选,              从传入的参数集合中使用属性名去获取值,              这个必须是一 ...

  5. spring属性注入方式

    一.使用有参构造注入属性 配置文件 constructor-arg标签是需注入属性的名字 User类 生成了User的有参构造函数 测试类 结果 打印出了name属性的值 二.使用set方法注入属性 ...

  6. Java之线程池(二)

    关于线程和线程池的学习,我们可以从以下几个方面入手: 第一,什么是线程,线程和进程的区别是什么 第二,线程中的基本概念,线程的生命周期 第三,单线程和多线程 第四,线程池的原理解析 第五,常见的几种线 ...

  7. vMware存储:SAN配置基础

    VMware存储不仅仅是将LUN映射给物理服务器这么简单.VMware vSphere允许系统管理员在一个物理机上创建多个虚拟机. 潜在的hypervisor和vSphere ESXi,能够使gues ...

  8. IM系统中如何保证消息的可靠投递(即QoS机制)(转)

    消息的可靠性,即消息的不丢失和不重复,是im系统中的一个难点.当初qq在技术上(当时叫oicq)因为以下两点原因才打败了icq:1)qq的消息投递可靠(消息不丢失,不重复)2)qq的垃圾消息少(它an ...

  9. Advanced GET 9.1 修正汉化版(免注册、页面加载、保存都正常)

    http://www.55188.com/viewthread.php?tid=2846679 Advanced GET 9.1 修正汉化版(免注册.页面加载.保存都正常) 网上流传的很多GET9.1 ...

  10. GIT笔记:将项目发布到GITHUB

    GIT笔记:将项目发布到GITHUB 本机配置 1.在项目目录初始化GIT $ git init 2.用命令git add告诉Git,把文件添加到仓库 $ git add . // 这里是所有文件,用 ...