Android camera preview look strange

后端 未结 4 966
醉梦人生
醉梦人生 2020-12-11 05:41

I am implementing a camera app and when I look at the preview (especially with front camera), the image is very fat. It looks like the image get stretched horizontally. I fo

相关标签:
4条回答
  • 2020-12-11 05:51

    I already solved problem. What could cause problem with strange camera preview.

    • Status bar takes spaces - you can hide it Hiding the Status Bar

    • Some spaces also take TitleBar - you can turn off this at manifest

    android:theme="@android:style/Theme.NoTitleBar">

    • Changed activity orientation to landscape "beacuse camera preview support that orientation" - you can check this at API demo Graphics->CameraPreview

    • algorithm that compares the size of Display.getWidth () Camera.getParameters size (). getSupportedPreviewSizes (); if they are the same is a function of surfaceChanged change Parametrs.setPreviewSize (x, y) you received when searching the list


    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters setPrevOrientation = mCamera.getParameters();
        if (mHolder.getSurface() == null)
            return;
    
        try {
            mCamera.stopPreview();
            Size sizeBefore = mCamera.getParameters().getPreviewSize();
            setPrevOrientation.setRotation(setCameraDisplayOrientation(
                    (Activity) context, getCameraId(), mCamera));
            // Orientacja Portrait np 640x480 Landscape 480x640
            this.resolution.setPreviewSize(this.optimalPreviewSize.x,
                    this.optimalPreviewSize.y);
            mCamera.setParameters(this.resolution);
            Size sizeAfter = mCamera.getParameters().getPreviewSize();
        } catch (RuntimeException e) {
    
            L.d("Podgląd nie istnieje");
        }
    
        try {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
    
        } catch (Exception e) {
            L.d("błąd podgladu: " + e.getMessage());
        }
     } 
    

        private Point getOptimalPreviewResolution(Display displaySize) {
    
            lSuportedPreviewSize = mCamera.getParameters()
                    .getSupportedPreviewSizes();
            Point optimalPreviewSize = new Point();
            int displayWidth = displaySize.getWidth();
            int displayHeight = displaySize.getHeight();
            int cameraHeight;
            int cameraWidth;
    
            List<Point> lOptimalPoint = new ArrayList<Point>();
    
            for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
                cameraHeight = lSuportedPreviewSize.get(i).width;
                cameraWidth = lSuportedPreviewSize.get(i).height;
                if (displayHeight >= cameraHeight) {
                    lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
                }
            }
    
            // Sort ascending
            Collections.sort(lOptimalPoint,
                    new ComapreSupportedPreviewByWidth());
            // Last element is optimal
            optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size() - 1);
    
            // Return resolution - camera at landscape mode (800x600)
            return optimalPreviewSize;
        }
    

        class ComapreSupportedPreviewByWidth implements Comparator<Point> {
    
        @Override
        public int compare(Point lhs, Point rhs) {
            return lhs.x - rhs.x;
        }
    
    0 讨论(0)
  • 2020-12-11 05:55

    The camera preview always fills up the SurfaceView showing it. If the aspect ratio of m_surfaceView doesn't match with the camera's aspect ratio, the preview will be stretched.

    You'll need to create m_surfaceView matching the aspect ratio. That means, you'll need to create it from code, not from layout XML file.

    There is a sample project APIDemos that you'll find in android sample projects. In the project there is a thing named CameraPreview. This one has a good demonstration for setting up camera preview in a SurfaceView. It has a class that extends ViewGroup, and adds the SurfaceView as its child from the code. The onMeasure() method has been overridden to determine the height and width of the SurfaceView, so the aspect ratio is preserved. Take a look on the project, and I hope it will be clear.

    [Sorry I couldn't post the link here - this is supposed to be the link, but I found it broken. But if you have installed the sample projects with the Android SDK, you can find the project in the samples. Open a new Android Sample Project, select APIDemos, then look for a class named CameraPreview. It should be in the package com.example.android.apis.graphics, as far as I remember.]

    0 讨论(0)
  • 2020-12-11 05:57

    I changed onLayout method and not camera preview is not stretched. Rest of the thing are same like APiDemo which find here sdk/sample/adroid-18.The idea is we have only some supported size of preview but our view size may not always match with preview size. so i took larger preview size then my imageview size. it works for me. May help someone..

    @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) {
                    previewWidth = mPreviewSize.width;
                    previewHeight = mPreviewSize.height;
                }
    
                // Center the child SurfaceView within the parent.
                if (width * previewHeight < height * previewWidth) {
    
                    final int scaledChildWidth = previewWidth * height
                            / previewHeight;
    
                    left = (width - scaledChildWidth) / 2;
                    top = 0;
                    right = (width + scaledChildWidth) / 2;
                    bottom = height;
    
                    child.layout(left, top, right, bottom);
                } else {
                    final int scaledChildHeight = previewHeight * width
                            / previewWidth;
    
                    left = 0;
                    top = (height - scaledChildHeight) / 2;
                    right = width;
                    bottom = (height + scaledChildHeight) / 2;
    
                    child.layout(left, top, right, bottom);
                }
            }
        }
    
    0 讨论(0)
  • 2020-12-11 06:12

    I have problem with too stretching camera preview. It is too stretching at vertical and landscape mode.

    So at manifest i added screenOrentation="Portrait", but it did not help,still preview is rescaled at any position (vertical - preview is to wide or landscape is too long) you can see this at screens. I would like to add at Samsung ace III everything is fine but at LG Nexus 4 is stretching

     package pl.probs.camera.component;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Point;
    import android.hardware.Camera;
    import android.hardware.Camera.AutoFocusCallback;
    import android.hardware.Camera.CameraInfo;
    import android.hardware.Camera.Parameters;
    import android.hardware.Camera.Size;
    import android.util.Log;
    import android.view.Display;
    import android.view.MotionEvent;
    import android.view.Surface;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import pl.probs.lib.debug.L;
    
    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
        private static final String TAG = "CameraPreview";
        private static boolean showLogs = true;
        private SurfaceHolder mHolder;
        private Camera mCamera;
        private Context context;
        private Parameters resolution;
        private List<Size> lSuportedPreviewSize;
        private static int cOrientation = 0; // aktualny kat orientacji
        private static boolean cOrientationChanged = false; // Stan orientacji
                                                            // zostal zmieniony
                                                            // wzgledem poprzedniego
        private Display display; // Rozmiar ekranu
        private Point displaySize; // Zmienna przechowuje Rozmiar Ekranu
        private Point optimalPreviewSize;
    public CameraPreview(Context context, Camera camera, int resolution) {
        super(context);
        this.optimalPreviewSize = new Point();
        this.context = context;
        this.mCamera = camera;
        setDisplaySize(this.display);
        setFocusable(true);
        setFocusableInTouchMode(true);
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        this.resolution = getMinResolution(resolution);
        this.optimalPreviewSize = getOptimalPreviewResolution(this.display);
        Size s = mCamera.getParameters().getPreviewSize(); // Sprawdzenie jaki
                                                            // prewiev ustawiony
    }
    
    public Point getOptimalPreviewSize() {
        return optimalPreviewSize;
    }
    
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.setPreviewDisplay(holder);
                Size s = mCamera.getParameters().getPreviewSize();
                mCamera.startPreview();
            }
        } catch (IOException e) {
            L.d("Błąd ustawiania podglÄ…du: " + e.getMessage());
        }
    }
    
    protected void onPause() {
        // Because the Camera object is a shared resource, it's very
        // important to release it when the activity is paused.
        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
    }
    
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }
    
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters setPrevOrientation = mCamera.getParameters();
        if (mHolder.getSurface() == null)
            return;
    
        try {
            mCamera.stopPreview();
            Size sizeBefore = mCamera.getParameters().getPreviewSize();
            setPrevOrientation.setRotation(setCameraDisplayOrientation((Activity) context, getCameraId(), mCamera));
            // Orientacja Portrait np 640x480 Landscape 480x640
            this.resolution.setPreviewSize(this.optimalPreviewSize.x, this.optimalPreviewSize.y);
            mCamera.setParameters(this.resolution);
            Size sizeAfter = mCamera.getParameters().getPreviewSize();
        } catch (RuntimeException e) {
            L.d("Podgląd nie istnieje");
        }
    
        try {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
    
        } catch (Exception e) {
            L.d("błąd podgladu: " + e.getMessage());
        }
    }
    
    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mCamera.autoFocus(new AutoFocusCallback() {
    
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    // do something
                }
            });
    
        }
    
        return true;
    }
    
    private static int setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
        android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
    
        android.hardware.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;
        }
    
        cOrientation = degrees;
    
        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;
        }
    
        camera.setDisplayOrientation(result);
        return result;
    }
    
    private int getCameraId() {
        int cameraId = -1;
        int numberOfCameras = Camera.getNumberOfCameras();
        for (int i = 0; i < numberOfCameras; i++) {
            CameraInfo info = new CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
                cameraId = i;
                break;
            }
        }
        return cameraId;
    }
    
    private Parameters getMinResolution(int desireResolutionInMpx) {
        int height[], width[], size;
        float megapixels;
        Camera.Parameters p = mCamera.getParameters();
        size = p.getSupportedPictureSizes().size();
        height = new int[size];
        width = new int[size];
        for (int i = 0; i < size; i++) {
            height[i] = p.getSupportedPictureSizes().get(i).height;
            width[i] = p.getSupportedPictureSizes().get(i).width;
            megapixels = (float) (((float) height[i] * (float) width[i]) / 1024000);
            if (megapixels <= desireResolutionInMpx) {
                p.setPictureSize(width[i], height[i]);
                break;
            }
        }
        return p;
    }
    
    private Point getOptimalPreviewResolution(Display displaySize) {
        lSuportedPreviewSize = mCamera.getParameters().getSupportedPreviewSizes();
        Point optimalPreviewSize = new Point();
        int displayWidth = displaySize.getWidth(); // szerokosc ekranu
        int displayHeight = displaySize.getHeight(); // wysokosc ekranu
        int cameraHeight; // wspierana wysokosc kamery
        int cameraWidth; // wspierana szerokosc kamery
    
        // Lista przechowywujace SupportedPreviewSize kamery, wszyskie
        // rozdzielczosci mniejsze od szerokosc i wysokosci ekranu
        List<Point> lOptimalPoint = new ArrayList<Point>();
    
        // Pomocniczo do listowania zawartosci listy
        // TODO manta displayHeight cameraHeight brak oraz width brak zgodnosci
        // (
        System.out.println(lOptimalPoint.toString());
        for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
            Log.i(TAG, "w " + lSuportedPreviewSize.get(i).width + " h " + lSuportedPreviewSize.get(i).height + " \n");
        }
    
        // Wyszukanie wszystkich wysokosci kamery mniejszej od wysokosci ekranu
        for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
            // TODO Uwazaj kamera zapisuje swoj rozmiar dla pozycji landscape
            // gdzie height = 480 a width = 800
            cameraHeight = lSuportedPreviewSize.get(i).width;
            cameraWidth = lSuportedPreviewSize.get(i).height;
            // Porownaj wysokosc ekranu urzadzenia z wysokosci supportedPreview
            // dodaj do listy
            if (displayHeight > cameraHeight) {
                lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
            }
        }
    
        // Sortowanie rosnaco
        Collections.sort(lOptimalPoint, new ComapreSupportedPreviewByWidth());
        // Ostatni element listy optymalny
        optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size()-1);
    
        // Zwracana rozdzielczosc landscape aparatu np (800x600)
        return optimalPreviewSize;
    }
    
    private void setDisplaySize(Display display) {
        Activity activity = (Activity) this.context; // Pobierz aktywnosc aby
                                                        // znać rozmiar ekranu
    
        this.display = activity.getWindowManager().getDefaultDisplay();
    }
    
    class ComapreSupportedPreviewByWidth implements Comparator<Point> {
    
        @Override
        public int compare(Point lhs, Point rhs) {
            return lhs.x - rhs.x;
        }
    }
    

    }

    Link to screens and project doing at eclipse

    0 讨论(0)
提交回复
热议问题