googlearchive/android-Camera2Video

The Preivew Size Stretch When Recording

Closed this issue · 8 comments

When previewing, we can find best match preview size with map.getOutputSizes(SurfaceTexture.class), it works find when preview, but when if start record, the preview size stretch, I set MediaRecorder video size with **mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());, but it doesn't work, you can see from this video that, when previewing, the circle is round, but when recording, it becomes oval. I have test it on MI6、MI Note and nexus 5X. Is there anyone encounter it?

I have seen your video form provided Link , i am facing same issue in every devices
When i start recording video the preview recording surface automatically zoom....
i have tried many different solution but not still find any solution ,if you have got solution please tell me
thanx

I have the same issue.. Did you guys figure out?
How to solve this?

I haven't figured out yet,

the reason why the preview stretch when you record is because you are recording with the textureView Size which height is not match parent. change the textureView height to "math_parent" and try again

Same problem ... Have you solved the issue?

Reason for stretching is early device is in 16:9 aspect ratio, but nowadays is came up to 18:9,19:9 & 19.5:9, aspect ratio. we have to customize the preview method, here is my code. hope it will help.
//Samsung-S6-choices[0]
//Samsung-S7-edge-choices[6]
//OnePlus-5T-choices[15]
/Following is used for Camera Preview in TextureView, based on device camera resolution/
/*
* Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
* width and height are at least as large as the respective requested values, and whose aspect
* ratio matches with the specified value.
*
* @param choices The list of sizes that the camera supports for the intended output class
* @param width The minimum desired width
* @param height The minimum desired height
* @param aspectRatio The aspect ratio
* @return The optimal {@code Size}, or an arbitrary one if none were big enough
*/

private  Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
        // Collect the supported resolutions that are at least as big as the preview Surface
        List<Size> bigEnough = new ArrayList<>();
        int w = aspectRatio.getWidth();
        int h = aspectRatio.getHeight();
        double ratio = (double) h / w;
        int loopCounter=0;
        for (Size size : choices) {
            int orientation = getActivityContext.getResources().getConfiguration().orientation;
            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                //if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=720) {
                //if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=3840 ) {
                //if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=5120 ) {//Retina 5K
                if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=7680 ) {//8K UHDTV Super Hi-Vision
                    Log.e(TAG1, "chooseOptimalSize:"+size+"--LoopPosition---==>"+loopCounter);
                    return size;
                }
            } else {
                Log.e(TAG1, "chooseOptimalSize:--given--"+size);
                if((size.getWidth()/16) == (size.getHeight()/9) && ((size.getWidth() <=1280)||(size.getHeight()<=1920))) {
                    //if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4320 ) ) {//8K UHDTV Super Hi-Vision
                    //if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2880 ) ) {//Retina 5K
                    //if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2160 ) ) {
                    //if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=1280 ) ) {
                    //if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4480 && size.getWidth() >=1280) ) {
                    Log.e(TAG1, "chooseOptimalSize:"+size+"-16:9"+"--LoopPosition---==>"+loopCounter);
                    return size;
                }else if((size.getWidth()/18) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {
                    Log.e(TAG1, "chooseOptimalSize:"+size+"-18:9"+"--LoopPosition---==>"+loopCounter);
                    return size;
                }else if((size.getWidth()/18.5) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {
                    Log.e(TAG1, "chooseOptimalSize:"+size+"-18.5:9"+"--LoopPosition---==>"+loopCounter);
                    return size;
                }else if((width/19) == (height/9) && ((width <=3840)||(height<=2160))) {
                    /*if((size.getWidth()/19) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {*/
                    Log.e(TAG1, "chooseOptimalSize:"+size+"-19:9"+"--LoopPosition---==>"+loopCounter);
                    return size;
                }else if((size.getWidth()/19.5) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {
                    Log.e(TAG1, "chooseOptimalSize:"+size+"-19.5:9"+"--LoopPosition---==>"+loopCounter);
                    return size;
                }else{
                    Log.e(TAG1, "chooseOptimalSize"+" not proper aspect resolution");
                }
                //2340
            }

            if(screenWidth==size.getWidth()){
                Log.e(TAG1, loopCounter+".choose:width Matched:"+screenWidth+"="+size.getWidth());
            }else{
                Log.e(TAG1, loopCounter+".choose:width Not Matched:"+screenWidth+"="+size.getWidth());
            }

            if(screenHeight==size.getHeight()){
                Log.e(TAG1, loopCounter+".choose:height Matched:"+screenHeight+"="+size.getHeight());
            }else{
                Log.e(TAG1, loopCounter+".choose:height Not Matched:"+screenHeight+"="+size.getHeight());
            }
            loopCounter++;
        }
        // Pick the smallest of those, assuming we found any
        if (bigEnough.size() > 0) {
            return Collections.min(bigEnough, new CompareSizesByArea());
        } else {
            Log.e(TAG1, "Couldn't find any suitable preview size");
            return choices[0];
        }
    }


    /*
     * Compares two {@code Size}s based on their areas.
     */
    static class CompareSizesByArea implements Comparator<Size> {
        @Override
        public int compare(Size lhs, Size rhs) {
            // We cast here to ensure the multiplications won't overflow
            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                    (long) rhs.getWidth() * rhs.getHeight());
        }
    }

If you find better idea, please let me know. Thank you.

Hi
Please use "chooseOptimalSize" from @mohanrajsambath and for further to show full screen without stretching view use this code for AutoFitTextureView.

class AutoFitTextureView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
TextureView(context, attrs, defStyle) {

private var mResolutionWidth = 0
private var mResolutionHeight = 0
private var deviceWidth: Int = 0
private var deviceHeight: Int = 0

fun setDeviceDimension(displayMetrics: DisplayMetrics) {
    deviceHeight = displayMetrics.heightPixels
    deviceWidth = displayMetrics.widthPixels
}

/**
 * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
 * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
 * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
 *
 * @param width  Relative horizontal size
 * @param height Relative vertical size
 */
fun setAspectRatio(width: Int, height: Int) {
    if (width < 0 || height < 0) {
        throw IllegalArgumentException("Size cannot be negative.")
    }
    mResolutionWidth = width
    mResolutionHeight = height
    requestLayout()
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    if (0 == mResolutionWidth || 0 == mResolutionHeight) {
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec))
    } else {
        if (mResolutionWidth > mResolutionHeight) {
            val h = ((deviceWidth * mResolutionWidth) / mResolutionHeight)
            if (h < deviceHeight) {
                val w = deviceHeight * mResolutionHeight / mResolutionWidth
                setMeasuredDimension(w, deviceHeight)
            } else {
                setMeasuredDimension(deviceWidth, h)
            }
        } 
    }
}
}

use this from your fragment
textureView.setAspectRatio(previewSize.width, previewSize.height)

The preview size is getting from "chooseOptimalSize()" function.

This sample has been migrated to a new location (check README for more information).

As recommended by GitHub, we are closing all issues and pull requests now that this older repo will be archived.

If you still see this issue in the updated repo, please reopen the issue/PR there. Thank you!