当横屏时将相机活动旋转180度会导致相机预览倒置。

3

编辑

当从倒立竖屏旋转到任一横向方向再返回倒立竖屏时,会出现问题。我在默认相机应用上测试了这些情况,似乎没有这些问题。

结束编辑

我有一个自定义相机,在180度旋转(例如从一种横向到另一种横向)时,预览会倒置。我在代码中使用了OrientationEventListener来处理这个问题。 在setDisplayOrientation中调用mCamera.setDisplayOrientation,使用roundOrientation(orientation, orientationHistory)将方向四舍五入为0、90、180、270,并使用getDisplayRotation获取自然显示旋转。 我在initializeFirstTime中实例化监听器并启用它,在initializeSecondTime中如果从暂停状态恢复则启用它。我在onPause中禁用监听器。在onResume中调用initializeFirstTime或initializeSecondTime。

    class MyOrientationEventListener extends OrientationEventListener
{
    
    @Override
    public void onOrientationChanged(int orientation)
    {
        if(orientation==ORIENTATION_UNKNOWN)
            return;
        mOrientation=roundOrientation(orientation,0);
        int orientationCompensation=getDisplayRotation(CameraActivity.this);
        if(mOrientationCompensation!=orientationCompensation)
            mOrientationCompensation=orientationCompensation;
    }

    public MyOrientationEventListener(Context context) {
        super(context);
    }
    
    private int roundOrientation(int orientation, int orientationHistory) {
        boolean changeOrientation = false;
        final int ORIENTATION_HYSTERESIS=5;//a tolerance value above the limit
        if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
            changeOrientation = true;
        } else {
            int dist = Math.abs(orientation - orientationHistory);
            dist = Math.min(dist, 360 - dist);
            changeOrientation = (dist >= 45 +ORIENTATION_HYSTERESIS );
        }
        if (changeOrientation) {
                return ((orientation + 45) / 90 * 90) % 360;
        }
        return orientationHistory;
    }   
}

private void setDisplayOrientation()
{
    mDisplayRotation=getDisplayRotation(this);
    mDisplayOrientation=getDisplayOrientation(mDisplayRotation, CameraInfo.CAMERA_FACING_BACK);
    mCamera.setDisplayOrientation(mDisplayOrientation);
}

private int getDisplayOrientation(int degrees, int cameraId) {
    // See android.hardware.Camera.setDisplayOrientation for
    // documentation.
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    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;
}

 private int getDisplayRotation(Activity activity) {
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .getRotation();
        switch (rotation) {
            case Surface.ROTATION_0: return 0;
            case Surface.ROTATION_90: return 90;
            case Surface.ROTATION_180: return 180;
            case Surface.ROTATION_270: return 270;
        }
        return 0;
    } 

private MyOrientationEventListener mOrientationListener;
private int mOrientation=OrientationEventListener.ORIENTATION_UNKNOWN;
private int mOrientationCompensation=0;
private int mDisplayRotation;
private int mDisplayOrientation;

这两种方法用于激活OrientationEventListener:

private void initializeFirstTime()
{
    //checking if previously initialized and setting camera parameters
    mOrientationListener=new MyOrientationEventListener(CameraActivity.this);
    mOrientationListener.enable();
    mFirstTimeInitialized=true;
}

private void initializeSecondTime()
{
    mOrientationListener.enable();
}

相机预览的启动、停止和重新启动的方式如下:
  private void startPreview() throws CameraHardwareException
{
    //check if called before onPause or after onResume,
    //open the Camera if null,stop the preview,set the parameters
    setDisplayOrientation();
    try
    {
        Log.d(TAG, "Trying to start the preview");
        mCamera.startPreview();
    }
    catch(Throwable ex)
    {
        closeCamera();
        throw new RuntimeException("Could not start camera preview");
    }
    mPreviewing=true;
}

Activity生命周期方法的实现方式如下:

@Override
public void onResume()
{
    super.onResume();
    mPausing=false;
    //check condition for SurfaceHolder
    //probsbly happens if camera has paused and is resuming
    if(mStatus==PREVIEW_STOPPED)
    {
        try {
            startPreview();
        } catch (CameraHardwareException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    if(surfaceHolder!=null)
    {
        if(!mFirstTimeInitialized)
            initializeFirstTime();
        else
            initializeSecondTime();
    }
    keepScreenOnAwhile();
    if(mStatus==CAMERA_IDLE)
    {
        mResumeTime=SystemClock.uptimeMillis();
        handler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
    }
}

@Override
public void onPause()
{
    mPausing=true;
    stopPreview();
    closeCamera();
    resetScreenOn();
    if(mFirstTimeInitialized)
        mOrientationListener.disable();
    handler.removeMessages(FIRST_TIME_INIT);
    handler.removeMessages(CLEAR_SCREEN_DELAY);
    super.onPause();
}

这里已经实现了SurfaceHolder.Callbacks方法:

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if(holder.getSurface()==null)
    {   
        Log.d(TAG, "holder.getSurface()=null");
        return;
    }
    //stash the holder here for later use,useful if onResume needs to be invoked after this.
    surfaceHolder=holder;
    if(mCamera==null)
        return;
    //sometimes surfaceChanged is called after onPause or before onResume,ignore it
    if(mPausing || isFinishing())
        return;
    if(mStatus==PREVIEW_STOPPED)
        try {
            startPreview();
        } catch (CameraHardwareException e1) {
            Log.e(TAG, "Error starting the preview");
        }
    if(!mPreviewing)
        try {
            startPreview();
        } catch (CameraHardwareException e) {
            Log.e(TAG,"Could not get the camera");
        }
    
    if(!mFirstTimeInitialized)
        if(getDisplayRotation(this)!=mDisplayOrientation)
            setDisplayOrientation();
    if(mPreviewing && holder.isCreating())
    {
        setPreviewDisplay(holder);
    }
    if(!mFirstTimeInitialized)
        handler.sendEmptyMessage(FIRST_TIME_INIT);
    else
        initializeSecondTime();
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    //nothing here
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    stopPreview();
    surfaceHolder=null;
}

在 onResume 和 surfaceChanged 中启用方向事件监听器,哪一个先调用就先执行,并在 onPause 中禁用。OrientationEventListener 只在 initializeFirstTime 中实例化。

编辑:

这是因为我没有正确启用 OrientationEventListener 吗?同时,我是否正确设置了影响图像旋转的参数旋转:

  mParameters.setRotation(rotation);

你有检查过 https://dev59.com/7HjZa4cB1Zd3GeqPcEh1#19599599 吗? - Alex Cohn
因为默认的相机应用程序锁定屏幕方向为横向(自然相机方向),所以它似乎没有这些问题。如果我理解正确,您的活动设置为android:screenOrientation=fullSensor - Alex Cohn
是的,我正在使用 android:screenOrientation=fullSensor已尝试通过 SurfaceHolder.Callbacks 进行更改 - vamsiampolu
@AlexCohnوˆ‘هœ¨layout-landن¸­و²،وœ‰و·»هٹ ن»»ن½•ه¸ƒه±€و–‡ن»¶ç»™CameraActivity,è؟™ن¼ڑوœ‰ن»€ن¹ˆه½±ه“چهگ—ï¼ں - vamsiampolu
首先,如果您的目标是旧版Android,则可能会遇到反向横向的问题。但更有可能的是,您面临的是Android的限制,即在设备快速旋转180度时不报告方向变化,并且不重新启动布局。我相信您的情况类似于_https://dev59.com/questions/7HjZa4cB1Zd3GeqPcEh1。 - Alex Cohn
显示剩余2条评论
1个回答

1

当表面创建时调用此函数

 private void setUpCamera(Camera c) {

    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    rotation = getWindowManager().getDefaultDisplay().getRotation();
    int degree = 0;
    switch (rotation) {
        case Surface.ROTATION_0:
            degree = 0;
            break;
        case Surface.ROTATION_90:
            degree = 90;
            break;
        case Surface.ROTATION_180:
            degree = 180;
            break;
        case Surface.ROTATION_270:
            degree = 270;
            break;

        default:

            break;
    }

    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        // frontFacing
        rotation = (info.orientation + degree) % 360;
        rotation = (360 - rotation) % 360;
    }
    else {
        // Back-facing
        rotation = (info.orientation - degree + 360) % 360;
    }


    c.setDisplayOrientation(rotation);




    params.setRotation(rotation);
    camera.setParameters(params);


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接