Matrix video on TextureView Android

I am trying to play video from ExoPlaye

to TextureView

. To scale and crop the video for viewing, I use a matrix. My custom view extends "TextureView". Here is my code:

@Override
public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio) {
    updateTextureViewSize(width, height);
    Log.v("EXO", "onVideoSizeChanged() " +  width + "x" + height);
}

private void updateTextureViewSize(float videoWidth, float videoHeight) {
    float viewWidth = getWidth();
    float viewHeight = getHeight();

    float scaleX = 1.0f;
    float scaleY = 1.0f;

    float viewRatio = viewWidth / viewHeight;
    float videoRatio = videoWidth / videoHeight;
    if (viewRatio > videoRatio) {
        // video is higher than view
        scaleY = videoHeight / videoWidth;
    } else {
        //video is wider than view
        scaleX = videoWidth / videoHeight;
    }

    Matrix matrix = new Matrix();
    matrix.setScale(scaleX, scaleY, viewWidth / 2, viewHeight / 2);


    setTransform(matrix);
}

      

I had a rectangular view and it worked fine. But now the views have 2 states: expanded (the old ones that are still rectangular) and collapsed (have a lower height.

So now the video is stretched vertically in these collapsed views.

For example, I have a preview 1080x480

and a video 360x640

, but it looks like the video is being scaled and cropped to 1080x1080

, rather than stretched to 1080x480

.

What am I doing wrong here?

UPD: Here are screenshots: enter image description here

+3


source to share


2 answers


check updateTextureViewSize

:



/**
 * Set the display options
 *
 * @param layout <ul>
 *               <li>{@link #VIDEO_LAYOUT_ORIGIN}
 *               <li>{@link #VIDEO_LAYOUT_SCALE}
 *               <li>{@link #VIDEO_LAYOUT_STRETCH}
 *               <li>{@link #VIDEO_LAYOUT_ZOOM}
 *               </ul>
 */
public void updateTextureViewSize(int layout,float videoWidth, float videoHeight) {
    RelativeLayout.LayoutParams lp = (android.widget.RelativeLayout.LayoutParams) getLayoutParams();
    DisplayMetrics disp = m_Context.getResources().getDisplayMetrics();
    int windowWidth = disp.widthPixels, windowHeight = disp.heightPixels;
    float windowRatio = windowWidth / (float) windowHeight;
    float videoRatio = (float) videoWidth / (float) videoHeight;
    m_iSurfaceHeight = videoHeight;
    m_iSurfaceWidth = videoWidth;
    if (VIDEO_LAYOUT_ORIGIN == layout && m_iSurfaceWidth < windowWidth && m_iSurfaceHeight < windowHeight) {
        lp.width = (int) (m_iSurfaceHeight * videoRatio);
        lp.height = m_iSurfaceHeight;
    } else if (layout == VIDEO_LAYOUT_ZOOM) {
        lp.width = windowRatio > videoRatio ? windowWidth : (int) (videoRatio * windowHeight);
        lp.height = windowRatio < videoRatio ? windowHeight : (int) (windowWidth / videoRatio);
    } else {
        boolean full = layout == VIDEO_LAYOUT_STRETCH;
        lp.width = (full || windowRatio < videoRatio) ? windowWidth : (int) (videoRatio * windowHeight);
        lp.height = (full || windowRatio > videoRatio) ? windowHeight : (int) (windowWidth / videoRatio);
        lp.leftMargin = (disp.widthPixels - lp.width) / 2;
        lp.topMargin = (disp.heightPixels - lp.height) / 2;
    }

    lp.leftMargin = (disp.widthPixels - lp.width) / 2;
    lp.topMargin = (disp.heightPixels - lp.height) / 2;

    getHolder().setFixedSize(m_iSurfaceWidth, m_iSurfaceHeight);

    setLayoutParams(lp);

    m_iVideoLayout = layout;
}

      

+1


source


I fixed this question by the following by multiplying or dividing the scale factors by viewRatio

( width / height

):

    if (viewRatio > videoRatio) {
        // video is higher than view
        scaleY = videoHeight / videoWidth * viewRatio;
    } else {
        //video is wider than view
        scaleX = videoWidth / videoHeight / viewRatio;
    }

      

But I didn't understand why this works. According to my calculations, if I have, for example, a view 1080x480

and the video the 360x640

video should be scaled with width x' = 1080

and proportional in height. So the height should be y' = 640*1080/360

( videoHeight * viewHeight / videoWidth

) andx' = 1080

According to this image: enter image description here



sx * 360 = 1080

=> sx = 1080 / 360

sy * 640 = 640*1080/360

=> sy = 1080 / 360

It sounds like it makes sense. If we want to keep the aspect ratio, the width and height must be multiplied by the same factor. But it doesn't work. Where is the mistake? Is there a good document on this?

+5


source







All Articles