wake-up-neo.com

Android - So verwenden Sie die Kamera getSupportedPreviewSizes () für die Ausrichtung im Hochformat

Ich versuche, eine Kameravorschau in eine Aktivität einzubetten. Und das nur im Hochformat. Das Problem ist, dass die Vorschau gestreckt wird.

Ich habe versucht, die optimale Größe auszuwählen. Das Problem ist jedoch, dass alle unterstützten Vorschaugrößen aus getSupportedPreviewSizes() die Größe im Querformat anzeigen. Die Auswahl der richtigen Größe gemäß meinem Code funktioniert also nicht, denke ich. 

Mein Layout XML: 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/activity_take_attendance"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:paddingBottom="@dimen/activity_vertical_margin"
    Android:paddingLeft="@dimen/activity_horizontal_margin"
    Android:orientation="vertical"
    Android:paddingRight="@dimen/activity_horizontal_margin"
    Android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.lab.rafael.smartattendance.TakeAttendanceActivity">

    <TextView
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:text="@string/take_attendance_label"
        Android:id="@+id/take_attendance_label"
        Android:layout_marginBottom="@dimen/activity_vertical_margin"/>

    <!-- camera preview container -->
    <FrameLayout
        Android:layout_width="wrap_content"
        Android:layout_height="0dp"
        Android:layout_weight="1"
        Android:background="@color/red"
        Android:id="@+id/take_attendance_scan_qr_frame"/>

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content">
        <EditText
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:hint="@string/take_attendance_manual_text"
            />
        <Button
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="@string/take_attendance_manual_button"
            Android:id="@+id/take_attendance_manual_button"/>
    </LinearLayout>
</LinearLayout>

Hier ist meine CameraPreview-Klasse:

package com.lab.rafael.smartattendance.camera;

import Android.content.Context;
import Android.hardware.Camera;
import Android.util.Log;
import Android.view.SurfaceHolder;
import Android.view.SurfaceView;
import Java.io.IOException;
import Java.util.List;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private Camera mCamera = null;
    private SurfaceHolder mHolder = null;
    private Camera.Size optimalSize = null;

    public CameraPreview(Context context, Camera camera)
    {
        super(context);
        mCamera = camera;
        mHolder = getHolder();
        mHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            Camera.Parameters params = mCamera.getParameters();
            List<String> focusModes = params.getSupportedFocusModes();
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewDisplay(holder);

            if(focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }

            if(optimalSize != null) {
                params.setPreviewSize(optimalSize.width, optimalSize.height);
            }

            mCamera.setParameters(params);

            mCamera.startPreview();
        } catch (IOException e)
        {
            Log.e("created_error", e.getMessage());
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if(mHolder.getSurface() == null) {
            return;
        }

        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            Log.e("changed_error", e.getMessage());
        }

        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e){
            Log.e("error", e.getMessage());
        }
    }

    @Override
    public void onMeasure(int measureWidthSpec, int measureHeightSpec) {
        optimalSize = getOptimalSize(MeasureSpec.getSize(measureWidthSpec), MeasureSpec.getSize(measureHeightSpec));
        setMeasuredDimension(optimalSize.width, optimalSize.height);
    }

    protected Camera.Size getOptimalSize(int width, int height) {
        List<Camera.Size> supportedSizes = mCamera.getParameters().getSupportedPreviewSizes();
        double targetRatio = (double) width / height,
                optimalRatio = 0.0,
                acceptableRatioMargin = 0.1,
                minDiff = Double.MAX_VALUE;


        for(Camera.Size size : supportedSizes) {
            optimalRatio = (double) size.width / size.height;
            if(Math.abs(optimalRatio - targetRatio) < acceptableRatioMargin) {
                if(Math.abs(height - size.height) < minDiff) {
                    minDiff = Math.abs(height - size.height);
                    optimalSize = size;
                }
            }
        }

        if(optimalSize == null) {
            for(Camera.Size size : supportedSizes) {
                if(Math.abs(height - size.height) <= minDiff) {
                    minDiff = Math.abs(height - size.height);
                    optimalSize = size;
                }
            }
        }

        return optimalSize;
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
    }
}

Die folgenden Bilder ergeben sich aus den Werten: 

Specified resolution from measureSpecWidth/Height = `984x1335`

Returned from getOptimalSize() = `1600x1200`.

Denn supportedPreviewSizes ist für Querformat kein Hochformat.

Hier ist das Ergebnis:

 enter image description here

17
Rafael Adel

Ich hatte das gleiche Problem wie vor einem Jahr. Außerdem musste ich mich mit Front- und Rückkameras beschäftigen. Ich erinnere mich nicht viel an den Code, aber ich habe es ausprobiert, bevor ich diese Antwort gepostet habe und er funktioniert immer noch wie ein Zauber.
Ich hoffe, Sie können mit Ihrem Code graben und vergleichen. Ich kann mehr Code teilen, wenn gerade etwas funktioniert;)

/**
 * A simple wrapper around a Camera and a SurfaceView that renders a centered preview of the Camera
 * to the surface. We need to center the SurfaceView because not all devices have cameras that
 * support preview sizes at the same aspect ratio as the device's display.
 */
public class Preview extends ViewGroup implements SurfaceHolder.Callback {

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Camera.Size mPreviewSize;
    List<Camera.Size> mSupportedPreviewSizes;
    Camera mCamera;
    private Context context;
    private int mCameraId;
    public boolean use_front_camera;

    public Preview(Context context, int cameraId) {
        super(context);

        this.context = context;
        mCameraId = cameraId;
        use_front_camera = true;

        mSurfaceView = new SurfaceView(context);
        addView(mSurfaceView);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            requestLayout();
        }
    }

    public void switchCamera(Camera camera) {
        setCamera(camera);
        try {
            camera.setPreviewDisplay(mHolder);
        } catch (IOException exception) {
            Android.util.Log.e(IdelityConstants.DEBUG_IDELITY_KEY_LOG, "IOException caused by setPreviewDisplay()", exception);
        }
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        requestLayout();

        camera.setParameters(parameters);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // We purposely disregard child measurements because act as a
        // wrapper to a SurfaceView that centers the camera preview instead
        // of stretching it.

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        //MUST CALL THIS
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                /**
                 * Como el calculo se hace con la cámara en modo landscape y luego toca
                 * girar la cámara para que se vea bien, se pasan los valores cambiados.
                 */
                previewWidth = mPreviewSize.height;
                previewHeight = mPreviewSize.width;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight < height * previewWidth) {
                final int scaledChildWidth = previewWidth * height / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2,
                    width, (height + scaledChildHeight) / 2);
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            Android.util.Log.e(IdelityConstants.DEBUG_IDELITY_KEY_LOG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
    //        if (mCamera != null) {
    //            mCamera.stopPreview();
    //        }
    }


    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin    
        // the preview.

        if (mCamera == null)
            return;

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        parameters.setJpegQuality(100);
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);


        List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
        Camera.Size size = sizes.get(0);
        for(int i=0;i<sizes.size();i++)
        {
            if(sizes.get(i).width > size.width)
                size = sizes.get(i);
        }
        parameters.setPictureSize(size.width, size.height);


        requestLayout();


        mCamera.setParameters(parameters);
            mCamera.setDisplayOrientation(getCameraDisplayOrientation((FragmentActivity)context, mCameraId));
        mCamera.startPreview();
    }


    public static int getCameraDisplayOrientation(FragmentActivity activity, int cameraId) {
        Camera.CameraInfo info = new Camera.CameraInfo();

        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        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;
        }


        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        }
        else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }

        return result;
    }


    /** A safe way to get an instance of the Camera object. */
    public static Camera getCameraInstance(int cameraIndex){
        Camera c = null;
        try {
            c = Camera.open(cameraIndex); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
            Android.util.Log.e(IdelityConstants.ERROR_IDELITY_KEY_LOG, "Camera is not available: " + e.getMessage());
        }
        return c; // returns null if camera is unavailable
    }
}



Hier ist das XML, es ist einfach (Sie werden im Screenshot sehen). Das einzig Wichtige ist das FrameLayout mit der ID: capture_evidence_camera_preview

<RelativeLayout
    Android:layout_width="fill_parent"
    Android:layout_height="0dp"
    Android:id="@+id/capture_evidence_linearLayout_camera"
    Android:layout_weight="3"
    Android:layout_gravity="center_horizontal">


    <FrameLayout
        Android:id="@+id/capture_evidence_camera_preview"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_centerVertical="true"
        Android:layout_centerHorizontal="true"/>

    <TextView
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:text="@string/capture_evidence_default_text_number_evidence"
        Android:id="@+id/capture_evidence_textView_value_typed"
        Android:textSize="50sp"
        Android:textColor="@color/idelity_blanco"
        Android:gravity="center_horizontal"
        Android:paddingLeft="5dp"
        Android:paddingRight="5dp"
        Android:background="#d2000000"
        Android:layout_alignParentBottom="true"
        Android:layout_centerHorizontal="true"
        Android:paddingTop="8dp"
        Android:paddingBottom="8dp" />
</RelativeLayout>


<RelativeLayout
    Android:layout_width="fill_parent"
    Android:layout_height="0dp"
    Android:layout_weight="1">

    <net.idelity.idelitymobile.ui.helpers.IdelityButton
        Android:layout_width="wrap_content"
        Android:layout_height="fill_parent"
        Android:text="@string/button_back"
        Android:id="@+id/capture_evidence_button_cancel"
        Android:layout_alignParentBottom="true"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true"
        Android:background="@drawable/button_gray"
        Android:textColor="@color/idelity_blanco"
        Android:textSize="20sp"
        Android:paddingLeft="40dp"
        Android:paddingRight="40dp"
        Android:textStyle="bold" />

    <net.idelity.idelitymobile.ui.helpers.IdelityButton
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent"
        Android:id="@+id/capture_evidence_button_capture_evidence"
        Android:layout_alignParentBottom="true"
        Android:layout_toRightOf="@+id/capture_evidence_button_cancel"
        Android:layout_toEndOf="@+id/capture_evidence_button_cancel"
        Android:background="@drawable/take_photo_button_camera"
        Android:textSize="25sp"
        Android:textColor="@color/idelity_blanco"
        Android:textStyle="bold"
        Android:text="@string/capture_evidence_button_capture_evidence"
        Android:paddingBottom="10dp" />
</RelativeLayout>

 XML preview

Es wird unter einer FragmentActivity verwendet (ich kann es teilen, wenn Sie es auch brauchen)

8
MiguelHincapieC

tl; dr Die Größen, die sowohl in getSupportedPreviewSizes() als auch in setPreviewSize(int width, int height) verwendet werden, befinden sich in der ursprünglichen Kameraausrichtung. Diese kann (und ist normalerweise) von der natürlichen Telefonausrichtung und der aktuellen Displayausrichtung abweichen. 

Aus diesem Grund hat die getOptimalSize(int, int)-Methode die Größen durchlaufen, wenn sie auf ihrer Seite sind (und deshalb 1/ratio verwenden), keine davon auswählen und am Ende ein falsches Verhältnis wählen, basierend auf der Höhe gemäß der zweiten Schleife in der Methode, was zu einem zerquetschten Bild führt.


Anscheinend beziehen sich die unterstützten Größen immer auf die Kamera in ihrem natürlichen Winkel (obwohl dies in der Dokumentation nicht vermerkt ist). Der natürliche Blickwinkel der Kamera entspricht normalerweise nicht dem natürlichen Blickwinkel des Telefons. Sie können den Unterschied zwischen ihnen mithilfe des Feldes CameraInfo.orientation überprüfen.

Die Dokumentation, die darauf hindeutet, dass dies wahr ist (abgesehen vom Ausprobieren), ist die gleiche Dokumentation, die auch Ihr Rätsel löst: Camera.Parameters.setPreviewSize(int width, int height):

Breite und Höhe der Seiten basieren auf der Kameraausrichtung. Das heißt, die Vorschaugröße ist die Größe, bevor sie durch die Anzeigeausrichtung gedreht wird. Daher müssen Anwendungen die Anzeigeausrichtung beim Einstellen der Vorschaugröße berücksichtigen. Angenommen, die Kamera unterstützt die Vorschaugrößen 480x320 und 320x480. Die Anwendung möchte eine Vorschau von 3: 2. Wenn die Anzeigeausrichtung auf 0 oder 180 eingestellt ist, sollte die Vorschaugröße auf 480x320 eingestellt werden. Wenn die Anzeigeausrichtung auf 90 oder 270 eingestellt ist, sollte die Vorschaugröße auf 320 x 480 eingestellt werden. Die Anzeigeausrichtung sollte auch beim Einstellen von Bildgröße und Miniaturbildgröße berücksichtigt werden.

( Dokumentation hier )

Daraus können wir einiges lernen:

  1. Die Größen, die Sie erhalten, sollten gleich sein, unabhängig von der Ausrichtung des Displays/des Telefons. Daher ist an den Werten, die Sie dort sehen, nichts falsch. Sie sollten sie auf die Seite drehen, um die beste Methode für die onMeasure () -Methode auszuwählen, um die Ansicht im Hochformat zu messen (basierend auf dem Bildschirm und dem Platz, den die Vorschau einnehmen soll).

    Idealerweise drehen Sie sie, nachdem Sie den Montagewinkel der Kamera bestätigt haben, und der aktuelle Winkel des Telefons ist nicht kompatibel (ein Querformat und ein Hochformat).

    //in getOptimalSize(int width, int height)
             //isCameraOnSide() is a new method you should implement
             //return true iff the camera is mounted on the side compared to 
             //the phone's natural orientation.
    double targetRatio = (isCameraOnSide()) ?  (double) height / width 
                            : (double) width / height,
            optimalRatio = 0.0,
            acceptableRatioMargin = 0.1,
            minDiff = Double.MAX_VALUE;
    
    
    for(Camera.Size size : supportedSizes) {
        optimalRatio = (double) size.width / size.height;
        if(Math.abs(optimalRatio - targetRatio) < acceptableRatioMargin) {
            if(Math.abs(height - size.height) < minDiff) {
                minDiff = Math.abs(height - size.height);
                optimalSize = size;
            }
        }
    }
    

    In Ihren und meinen Fällen gibt isCameraOnSide()true zurück - wie wir aus Ihrer Zeile von setPreviewOrientation(90) sehen können. Für eine allgemeinere Implementierung finden Sie hier ein Camera2Basic-Beispiel von Google:

    private boolean isCameraOnSide(){
        int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        //Inquire the sensor's orientation relative to the natural phone's orientation
        Android.hardware.Camera.CameraInfo info =
            new Android.hardware.Camera.CameraInfo();
        Android.hardware.Camera.getCameraInfo(0, info); //Back-facing camera
        int sensorOrientation = info.orientation;
    
        boolean swappedDimensions = false;
        switch (displayRotation) {
            case Surface.ROTATION_0:
            case Surface.ROTATION_180:
                if (sensorOrientation == 90 || sensorOrientation == 270) {
                    swappedDimensions = true;
                }
                break;
            case Surface.ROTATION_90:
            case Surface.ROTATION_270:
                if (sensorOrientation == 0 || sensorOrientation == 180) {
                    swappedDimensions = true;
                }
                break;
            default:
                Log.e(TAG, "Display rotation is invalid: " + displayRotation);
        }
    
        return swappedDimensions;
    }
    
  2. Und noch wichtiger: Wenn Sie die Camera.Parameters.getPreviewSize()-Methode als Uhr oder in einem Protokoll verwenden, werden Sie wahrscheinlich feststellen, dass ein anderes Verhältnis als das mit der setMearuseDimension(int, int)-Methode gewählte Verhältnis hat. Dieser Verhältnisunterschied ist der Ursprung der Dehnung/des Kürbisses (er sieht in Ihrem Bild vertikal zusammengedrückt aus. That kann auch ein Hinweis darauf sein, dass die Verzerrung nicht aus einer Landschafts-/Porträt-Verwirrung besteht Landschaftsbild im Hochformat würde vertikal gestreckt und nicht gestaucht werden). Nachdem Sie die richtige Größe für die Ansicht (in diesem Fall SurfaceView) ausgewählt haben, sollten Sie Camera.Parameters.setPreviewSize(int width, int height) mit einer unterstützten Vorschaugröße aufrufen, die das gleiche Verhältnis wie die für die Ansicht verwendete Größe hat (wiederum Breite entsprechend der Kamera, nicht das aktuelle Telefon)/Anzeigeorientierung. Dies bedeutet, dass der Parameter height verwendet werden kann.

    Zum Beispiel könnten Sie das in surfaceCreated- und surfaceChanged-Methoden tun (bei mir gearbeitet). Vergewissern Sie sich, dass die Vorschau nicht aktiv ist, wenn Sie die Vorschaugröße der Kamera festgelegt haben, und starten Sie sie (oder starten Sie sie erneut), nachdem Sie die folgenden Schritte ausgeführt haben:

        //inside surfaceCreated(SurfaceHolder holder)
        Camera.Parameters params = mCamera.getParameters(); 
        Camera.Size prevSize = getOptimalSize(getWidth(), getHeight()); 
             //prevSize should be still in the camera's orientation. In your and my cases - landscape
        params.setPreviewSize(prevSize.width, prevSize.height);
        mCamera.setParameters(params);
    
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
    
3
et_l

Ich habe eine Zeitlang an der Entwicklung von Kameraanwendungen gearbeitet, und es gibt viele Dinge, die zu berücksichtigen sind, aber lassen Sie uns einfach bleiben

  1. Versuchen Sie, die Zielansichtsgröße mit dem gleichen Seitenverhältnis wie eine der gängigen unterstützten Vorschaugrößen (3: 2, 16: 9, 4: 3) festzulegen. Wenn Sie nicht versuchen können, eine Vorschaugröße zu wählen, die den kleinsten Unterschied im Seitenverhältnis hat
  2. Nachdem Sie eine geeignete Ansichtsgröße ausgewählt haben, können Sie sie innerhalb Ihrer Aktivität zentrieren, indem Sie onLayout() in Ihrer CameraPreview überschreiben.
0
Mohammad Abbas
public static Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    return determineBestSize(sizes);
}

public static Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
    List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
    return determineBestSize(sizes);
}

protected static Camera.Size determineBestSize(List<Camera.Size> sizes) {
    Camera.Size bestSize = null;
    long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    long availableMemory = Runtime.getRuntime().maxMemory() - used;
    for (Camera.Size currentSize : sizes) {
        int newArea = currentSize.width * currentSize.height;
        long neededMemory = newArea * 4 * 4; // newArea * 4 Bytes/pixel * 4 needed copies of the bitmap (for safety :) )
        boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
        boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
        boolean isSafe = neededMemory < availableMemory;
        if (isDesiredRatio && isBetterSize && isSafe) {
            bestSize = currentSize;
        }
    }
    if (bestSize == null) {
        return sizes.get(0);
    }
    return
0
MIkka Marmik