zoukankan      html  css  js  c++  java
  • android之VideoView和视频播放View的扩展

    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用来得到 加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。
  • 相关阅读:
    The Quad
    将OrCAD Capture CIS的设计文件(.dsn)导入到PADS Logic VX.2.3
    OrCAD Capture CIS 16.6 将版本16.6的设计文件另存为版本16.2的设计文件
    Eclipse IDE 添加jar包到Java工程中
    PADS Logic VX.2.3 修改软件界面语言
    切换Allegro PCB Editor
    Allegro PCB Design GXL (legacy) 将brd文件另存为低版本文件
    Allegro PCB Design GXL (legacy) 设置自动保存brd文件
    Could not create an acl object: Role '16'
    windows 下apache开启FastCGI
  • 原文地址:https://www.cnblogs.com/makeryan/p/2495670.html
Copyright © 2011-2022 走看看