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用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。

本文链接:http://www.cnblogs.com/devinzhang/archive/2012/02/04/2338125.html

更多相关文章

  1. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  2. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  3. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  4. Android动画TweenAnimation的使用方法
  5. android 5.1 USB调试开关
  6. Android学习笔记之数据库
  7. 【Android】小白进阶之接口和抽象类的使用
  8. Android(安卓)Studio获取网络JSON数据并处理的方法
  9. Android与单片机通信常用数据转换方法总结

随机推荐

  1. ScrollView实现界面自动滚动
  2. 使用IntelliJ IDEA 编译Android(安卓)JNI
  3. Android(安卓)UI开发第二十八篇——Fragm
  4. 10 个 Android开发人员必备的开发工具
  5. Android(安卓)文件系统移植
  6. Android下Bonjour服务的使用
  7. MVP 笔记
  8. Android平台软件体系浅注
  9. Android菜鸟日记12 Gallery
  10. Android中常用基本控件的使用方法和步骤(.