对视频播放器的理解

说起播放器,首先想到的是VideoView。当我们对VedioView初始化结束后,要设置播放资源,这时调用了setVideoURI(Uri uri),查看该方法:

    /**
     * Sets video URI.
     *
     * @param uri the URI of the video.
     */
    public void setVideoURI(Uri uri) {
        setVideoURI(uri, null);
    }

    /**
     * Sets video URI using specific headers.
     *
     * @param uri     the URI of the video.
     * @param headers the headers for the URI request.
     *                Note that the cross domain redirection is allowed by default, but that can be
     *                changed with key/value pairs through the headers parameter with
     *                "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
     *                to disallow or allow cross domain redirection.
     */
    public void setVideoURI(Uri uri, Map<String, String> headers) {
        mUri = uri;
        mHeaders = headers;
        mSeekWhenPrepared = 0;
        openVideo();//打开资源
        requestLayout();
        invalidate();
    }

此时我们查看openVideo()方法,发现里面创建了一个MediaPlayer对象,然后使用该对象设置了一系列的监听。

            mMediaPlayer.setOnPreparedListener(mPreparedListener);
            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
            mMediaPlayer.setOnErrorListener(mErrorListener);
            mMediaPlayer.setOnInfoListener(mInfoListener);
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
            mCurrentBufferPercentage = 0;
            mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
            mMediaPlayer.setDisplay(mSurfaceHolder);
            mMediaPlayer.setAudioAttributes(mAudioAttributes);
            mMediaPlayer.setScreenOnWhilePlaying(true);
            //进行异步prepare,prepare()适合播放本地视频,但是最好都用prepareAsync()
            mMediaPlayer.prepareAsync();

继续查看prepareAsync()方法

    /**
     * Prepares the player for playback, asynchronously.
     *
     * After setting the datasource and the display surface, you need to either
     * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
     * which returns immediately, rather than blocking until enough data has been
     * buffered.
     *
     * @throws IllegalStateException if it is called in an invalid state
     */
    public native void prepareAsync() throws IllegalStateException;

发现prepareAsync()是一个native方法,由此我们发现MediaPlayer主要负责和底层库进行交流,通过JNI调用底层C代码进行视频解码,MediaPlayer中加载了media_jni。

    static {
        System.loadLibrary("media_jni");
        native_init();
    }

当底层执行完毕后,MediaPlayer中的EventHandler会收到MEDIA_PREPARED的消息,这时我们VideoView注册的监听便能执行。准备好之后当然是开始播放了,我们调用VideoView的start()方法,该方法又调用了MediaPlayer的start()方法,最终还是调用了native方法。其它方法也是如此。

private native void _start() throws IllegalStateException;

当视频可以播放的时候,我们需要一个可以控制视频播放暂停的面板。系统恰好为我们提供了一个。
* MediaController,继承自FrameLayout。通过
videoView.setMediaController(new MediaController(context))将gaiview同VideoView进行了关联。但MediaController是如何控制视频的播放呢?查看MediaController发现,该类中定义了一个接口:

    public interface MediaPlayerControl {
        void    start();
        void    pause();
        int     getDuration();
        int     getCurrentPosition();
        void    seekTo(int pos);
        boolean isPlaying();
        int     getBufferPercentage();
        boolean canPause();
        boolean canSeekBackward();
        boolean canSeekForward();

        /**
         * Get the audio session id for the player used by this VideoView. This can be used to
         * apply audio effects to the audio track of a video.
         * @return The audio session, or 0 if there was an error.
         */
        int     getAudioSessionId();
    }

而VideoView是MediaPlayerControl的实现类。通过mMediaController.setMediaPlayer(this)将自己传递给MediaController。之后的操作就可以通过接口回调传递过来了。

    //和MediaController建立连接
    private void attachMediaController() {
        if (mMediaPlayer != null && mMediaController != null) {
            mMediaController.setMediaPlayer(this);
            View anchorView = this.getParent() instanceof View ?
                    (View)this.getParent() : this;
            //添加锚点视图
            mMediaController.setAnchorView(anchorView);
            mMediaController.setEnabled(isInPlaybackState());
        }
    }

补充:VideoView继承自SurfaceView。SurfaceView默认使用双缓冲技术,支持在子线程程中绘制图像,这样就不会阻塞主线程了,所以它更适合游戏和视频播放器的开发

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值