How to change aspect ratio of camera2 preview?

8k views Asked by At

I try to change the aspect ratio of the Camera2 preview but I fail :-(

For cropping I have to use the SCALER_CROP_REGION but I don't get it working.

I used the android-Camera2Video example from Google for my tests.

In the openCamera method I added the following line:

mSensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);

And in startPreview I added this:

final int centerX = mSensorSize.width() / 2;
final int centerY = mSensorSize.height() / 2;
final int cropSize = Math.min(mSensorSize.width(), mSensorSize.height());
final Rect crop = new Rect(centerY - cropSize / 2,
                           centerX - cropSize / 2,
                           cropSize,
                           cropSize);
mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, crop);

I should get a preview with a 1:1 ratio but it is 3:4 :-(

What did I wrong?

1

There are 1 answers

5
Umar Ata On

you may try to change onMeasure method inside your AutofitTextureView class

public class AutoFitTextureView extends TextureView {

    int maxwidth = 0;
    int maxheight = 0;
    private int mRatioWidth = 0;
    private int mRatioHeight = 0;
    private Size previewSize;

    public AutoFitTextureView(Context context) {
        this(context, null);
    }

    public AutoFitTextureView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setAspectRatio(int width, int height, int maxwidth, int maxheight, Size preview) {
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("Size cannot be negative.");
        }
        mRatioWidth = width;
        mRatioHeight = height;
        this.maxwidth = maxwidth;
        this.maxheight = maxheight;
        this.previewSize = preview;
        enterTheMatrix();
        requestLayout();
    }



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

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        boolean isFullBleed = true;
        if (0 == mRatioWidth || 0 == mRatioHeight) {
            setMeasuredDimension(width, height);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight,height);
         }

    }


    private void adjustAspectRatio(int previewWidth,
                                   int previewHeight,
                                   int rotation) {
        Matrix txform = new Matrix();
        int viewWidth = getWidth();
        int viewHeight = getHeight();
        RectF rectView = new RectF(0, 0, viewWidth, viewHeight);
        float viewCenterX = rectView.centerX();
        float viewCenterY = rectView.centerY();
        RectF rectPreview = new RectF(0, 0, previewHeight, previewWidth);
        float previewCenterX = rectPreview.centerX();
        float previewCenterY = rectPreview.centerY();

        if (Surface.ROTATION_90 == rotation ||
                Surface.ROTATION_270 == rotation) {
            rectPreview.offset(viewCenterX - previewCenterX,
                    viewCenterY - previewCenterY);

            txform.setRectToRect(rectView, rectPreview,
                    Matrix.ScaleToFit.FILL);

            float scale = Math.max((float) viewHeight / previewHeight,
                    (float) viewWidth / previewWidth);

            txform.postScale(scale, scale, viewCenterX, viewCenterY);
            txform.postRotate(90 * (rotation - 2), viewCenterX,
                    viewCenterY);
        } else {
            if (Surface.ROTATION_180 == rotation) {
                txform.postRotate(180, viewCenterX, viewCenterY);
            }
        }

        if (LollipopCamera.type == 1) {
            txform.postScale(-1, 1, viewCenterX, viewCenterY);
        }

        setTransform(txform);
    }

    private void enterTheMatrix() {
        if (previewSize != null) {
            adjustAspectRatio(mRatioWidth,
                    mRatioHeight,
                    ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation());
        }
    }
}

this is before applying above method enter image description here

and this is after applying above method enter image description here
Camera2Video google sample

and i also removed thse two lines in the fragment_camera2_video.xml

 android:layout_below="@id/texture"
    android:background="#4285f4"

I am calling setAspectRation from my camera Fragment as follows

  mPreviewSize = chooseOptimalSize(map.getOutputSizes(ImageFormat.JPEG),
                        rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                        maxPreviewHeight, largest);

                // We fit the aspect ratio of TextureView to the size of preview we picked.
                int orientation = getResources().getConfiguration().orientation;
                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    mTextureView.setAspectRatio(
                            mPreviewSize.getWidth(), mPreviewSize.getHeight(), universal_width, universal_height, largest);
                } else {
                    mTextureView.setAspectRatio(
                            mPreviewSize.getHeight(), mPreviewSize.getWidth(), universal_width, universal_height, largest);
                }