Realization of Dynamic Background Video in QQ7.0 Login Interface of Original Android Mobile Phone

Posted by M2tM on Mon, 10 Jun 2019 04:12:13 +0200

Qq7.0 login interface dynamic background realizes qq7.0 login interface dynamic video background realizes android dynamic video background android dynamic background

qq7.0:

Video starts playing when the login interface is opened, and there is no black screen during that time.
And it's looping.

Let's not talk about the quality of the picture. This video source.

It allows irregular width, varying video proportions and video sizes to accommodate any Android phone's width, including the flat panel, without leaving any gaps.

Player control selection: to solve the problem of mobile phone adaptation, and the other is the player control, where the selection of system player is better. Because some players do not support reading Uri of asset folder, such as Qiniu's.

The first frame is replaced by a picture and needs to be coupled with the first frame of the video.

The first frame of the picture is intercepted by a professional adobe premiere development tool, which you can also let ps and other later stages to do, which is still a small kiss for me.

Technical points:
How to Read Resource File Video
How to Measure
How to Calculate the Scaling Proportion of Video Size to Solve the Problem of No Black Edge on Video Phone of Any Size
How to make the picture cover zoom in and out small and match the video zoom in and out small
How to Call onStart Transient Black Screen

Architecture Construction

Reading of resources

   String VIDEO_PATH = "android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.raw.login;
videoView.setVideoURI(Uri.parse(Constants.VIDEO_PATH));

Create a custom video class custom picture class on top of the video because the video is not immediately played and loaded for a certain time there will also be a black screen.

As for the problem of reading video, previous attempts to read the video in assests failed, and the stack overflow photography failed. Finally, the video was put into the res/ray folder.

Video Controls Specifically Implemented

1. Get the width and height of the video before you can measure and rearrange it.

Add the setOnPreparedListener method to the inherited VideoView to get the width and height of the video set to the member variable.

 super.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(final MediaPlayer mp) {


      SystemVideoView.this.videoWidth = mp.getVideoWidth();
      SystemVideoView.this.videoHeight = mp.getVideoHeight();

}
}

2. Inheriting VideoView Rewriting onMeasure Measurement Method

A perfect algorithm is needed to solve the problem of full screen width and height.

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        MeasureUtil.Size measure = MeasureUtil.measure(displayAspectRatio, widthMeasureSpec, heightMeasureSpec, videoWidth, videoHeight);

        setMeasuredDimension(measure.width, measure.height);
    }

The algorithm here is more troublesome, students do not understand the template code.
MeasureUtil.measure method extraction
The approximate code is

    public static MeasureUtil.Size measure(int displayAspectRatio, int widthMeasureSpec, int heightMeasureSpec, int videoWidth, int videoHeight) {


 if (widthMode == View.MeasureSpec.EXACTLY && heightMode == View.MeasureSpec.EXACTLY) {  

  if (percentVideo > percentView) {
                            width = widthSize;
                            height = (int) ((float) widthSize / percentVideo);
                        } else {
                            height = heightSize;
                            width = (int) ((float) heightSize * percentVideo);
                        }

    }else if (widthMode == View.MeasureSpec.EXACTLY) {
                width = widthSize;
                height = widthSize * videoHeight / videoWidth;
                if (heightMode == View.MeasureSpec.AT_MOST && height > heightSize) {
                    height = heightSize;
                }
            } else if (heightMode == View.MeasureSpec.EXACTLY) {
                height = heightSize;
                width = heightSize * videoWidth / videoHeight;
                if (widthMode == View.MeasureSpec.AT_MOST && width > widthSize) {
                    width = widthSize;
                }
            } else {
                width = videoWidth;
                height = videoHeight;
                if (heightMode == View.MeasureSpec.AT_MOST && videoHeight > heightSize) {
                    height = heightSize;
                    width = heightSize * videoWidth / videoHeight;
                }

                if (widthMode == View.MeasureSpec.AT_MOST && width > widthSize) {
                    width = widthSize;
                    height = widthSize * videoHeight / videoWidth;
                }
            }

}


public static class Size {
        public final int width;
        public final int height;

        public Size(int width, int height) {
            this.width = width;
            this.height = height;
        }
    }

3. Probe into the Solution of Black Screen Problem

There is a certain probability of black screen milliseconds just by calling start
First of all, regardless of the measurement pavement problem, we found that there will be a pit, that is, the video black screen problem, enter this interface must make it non-black screen.
1. It's no use trying to show hidden results in onPrepared and then in VideoView.
1. The direct hiding control is extended for several seconds on the basis of scheme 1. It is still hidden in the start process (different mobile phones need different lengthening time). But if there is no screen movement in the process of 0 seconds to 1 seconds, if it moves, the video will need to stay longer than 1 seconds after displaying the control. Otherwise, the first frame is not consistent with the time when the video view is displayed, which is found later. There's no way to solve the problem of circular playback.

The final solution found by Baidu is based on the first frame of info's video.

  mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra) {
                        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                            if (onCorveHideListener != null) {
                                onCorveHideListener.requestHide();
                            }
                        }
                        if (onInfoListener != null) {
                            onInfoListener.onInfo(mp, what, extra);
                        }
                        return false;
                    }
                });

Picture solutions are the same as videos. You need code to reward one, haha.

The hidden method is out there. It's called setOn CorveHideListener. In fact, when you enter the interface, you should immediately display the hidden video of the screen. It's a white screen, so you need it here.

Final interface activity or fragment code

    String VIDEO_PATH = "android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.raw.login;

    loginActivityBinding.videoView.setDisplayAspectRatio(MeasureUtil.ASPECT_RATIO_PAVED_PARENT);
        loginActivityBinding.videoView.setOnCorveHideListener(new SystemVideoView.OnCorveHideListener() {
            @Override
            public void requestHide() {
                loginActivityBinding.corver.setVisibility(View.GONE);
            }
        });
        loginActivityBinding.videoView.setVideoURI(Uri.parse(Constants.VIDEO_PATH));
        loginActivityBinding.videoView.start();
        loginActivityBinding.videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                loginActivityBinding.videoView.seekTo(0);
                loginActivityBinding.videoView.start();
            }
        });




 @Override
    public void onPause() {
        super.onPause();
        loginActivityBinding.videoView.pause();
    }

    @Override
    public void onResume() {
        super.onResume();
        loginActivityBinding.videoView.start();
    }

Complete System VideoView code

public class SystemVideoView extends VideoView {


    private int videoWidth;//width
    private int videoHeight;
    private int displayAspectRatio;

    public SystemVideoView(Context context) {
        super(context);
    }

    public SystemVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SystemVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);

    }

    protected void init(Context context) {
        this.videoHeight = context.getResources().getDisplayMetrics().heightPixels;
        this.videoWidth = context.getResources().getDisplayMetrics().widthPixels;

        super.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(final MediaPlayer mp) {

                SystemVideoView.this.videoWidth = mp.getVideoWidth();
                SystemVideoView.this.videoHeight = mp.getVideoHeight();
                mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra) {
                        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                            if (onCorveHideListener != null) {
                                onCorveHideListener.requestHide();
                            }
                        }
                        if (onInfoListener != null) {
                            onInfoListener.onInfo(mp, what, extra);
                        }
                        return false;
                    }
                });
            }
        });
    }

    MediaPlayer.OnPreparedListener onPreparedListener = null;

    public interface OnCorveHideListener {
        void requestHide();
    }

    @Override
    public void setOnInfoListener(MediaPlayer.OnInfoListener onInfoListener) {
        this.onInfoListener = onInfoListener;
    }

    MediaPlayer.OnInfoListener onInfoListener;

    public void setOnCorveHideListener(OnCorveHideListener onCorveHideListener) {
        this.onCorveHideListener = onCorveHideListener;
    }

    OnCorveHideListener onCorveHideListener;

    @Override
    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
        this.onPreparedListener = l;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);


        MeasureUtil.Size measure = MeasureUtil.measure(displayAspectRatio, widthMeasureSpec, heightMeasureSpec, videoWidth, videoHeight);
        setMeasuredDimension(measure.width, measure.height);





    public void setDisplayAspectRatio(int var1) {
        displayAspectRatio = var1;
        this.requestLayout();

    }


    @Override
    public boolean isPlaying() {
        return false;
    }

    public int getDisplayAspectRatio() {
        return displayAspectRatio;
    }

    public void setCorver(int resource) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), resource, opts);

    }

My blog
My brief book

Topics: MediaPlayer Android Mobile Fragment