Android相机预览在全屏上被拉伸显示。

huangapple go评论71阅读模式
英文:

Android Camera Preview is stretched on Full screen

问题

以下是翻译好的部分:

我正在为我的应用程序使用自定义相机进行AR视图。在全屏纵向模式下,相机预览会被拉伸。

我已经尝试了许多在stackoverflow上的解决方案,但对于我的代码来说没有起作用。
有人可以告诉我如何修复这个问题吗?

我已经添加了我的相机工作代码和下面的截图,显示了预览被拉伸的情况。

这是我的自定义相机类:

public class ARCamera extends ViewGroup implements SurfaceHolder.Callback {
    // ... (代码部分略)
}

Android相机预览在全屏上被拉伸显示。

英文:

I'm using a Custom Camera for my app for AR View. The Camera preview is getting stretched on full screen portrait mode.

I have tried many solutions on stackoverflow but it's not working for my code.
Can anyone please tell me how to fix this?

I have added my camera working code and a screenshot below where the preview is getting stretched.

This is my Custom Camera Class:

public class ARCamera extends ViewGroup implements SurfaceHolder.Callback {
    private final static float Z_NEAR = 0.5f;
    private final static float Z_FAR = 2000;
    private final String TAG = ARCamera.class.getSimpleName();
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    Camera camera;
    Activity activity;
    float[] projectionMatrix = new float[16];
    int cameraWidth;
    int cameraHeight;
    int screenWidth, screenHeight;
    int rotation;

    public ARCamera(Context context, SurfaceView surfaceView) {
        super(context);

        this.surfaceView = surfaceView;
        this.activity = (Activity) context;
        surfaceHolder = this.surfaceView.getHolder();
        surfaceHolder.addCallback(this);

        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);

        rotation = windowManager.getDefaultDisplay()
                .getRotation();

        this.screenWidth = displayMetrics.widthPixels;
        this.screenHeight = displayMetrics.heightPixels;


    }

    public void setCamera(Camera camera) {
        this.camera = camera;

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

    }

    public void surfaceCreated(SurfaceHolder holder) {
        try {
            if (camera != null) {

                Camera.CameraInfo info = new Camera.CameraInfo();
                Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);

                int degrees = 0;
                switch (rotation) {
                    case Surface.ROTATION_0:
                        degrees = 0;
                        break;
                    case Surface.ROTATION_90:
                        degrees = 90;
                        break;
                    case Surface.ROTATION_180:
                        degrees = 180;
                        break;
                    case Surface.ROTATION_270:
                        degrees = 270;
                        break;
                }

                camera.setDisplayOrientation((info.orientation - degrees + 360) % 360);

                camera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        if (camera != null) {
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (camera != null) {
            this.cameraWidth = width;
            this.cameraHeight = height;

            Camera.Parameters parameters = camera.getParameters();
            try {
                List<Camera.Size> supportedSizes = camera.getParameters().getSupportedPreviewSizes();
                for (Camera.Size element : supportedSizes) {
                    element.width -= cameraWidth;
                    element.height -= cameraHeight;
                }
                Collections.sort(supportedSizes, new ResolutionOrders());
                parameters.setPreviewSize(width + supportedSizes.get(supportedSizes.size() - 1).width, height + supportedSizes.get(supportedSizes.size() - 1).height);
            } catch (Exception ex) {
                parameters.setPreviewSize(screenWidth, screenHeight);
            }

            this.camera.setParameters(parameters);
            this.camera.startPreview();

            generateProjectionMatrix();
        }
    }

    private void generateProjectionMatrix() {
        float ratio = (float) this.screenWidth / this.screenHeight;
        final int OFFSET = 0;
        final float LEFT = -ratio;
        final float RIGHT = ratio;
        final float BOTTOM = -1;
        final float TOP = 1;
        Matrix.frustumM(projectionMatrix, OFFSET, LEFT, RIGHT, BOTTOM, TOP, Z_NEAR, Z_FAR);
    }

    public float[] getProjectionMatrix() {
        return projectionMatrix;
    }

    class ResolutionOrders implements java.util.Comparator<Camera.Size> {
        public int compare(Camera.Size left, Camera.Size right) {
            return Float.compare(left.width + left.height, right.width + right.height);
        }
    }

}

Android相机预览在全屏上被拉伸显示。

答案1

得分: 0

在表面变化的块中,您需要根据您的设备编程选择最佳大小。

List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();

这将为您提供支持的相机尺寸的列表。您需要从中选择合适的尺寸。我使用了名为 "chooseOptimalSize" 的函数。

Size aspectRatio = new Size(matrix.widthPixels, matrix.heightPixels);

Camera.Size previewSize = chooseOptimalSize(previewSizes, PREFERRED_PREVIEW_WIDTH, PREFERRED_PREVIEW_HEIGHT, aspectRatio, this);

这是 "chooseOptimalSize" 函数的定义:

public static Camera.Size chooseOptimalSize(List<Camera.Size> choices, int width, int height, Size aspectRatio, Context c) {
    // 收集至少与预览表面一样大的支持分辨率
    List<Size> bigEnough = new ArrayList<>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    double ratio = (double) h / w;
    int loopCounter = 0;
    for (Camera.Size size : choices) {
        int orientation = c.getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            if ((size.width / 16) == (size.height / 9) && size.width <= 7680) {
                Log.e(TAG, "chooseOptimalSize:" + size + "--LoopPosition---=>" + loopCounter);
                return size;
            }
        } else {
            // 其他情况的逻辑判断...
        }
        loopCounter++;
    }
    return choices.get(0);
}

static class CompareSizesByArea implements Comparator<Size> {
    @Override
    public int compare(Size lhs, Size rhs) {
        return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                (long) rhs.getWidth() * rhs.getHeight());
    }
}

如果需要,您可以取消注释代码。在我的情况下,不需要该代码。

这个函数将会给您设备相机的最佳尺寸。您可以使用以下代码设置相机预览大小:

parameters.setPreviewSize(previewSize.width, previewSize.height);

然后您就完成了!

英文:

In the surface changed block, you have to choose the optimal size according to your device programmatically.

List&lt;Camera.Size&gt; previewSizes = parameters.getSupportedPreviewSizes();

this will give you total supported camera sizes. you have to choose appropriate size from this. I have use the function called "chooseOptimalSize".

Size aspectRatio = new Size(matrix.widthPixels, matrix.heightPixels);

Camera.Size previewSize = chooseOptimalSize(previewSizes, PREFERRED_PREVIEW_WIDTH, PREFERRED_PREVIEW_HEIGHT, aspectRatio, this);

This is the function "chooseOptimalSize":-

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

//            if(screenWidth==size.getWidth()){
//                Log.e(TAG1, loopCounter+&quot;.choose:width Matched:&quot;+screenWidth+&quot;=&quot;+size.getWidth());
//            }else{
//                Log.e(TAG1, loopCounter+&quot;.choose:width Not Matched:&quot;+screenWidth+&quot;=&quot;+size.getWidth());
//            }
//
//            if(screenHeight==size.getHeight()){
//                Log.e(TAG1, loopCounter+&quot;.choose:height Matched:&quot;+screenHeight+&quot;=&quot;+size.getHeight());
//            }else{
//                Log.e(TAG1, loopCounter+&quot;.choose:height Not Matched:&quot;+screenHeight+&quot;=&quot;+size.getHeight());
//            }
            loopCounter++;
        }
        // Pick the smallest of those, assuming we found any
//        if (bigEnough.size() &gt; 0) {
//            return Collections.min(bigEnough, new CompareSizesByArea());
//        } else {
//            Log.e(TAG, &quot;Couldn&#39;t find any suitable preview size&quot;);
            return choices.get(0);
//        }
    }


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

you can uncomment the code if you want in my case there is no need of that code.

This function will give you optimal size of the device's camera. you can set that using :

parameters.setPreviewSize(previewSize.width,previewSize.height);

and you are done !!!

huangapple
  • 本文由 发表于 2020年10月5日 19:55:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/64208146.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定