簡體   English   中英

如果手機處於橫向模式,則Android相機預覽方向不正確

[英]Android camera preview orientation is incorrect if the phone is held in landscape mode

我在這里找到了很多關於android相機預覽定位問題的問題。 所有修復涉及將屏幕方向固定為橫向或調用camera.setDisplayOrientation(90)或調用params.setRotation(90)。 我無法找到實際上使其在橫向方向上工作時的設置組合。

使用android:screenOrientation =“landscape”將活動固定為橫向模式。

我的問題是,如果我以縱向方向拿着相機並啟動應用程序它工作正常(我的意思是它正確顯示圖像為景觀)。 如果我在啟動應用程序時將相機保持在橫向方向,則圖像全部搞砸(有點隔行掃描)。 如果我使用camera.setDisplayOrientation(90); 圖片不再混亂,但圖像側向定向。

奇怪的是,如果我刪除android:screenOrientation =“landscape”並允許屏幕旋轉,我仍然有同樣的問題,但如果我將手機旋轉為肖像,它在縱向看起來很好。 如果我將它旋轉回景觀,那么它在景觀中看起來很好! 我唯一的問題是它首次啟動時無法正常工作。

import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.Log;
import android.view.*;


public class CameraView extends SurfaceView
{    
    //Callback for the surfaceholder
    SurfaceHolder.Callback surfaceHolderListener = new SurfaceHolder.Callback() {
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                camera=Camera.open();
            } catch(Exception e) {
                Log.e("CameraView","Couldn't open the camera.",e);
            }
            try {
                camera.setPreviewDisplay(previewHolder);
            } catch (Throwable e) {
                Log.e("CameraView","Couldn't call setPreviewDisplay.",e);
            }
        }

        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
            if(camera!=null) {
                Parameters params = camera.getParameters();

                List<Size> sizes = params.getSupportedPreviewSizes();
                Size optimalSize = getOptimalPreviewSize(sizes, w, h);
                params.setPreviewSize(optimalSize.width, optimalSize.height);

                camera.setParameters(params);
                camera.startPreview();
            }
        }

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

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

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

            int targetHeight = h;

            // Try to find an size match aspect ratio and size
            for (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 (Size size : sizes) {
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
            }
            return optimalSize;
        }
    };


    public CameraView(Context ctx) {
        super(ctx);

        previewHolder = this.getHolder();
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        previewHolder.addCallback(surfaceHolderListener);
        setBackgroundColor(Color.TRANSPARENT);
    }

    public CameraView(Context ctx, AttributeSet attrs) {
        super(ctx, attrs);
    }

    private Camera camera;
    private SurfaceHolder previewHolder;
}

編輯:真正的問題似乎是在surfaceChanged之后發生的事情搞砸了。 我發現如果我啟動相機預覽,然后在surfaceChanged的末尾添加一個調試點,相機看起來很好。 然后,如果我向前邁出大約20步,它突然看起來搞砸了。

我通過使用方向更改偵聽器一次更新方向然后禁用自身來解決這個問題(以我認為完全破解的方式)。 我只需要在最初設置視圖后激活的東西。 我可能已經在其他地方做過了。

如果有人知道如何解決這個問題而不是完全愚蠢,請幫忙!

/** This works fine for me, but it's a hack. */

import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraView3
    extends SurfaceView
{
    private static Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.05;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

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

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (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 (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }


    private class CameraSurfaceHolder
        extends OrientationEventListener
        implements SurfaceHolder.Callback
    {
        CameraSurfaceHolder(Context ctx) {
            super(ctx);
        }

        public void surfaceCreated(SurfaceHolder holder) {
            try {
                camera= Camera.open();
            } catch(Exception e) {
                Log.e("CameraView","Couldn't open the camera.",e);
            }
            try {
                camera.setPreviewDisplay(previewHolder);
            } catch (Throwable e) {
                Log.e("CameraView","Couldn't call setPreviewDisplay.",e);
            }
        }

        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
        }

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

        @Override
        public void onOrientationChanged(int orientation) {
            if(camera!=null) {
                DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
                camera.stopPreview();
                CameraView3.this.layout(0, 0, dm.widthPixels-1, dm.heightPixels-1);
                camera.startPreview();
                disable();
                return;
            }
        }
    }


    public CameraView3(Context ctx) {
        super(ctx);
        this.ctx = ctx;

        previewHolder = this.getHolder();
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceHolderListener = new CameraSurfaceHolder(ctx);
        previewHolder.addCallback(surfaceHolderListener);
        surfaceHolderListener.enable();

        setBackgroundColor(Color.TRANSPARENT);
    }

    private Context ctx;
    private Camera camera;
    private SurfaceHolder previewHolder;
    private CameraSurfaceHolder surfaceHolderListener;
    private Size optimalSize;
}

總之,我發布的第一個版本在我的Nexus One上運行良好。 但是,它不適用於我的Skyrocket。 我需要使用第二個版本才能在那里工作。

奇怪的是,如果我刪除android:screenOrientation =“landscape”並允許屏幕旋轉,我仍然有同樣的問題,但如果我將手機旋轉為肖像,它在縱向看起來很好。

首先請注意,相機預覽方向與活動方向無關。 兩者都不同。 當您更改設備方向時,您必須調用camera.setDisplayOrientation根據方向設置預覽的方向。

您必須以度為單位設置此方向。 這可以通過在相機視圖中設置OrientationEventListener來獲得。 onOrientationChanged(int orientation) ,您將獲得設備的精確旋轉角度(以度為單位)。

不要忘記計算旋轉,因為即使設備方向的角度變化很小,也會調用API onOrientationChanged(int orientation) 您可以將此問題視為參考。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM