您的位置:首页 > 移动开发 > Android开发

android之VideoView和视频播放View的扩展

2015-09-04 10:25 441 查看
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用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: