Android 相机在Nexus设备中倒置

Android 相机在Nexus设备中倒置,android,camera,Android,Camera,我正在尝试创建适用于所有场景的自定义相机预览逻辑: any device: phone, tablet any camera: front-facing, rear-facing android.hardware.Camera 我的android:minSdkVersion是14和android:targetSdkVersion是21。 我已经实现了自定义的camera preview类来为camera preview设置显示方向,并且在没有Nexus设备的所有设备上都能很好地工作。我认为Ne

我正在尝试创建适用于所有场景的自定义相机预览逻辑:

any device: phone, tablet
any camera: front-facing, rear-facing
android.hardware.Camera
我的
android:minSdkVersion
14
android:targetSdkVersion
21
。 我已经实现了自定义的camera preview类来为camera preview设置显示方向,并且在没有Nexus设备的所有设备上都能很好地工作。我认为Nexus设备有默认的
180
方向

当我在Nexus设备中启动相机时,它显示的是反转的。为了克服这个问题,我已经检查了
Build.MANUFACTURER
Build.MODEL
来识别设备并根据它设置方向

 if (Build.MODEL.equals("Nexus 6P") && Build.MANUFACTURER.equals("Huawei")) mCamera.setDisplayOrientation(90);
        else mCamera.setDisplayOrientation(270);

但它不起作用。所以,任何人都可以用这个和推荐的方法来克服!!如果您能提前提供帮助,我们将不胜感激

在活动中启动:

 CameraPreviewNew mPreview = new ResizableCameraPreview(this, cameraId, CameraPreviewNew.LayoutMode.NoBlank, false, screenHeight, screenWidth); // cameraId for front or rear
        LinearLayout.LayoutParams previewLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        frameCamera.addView(mPreview, 0, previewLayoutParams);
CameraPreviewNew.java

public class CameraPreviewNew extends SurfaceView implements SurfaceHolder.Callback {
    private static boolean DEBUGGING = false;
    private static final String LOG_TAG = "CameraPreviewSample";
    private static final String CAMERA_PARAM_ORIENTATION = "orientation";
    private static final String CAMERA_PARAM_LANDSCAPE = "landscape";
    private static final String CAMERA_PARAM_PORTRAIT = "portrait";
    protected Activity mActivity;
    private SurfaceHolder mHolder;
    protected Camera mCamera;
    protected List<Camera.Size> mPreviewSizeList;
    protected List<Camera.Size> mPictureSizeList;
    protected Camera.Size mPreviewSize;
    protected Camera.Size mPictureSize;
    private int mSurfaceChangedCallDepth = 0;
    private int mCameraId;
    private LayoutMode mLayoutMode;
    private int mCenterPosX = -1;
    private int mCenterPosY;
    private int screenHeight, screenWidth;

    PreviewReadyCallback mPreviewReadyCallback = null;

    public enum LayoutMode {
        FitToParent, // Scale to the size that no side is larger than the parent
        NoBlank // Scale to the size that no side is smaller than the parent
    }

    public interface PreviewReadyCallback {
        void onPreviewReady();
    }

    /**
     * State flag: true when surface's layout size is set and surfaceChanged()
     * process has not been completed.
     */
    protected boolean mSurfaceConfiguring = false;

    public CameraPreviewNew(Activity activity, int cameraId, LayoutMode mode, int screenHeight,  int screenWidth) {
        super(activity); // Always necessary
        mActivity = activity;
        mLayoutMode = mode;
        this.screenHeight = screenHeight;
        this.screenWidth = screenWidth;
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//        mHolder.setFixedSize(fixWidth, fixHeight);

//        FileLog.v("Camera ID ::::::::::: " + cameraId);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            if (Camera.getNumberOfCameras() > cameraId) {
                mCameraId = cameraId;
            } else {
                mCameraId = 0;
            }
        } else {
            mCameraId = 0;
        }
//        FileLog.d("Camera ID ::::::::::: " + cameraId);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            mCamera = Camera.open(mCameraId);
        } else {
            mCamera = Camera.open();
        }
        Camera.Parameters cameraParams = mCamera.getParameters();
        mPreviewSizeList = cameraParams.getSupportedPreviewSizes();
        mPictureSizeList = cameraParams.getSupportedPictureSizes();

//        FileLog.d("Preview Size ID ::::::::::: " + mPreviewSizeList);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCamera.setPreviewDisplay(mHolder);
        } catch (IOException e) {
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mSurfaceChangedCallDepth++;
        doSurfaceChanged(width, height);
        mSurfaceChangedCallDepth--;
    }

    public void doSurfaceChanged(int width, int height) {
        mCamera.stopPreview();

        Camera.Parameters cameraParams = mCamera.getParameters();
        boolean portrait = isPortrait();

        // The code in this if-statement is prevented from executed again when surfaceChanged is
        // called again due to the change of the layout size in this if-statement.
        if (!mSurfaceConfiguring) {
            Camera.Size previewSize = determinePreviewSize(portrait, width, height);
            Camera.Size pictureSize = determinePictureSize(previewSize);
            if (DEBUGGING) { Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height); }
            mPreviewSize = previewSize;
            mPictureSize = pictureSize;
            mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
            // Continue executing this method if this method is called recursively.
            // Recursive call of surfaceChanged is very special case, which is a path from
            // the catch clause at the end of this method.
            // The later part of this method should be executed as well in the recursive
            // invocation of this method, because the layout change made in this recursive
            // call will not trigger another invocation of this method.
            if (mSurfaceConfiguring && (mSurfaceChangedCallDepth <= 1)) {
                return;
            }
        }

        configureCameraParameters(cameraParams, portrait);
        mSurfaceConfiguring = false;

        try {
            mCamera.startPreview();
        } catch (Exception e) {
            Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage());

            // Remove failed size
            mPreviewSizeList.remove(mPreviewSize);
            mPreviewSize = null;

            // Reconfigure
            if (mPreviewSizeList.size() > 0) { // prevent infinite loop
                surfaceChanged(null, 0, width, height);
            } else {
                Log.w(LOG_TAG, "Gave up starting preview");
            }
        }

        if (null != mPreviewReadyCallback) {
            mPreviewReadyCallback.onPreviewReady();
        }
    }

    /**
     * @param portrait
     * @param reqWidth must be the value of the parameter passed in surfaceChanged
     * @param reqHeight must be the value of the parameter passed in surfaceChanged
     * @return Camera.Size object that is an element of the list returned from Camera.Parameters.getSupportedPreviewSizes.
     */
    protected Camera.Size determinePreviewSize(boolean portrait, int reqWidth, int reqHeight) {
        // Meaning of width and height is switched for preview when portrait,
        // while it is the same as user's view for surface and metrics.
        // That is, width must always be larger than height for setPreviewSize.
        int reqPreviewWidth; // requested width in terms of camera hardware
        int reqPreviewHeight; // requested height in terms of camera hardware
        if (portrait) {
            reqPreviewWidth = reqHeight;
            reqPreviewHeight = reqWidth;
        } else {
            reqPreviewWidth = reqWidth;
            reqPreviewHeight = reqHeight;
        }

        if (DEBUGGING) {
            Log.v(LOG_TAG, "Listing all supported preview sizes");
            for (Camera.Size size : mPreviewSizeList) {
                Log.v(LOG_TAG, "  w: " + size.width + ", h: " + size.height);
            }
            Log.v(LOG_TAG, "Listing all supported picture sizes");
            for (Camera.Size size : mPictureSizeList) {
                Log.v(LOG_TAG, "  w: " + size.width + ", h: " + size.height);
            }
        }

        // Adjust surface size with the closest aspect-ratio
        float reqRatio = ((float) reqPreviewWidth) / reqPreviewHeight;
        float curRatio, deltaRatio;
        float deltaRatioMin = Float.MAX_VALUE;
        Camera.Size retSize = null;
        for (Camera.Size size : mPreviewSizeList) {
            curRatio = ((float) size.width) / size.height;
            deltaRatio = Math.abs(reqRatio - curRatio);
            if (deltaRatio < deltaRatioMin) {
                deltaRatioMin = deltaRatio;
                retSize = size;
            }
        }

        retSize = mPreviewSizeList.get(0);

        return retSize;
    }

    protected Camera.Size determinePictureSize(Camera.Size previewSize) {
        Camera.Size retSize = null;
        for (Camera.Size size : mPictureSizeList) {
            if (size.equals(previewSize)) {
                return size;
            }
        }

        if (DEBUGGING) { Log.v(LOG_TAG, "Same picture size not found."); }

        // if the preview size is not supported as a picture size
        float reqRatio = ((float) previewSize.width) / previewSize.height;
        float curRatio, deltaRatio;
        float deltaRatioMin = Float.MAX_VALUE;
        for (Camera.Size size : mPictureSizeList) {
            curRatio = ((float) size.width) / size.height;
            deltaRatio = Math.abs(reqRatio - curRatio);
            if (deltaRatio < deltaRatioMin) {
                deltaRatioMin = deltaRatio;
                retSize = size;
            }
        }

        retSize = mPictureSizeList.get(0);

        return retSize;
    }

    protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize, boolean portrait,
                                              int availableWidth, int availableHeight) {
        float tmpLayoutHeight, tmpLayoutWidth;
        if (portrait) {
            tmpLayoutHeight = previewSize.width;
            tmpLayoutWidth = previewSize.height;
        } else {
            tmpLayoutHeight = previewSize.height;
            tmpLayoutWidth = previewSize.width;
        }

        float factH, factW, fact;
        factH = availableHeight / tmpLayoutHeight;
        factW = availableWidth / tmpLayoutWidth;
        if (mLayoutMode == LayoutMode.FitToParent) {
            // Select smaller factor, because the surface cannot be set to the size larger than display metrics.
            if (factH < factW) {
                fact = factH;
            } else {
                fact = factW;
            }
        } else {
            if (factH < factW) {
                fact = factW;
            } else {
                fact = factH;
            }
        }

        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)this.getLayoutParams();

        int layoutHeight = (int) (tmpLayoutHeight * fact);
        int layoutWidth = (int) (tmpLayoutWidth * fact);
        if (DEBUGGING) {
            Log.v(LOG_TAG, "Preview Layout Size - w: " + layoutWidth + ", h: " + layoutHeight);
            Log.v(LOG_TAG, "Scale factor: " + fact);
        }

        boolean layoutChanged;
        if ((layoutWidth != this.getWidth()) || (layoutHeight != this.getHeight())) {
            int diffHeight = (screenHeight - layoutHeight) / 2;
            layoutParams.height = layoutHeight + diffHeight;
            int diffWidth = (screenWidth - layoutWidth) / 2;
            layoutParams.width = layoutWidth + diffWidth;
            if (mCenterPosX >= 0) {
                layoutParams.topMargin = mCenterPosY - (layoutHeight / 2);
                layoutParams.leftMargin = mCenterPosX - (layoutWidth / 2);
            }
            this.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation.
            layoutChanged = true;
        } else {
            layoutChanged = false;
        }

        return layoutChanged;
    }

    /**
     * @param x X coordinate of center position on the screen. Set to negative value to unset.
     * @param y Y coordinate of center position on the screen.
     */
    public void setCenterPosition(int x, int y) {
        mCenterPosX = x;
        mCenterPosY = y;
    }

    protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before
            if (portrait) {
                cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
            } else {
                cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
            }
        } else { // for 2.2 and later
            int angle;
            Display display = mActivity.getWindowManager().getDefaultDisplay();
            switch (display.getRotation()) {
                case Surface.ROTATION_0: // This is display orientation
                    angle = 90; // This is camera orientation
                    break;
                case Surface.ROTATION_90:
                    angle = 0;
                    break;
                case Surface.ROTATION_180:
                    angle = 270;
                    break;
                case Surface.ROTATION_270:
                    angle = 180;
                    break;
                default:
                    angle = 90;
                    break;
            }
            Log.v(LOG_TAG, "angle: " + angle);
            mCamera.setDisplayOrientation(angle);
        }

        cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
        cameraParams.setZoom(0);

//        if (cameraParams.isZoomSupported()) {
            final int maxZoomLevel = cameraParams.getMaxZoom();
            Log.e("max ZOOM ", "is " + maxZoomLevel);
//        }
//        cameraParams.setPreviewSize(fixWidth, fixHeight);
//        cameraParams.setPictureSize(fixWidth, fixHeight);
        if (DEBUGGING) {
            Log.v(LOG_TAG, "Preview Actual Size - w: " + mPreviewSize.width + ", h: " + mPreviewSize.height);
            Log.v(LOG_TAG, "Picture Actual Size - w: " + mPictureSize.width + ", h: " + mPictureSize.height);
        }

        mCamera.setParameters(cameraParams);
    }

    @SuppressWarnings("unused")
    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.2;
        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) {
            Log.d("Camera", "Checking size " + size.width + "w " + size.height
                    + "h");
            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;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        stop();
    }

    public void stop() {
        try {
            if (null == mCamera) {
                return;
            }
            if(mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public boolean isPortrait() {
        return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
    }

    public void setOneShotPreviewCallback(PreviewCallback callback) {
        if (null == mCamera) {
            return;
        }
        mCamera.setOneShotPreviewCallback(callback);
    }

    public void setPreviewCallback(PreviewCallback callback) {
        if (null == mCamera) {
            return;
        }
        mCamera.setPreviewCallback(callback);
    }

    public Camera.Size getPreviewSize() {
        return mPreviewSize;
    }

    public void setOnPreviewReady(PreviewReadyCallback cb) {
        mPreviewReadyCallback = cb;
    }

    public Camera getPreviewCamera() {
        return mCamera;
    }
}
公共类CameraPreviewEW扩展了SurfaceView实现了SurfaceHolder.Callback{
私有静态布尔调试=false;
私有静态最终字符串日志\u TAG=“CameraPreviewSample”;
专用静态最终字符串摄影机参数方向=“方向”;
专用静态最终字符串CAMERA_PARAM_横向=“横向”;
专用静态最终字符串照相机参数纵向=“纵向”;
保护活性;
私人地勤人员;
受保护的摄像机mCamera;
受保护列表mPreviewSizeList;
受保护列表;
受保护的摄像头。大小mPreviewSize;
受保护的摄像头。大小和大小;
private int mSurfaceChangedCallDepth=0;
麦卡默雷德私人酒店;
私人布局模式mLayoutMode;
私有int-mCenterPosX=-1;
私营企业;
私有int屏幕高度、屏幕宽度;
PreviewerAyCallback MPReviewerAyCallback=null;
公共枚举布局模式{
FitToParent,//缩放到没有边大于父边的大小
NoBlank//缩放到没有边小于父边的大小
}
公共接口预览和回调{
void onprevieweray();
}
/**
*状态标志:当设置了曲面的布局大小并且surfaceChanged()时为true
*该过程尚未完成。
*/
受保护的布尔值mSurfaceConfiguring=false;
公共CameraPreviewEW(活动活动、内部cameraId、布局模式、内部屏幕高度、内部屏幕宽度){
超级(活动);//总是必要的
活动性=活动性;
mLayoutMode=模式;
this.screenHeight=屏幕高度;
this.screenWidth=屏幕宽度;
mHolder=getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE\u TYPE\u PUSH\u缓冲区);
//mHolder.setFixedSize(固定宽度、固定高度);
//FileLog.v(“摄像机ID:::::::”+cameraId);
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.gingerbrand){
if(Camera.getNumberOfCameras()>camerRAID){
mCameraId=cameraId;
}否则{
mCameraId=0;
}
}否则{
mCameraId=0;
}
//FileLog.d(“摄像机ID::::::”+cameraId);
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.gingerbrand){
mCamera=Camera.open(mCameraId);
}否则{
mCamera=Camera.open();
}
Camera.Parameters cameraParams=mCamera.getParameters();
MPReviewIzeList=cameraParams.getSupportedPreviewSizes();
mpicuteResizeList=cameraParams.getSupportedPictureSizes();
//FileLog.d(“预览大小ID:::::”+mPreviewSizeList);
}
@凌驾
已创建的公共空白表面(表面持有人){
试一试{
mCamera.setPreviewDisplay(mHolder);
}捕获(IOE异常){
mCamera.release();
mCamera=null;
}
}
@凌驾
公共空白表面更改(表面文件夹持有者、整型格式、整型宽度、整型高度){
mSurfaceChangedCallDepth++;
doSurfaceChanged(宽度、高度);
mSurfaceChangedCallDepth--;
}
已更改公共空心面(整型宽度、整型高度){
mCamera.stopPreview();
Camera.Parameters cameraParams=mCamera.getParameters();
布尔纵向=isPortrait();
//当SURFACHECHANGE被禁用时,将阻止再次执行此if语句中的代码
//由于此if语句中布局大小的更改而再次调用。
如果(!mSurfaceConfiguring){
Camera.Size previewSize=确定预览大小(纵向、宽度、高度);
Camera.Size pictureSize=确定图像大小(previewSize);
if(调试){Log.v(Log_标记,“所需预览大小-w:+width+”,h:+height);}
mPreviewSize=预览大小;
mPictureSize=图片大小化;
msurfaceconfiguration=调整surfacelayoutsize(预览大小、纵向、宽度、高度);
//如果递归调用此方法,则继续执行此方法。
//surfaceChanged的递归调用是非常特殊的情况,它是来自
//此方法末尾的catch子句。
//该方法的后面部分也应该在递归过程中执行
//调用此方法,因为布局更改在此递归
//调用将不会触发此方法的另一次调用。
if(mSurfaceConfiguring&&(mSurfaceChangedCallDepth 0){//防止无限循环
表面更改(空、0、宽度、高度);
}否则{
w(Log_标签,“放弃启动预览”);
}
}
if(null!=mprevieweradycallback){
mPreviewReadyCallback.onPreviewReady();
}
}
/**
*@param肖像
*@param reqWidth必须是在surfaceChanged中传递的参数的值
*@param reqHeight必须为该值
public class ResizableCameraPreview extends CameraPreviewNew {
    private static boolean DEBUGGING = false;
    private static final String LOG_TAG = "ResizableCameraPreviewSample";

    /**
     * @param activity
     * @param addReversedSizes is set to true to add reversed values of supported preview-sizes to the list.
     */
    public ResizableCameraPreview(Activity activity, int cameraId, LayoutMode mode, boolean addReversedSizes, int screenHeight, int screenWidth) {
        super(activity, cameraId, mode, screenHeight, screenWidth);
        if (addReversedSizes) {            
            List<Camera.Size> sizes = mPreviewSizeList;
            int length = sizes.size();
            for (int i = 0; i < length; i++) {
                Camera.Size size = sizes.get(i);
                Camera.Size revSize = mCamera.new Size(size.height, size.width);
                sizes.add(revSize);
            }
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mCamera.stopPreview();

        Camera.Parameters cameraParams = mCamera.getParameters();
        boolean portrait = isPortrait();

        if (!mSurfaceConfiguring) {
            Camera.Size previewSize = determinePreviewSize(portrait, width, height);
            Camera.Size pictureSize = determinePictureSize(previewSize);
            Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height);
            mPreviewSize = previewSize;
            mPictureSize = pictureSize;
            mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
            if (mSurfaceConfiguring) {
                return;
            }
        }

        configureCameraParameters(cameraParams, portrait);
        mSurfaceConfiguring = false;

        try {
            mCamera.startPreview();
        } catch (Exception e) {
            Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage());
        }
    }

    /**
     * 
     * @param index selects preview size from the list returned by CameraPreview.getSupportedPreivewSizes().
     * @param width is the width of the available area for this view
     * @param height is the height of the available area for this view
     */
    public void setPreviewSize(int index, int width, int height) {
        mCamera.stopPreview();

        Camera.Parameters cameraParams = mCamera.getParameters();
        boolean portrait = isPortrait();

        Camera.Size previewSize = mPreviewSizeList.get(index);
        Camera.Size pictureSize = determinePictureSize(previewSize);
        if (DEBUGGING) { Log.v(LOG_TAG, "Requested Preview Size - w: " + previewSize.width + ", h: " + previewSize.height); }
        mPreviewSize = previewSize;
        mPictureSize = pictureSize;
        boolean layoutChanged = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
        if (layoutChanged) {
            mSurfaceConfiguring = true;
            return;
        }

        configureCameraParameters(cameraParams, portrait);
        try {
            mCamera.startPreview();
        } catch (Exception e) {
        }
        mSurfaceConfiguring = false;
    }

    public List<Camera.Size> getSupportedPreivewSizes() {
        return mPreviewSizeList;
    }
}
 <FrameLayout
    android:id="@+id/frm"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <LinearLayout
        android:id="@+id/frameCamera"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    </LinearLayout>
</FrameLayout>
 public CameraPreview(Context context, int screenRotation, Camera camera) {
    super(context);
    mCamera = camera;
    mScreenRotation = screenRotation;
    mHolder = getHolder();
    mHolder.addCallback(this);
    setFocusable(true);
    setFocusableInTouchMode(true);
}
 public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera.setPreviewDisplay(holder);
        setCameraDisplayOrientation(mScreenRotation, 0, mCamera);
public void setCameraDisplayOrientation(int screenRotation, int cameraId, Camera camera) {
    int rotation = getRotationAngle(screenRotation, cameraId);
    camera.setDisplayOrientation(rotation);
}

public static int getRotationAngle(int screenRotation, int cameraId) {
    Camera.CameraInfo info = new Camera.CameraInfo();
    android.hardware.Camera.getCameraInfo(cameraId, info);
    int degrees = 0;
    switch (screenRotation) {
        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;
}