Android audio and video development series - VideoView use

Get into the habit of writing together! This is the 4th day of my participation in the "Nuggets Daily New Plan·April Update Challenge", click to view the details of the event .

Introduction to VideoView

I have previously introduced the use of MediaPlayer+ SurfaceViewto realize the function of playing video. I accidentally found that the official packaged VideoViewcomponents to realize the simple video playback function, and the MediaPlayer+ SurfaceViewform is also used to control MediaPlayerthe playback of video files. The usage scenario is relatively simple, and it is suitable for the scenario of just playing the video. Its limited ability is not suitable for other functions such as adjusting the video brightness.

MediaController

In addition to the playback component VideoView, there is also a MediaControllercomponent that provides a playback operation bar function for video playback, which supports video playback, pause, fast forward, fast reverse and other functions. In addition, it also provides a progress bar function that can be dragged to a specified position to play the video.

use

VideoViewThe package MediaPlayeralso provides a similar MediaPlayerAPI. For example start, the method is also the function of playing video, but it is best to set the setOnpreparedListenercallback result before calling the method to execute the method, and the method setVideoPathwill be actively executed after the prepareAsyncmethod is called. It VideoViewhelps developers to encapsulate and implement many functions internally. In fact, it can also learn from its internal source code to realize a more comprehensive and more complete self-made player.

Common APIs illustrate
setVideoPath Set up video assets
start play
pause pause
resume replay
seekTo Play at a specified location
isPlaying Whether the video is playing
getCurrentPosition Get the current playback position
setMediaController Set up MediaController
setOnpreparedListener Listen for video loading completion event
// 实例化videoView     
videoView = new VideoView(this);
Uri uri = Uri.fromFile(new File("sdcard/DCIM","新世纪福音战士24.mp4"));
//加载视频资源
videoView.setVideoURI(uri);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.addView(videoView);
setContentView(linearLayout);
//设置监听
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        //回调成功并播放视频
        videoView.start();
    }
});
//创建操作栏
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
mediaController.setMediaPlayer(videoView);
复制代码

a5a4ba6ebe7731127c5f2f64eb01b134.jpg

Source code analysis

VideoViewNow that the two components are encapsulated MediaController, many functions that have been tried to be implemented before are found in the process of use to see how they are implemented.

progress display

MediaControllerA method showcan be seen inside the calling method when displayedpost(mShowProgress);

public void show(int timeout) {
    if (!mShowing && mAnchor != null) {
        setProgress();
        if (mPauseButton != null) {
            mPauseButton.requestFocus();
        }
        disableUnsupportedButtons();
        updateFloatingWindowLayout();
        mWindowManager.addView(mDecor, mDecorLayoutParams);
        mShowing = true;
    }
    updatePausePlay();

    // cause the progress bar to be updated even if mShowing
    // was already true.  This happens, for example, if we're
    // paused with the progress bar showing the user hits play.
    post(mShowProgress);

    if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
        removeCallbacks(mFadeOut);
        postDelayed(mFadeOut, timeout);
    }
}
复制代码

It can be seen that it mShowProgressis one Runnable, and the internal delay will call itself to update setProgress(). setProgress()The method is to read the MediaPlayerplayback progress to update the playback information.

private final Runnable mShowProgress = new Runnable() {
    @Override
    public void run() {
        int pos = setProgress();
        if (!mDragging && mShowing && mPlayer.isPlaying()) {
            postDelayed(mShowProgress, 1000 - (pos % 1000));
        }
    }
};
复制代码

Play size adaptation

Before customizing the playback size adaptation, it VideoViewdirectly helps developers to achieve video playback adaptation internally. The detailed code can be onMeasuredirectly rewritten. The approximate algorithm of the code is VideoViewto rewrite the calculated width and height by comparing the width and height of the layout and the width and height of the video VideoView.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
    //        + MeasureSpec.toString(heightMeasureSpec) + ")");

    int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
    int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
    if (mVideoWidth > 0 && mVideoHeight > 0) {

        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
            // the size is fixed
            width = widthSpecSize;
            height = heightSpecSize;

            // for compatibility, we adjust size based on aspect ratio
            if ( mVideoWidth * height  < width * mVideoHeight ) {
                //Log.i("@@@", "image too wide, correcting");
                width = height * mVideoWidth / mVideoHeight;
            } else if ( mVideoWidth * height  > width * mVideoHeight ) {
                //Log.i("@@@", "image too tall, correcting");
                height = width * mVideoHeight / mVideoWidth;
            }
        } else if (widthSpecMode == MeasureSpec.EXACTLY) {
            // only the width is fixed, adjust the height to match aspect ratio if possible
            width = widthSpecSize;
            height = width * mVideoHeight / mVideoWidth;
            if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
                // couldn't match aspect ratio within the constraints
                height = heightSpecSize;
            }
        } else if (heightSpecMode == MeasureSpec.EXACTLY) {
            // only the height is fixed, adjust the width to match aspect ratio if possible
            height = heightSpecSize;
            width = height * mVideoWidth / mVideoHeight;
            if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
                // couldn't match aspect ratio within the constraints
                width = widthSpecSize;
            }
        } else {
            // neither the width nor the height are fixed, try to use actual video size
            width = mVideoWidth;
            height = mVideoHeight;
            if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
                // too tall, decrease both width and height
                height = heightSpecSize;
                width = height * mVideoWidth / mVideoHeight;
            }
            if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
                // too wide, decrease both width and height
                width = widthSpecSize;
                height = width * mVideoHeight / mVideoWidth;
            }
        }
    } else {
        // no size yet, just adopt the given spec sizes
    }
    setMeasuredDimension(width, height);
}
复制代码

Guess you like

Origin juejin.im/post/7085243234523283464