Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VideoView doesn't scale content to match its parent

Tags:

android

I am using the DraggablePanel library (https://github.com/pedrovgs/DraggablePanel) to facilitate a YouTube like video player. If you are not familiar with this feature it basically allows the user to shrink the currently playing video into a small thumbnail that is docked into the corner of the screen.

Unfortunately (and I am not so sure this is an issue with the above library) I have noticed that if I apply an X and Y scale on the parent view of a VideoView, the VideoView itself will not resize its content to match.

See below screenshots, where VideoView is at its natural scale and then with its parent view scaled down to about 0.6:0.6. You should notice that in the scaled screenshot the VideoView has cropped its content instead of resizing to fit.

VideoView properly scaled 1:1

VideoView parent scaled to 0.6:0.6

So I tried to force a width and height on the VideoView as its parent's scale changed. There are a few examples on the internet about overriding the dimensions of a VideoView - but here is my simple version:

public class ScalableVideoView extends VideoView {

    private int mVideoWidth;
    private int mVideoHeight;

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

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

    public ScalableVideoView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mVideoWidth = 0;
        mVideoHeight = 0;
    }

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

        if (mVideoWidth > 0 && mVideoHeight > 0) {
            // If a custom dimension is specified, force it as the measured dimension
            setMeasuredDimension(mVideoWidth, mVideoHeight);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    public void changeVideoSize(int width, int height) {
        mVideoWidth = width;
        mVideoHeight = height;

        getHolder().setFixedSize(width, height);

        requestLayout();
        invalidate();
    }

}

The fragment that contains the VideoView is responsible for calling changeVideoSize on it when it receives a notification from the DraggablePanel library about a change in scale. At which point I calculate a new pair of width and height based on the provided scale values. (scale is from 0f to 1f)

public void setVideoViewScale(float scaleX, float scaleY) {
        if (mMaxVideoWidth == 0) {
            mMaxVideoWidth = mVideoView.getWidth();
        }

        if (mMaxVideoHeight == 0) {
            mMaxVideoHeight = mVideoView.getHeight();
        }

        if (mMaxVideoWidth > 0) {

            mVideoView.changeVideoSize((int) (scaleX * mMaxVideoWidth),
                    (int) (scaleY * mMaxVideoHeight));
        }
    }

Unfortunately this causes some really interesting results. It seems that the Video portion of the VideoView is scaling appropriately - but the bounds of the VideoView seem to be scaling too fast (causing the video to both shrink and crop).

ScalingVideoView at 0.5 scale

For further demonstration here are two videos:

  • https://github.com/npike/so_scalevideoview/blob/master/demo_videos/so_videoview_noscale.mp4
  • https://github.com/npike/so_scalevideoview/blob/master/demo_videos/so_videoview_scale.mp4

I have also uploaded this sample project to GitHub so that you can see the complete code: https://github.com/npike/so_scalevideoview

like image 791
NPike Avatar asked Sep 30 '22 19:09

NPike


1 Answers

I was having the same problem with my app, so I took your example that is much simpler, and tried to fix it.
This is the code that fixes the problem. Edit your changeVideoSize(int width, int height) method to:

public void changeVideoSize(int width, int height){
    mVideoWidth = width;
    mVideoHeight = height;

    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(width, height);
    lp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
    lp.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    setLayoutParams(lp);

    requestLayout();
    invalidate();
}

With the invalidation of the view you force the VideoView to redraw the whole View with the new layout parameters.

like image 110
OscarBudo Avatar answered Oct 11 '22 02:10

OscarBudo