vamsiampolu
vamsiampolu

Reputation: 6642

Rotating the Camera Activity 180 degrees when in landscape causes inverted camera preview

EDIT

Also an issue when rotating from upside down portrait to one of the landscape orientations and back from there to the upside down portrait orientation.I have tested these cases on the default Camera application and it does not seem to have any of these problems.

END EDIT

I have a custom camera which when rotated by 180 degrees say from one landscape to another shows an inverted preview.I have used an OrientationEventListener in my code like this. mCamera.setDisplayOrientation is called in setDisplayOrientation,I am rounding the orientation to 0,90,180,270 using roundOrientation(orientation,orientationHistory) and I get the natural display rotation using getDisplayRotation.I instantiate the listener in initializeFirstTime and enable it initializeFirstTime and if resuming from a paused state from initializeSecondTime.I disable the listener in onPause.I call initializeFirstTime or initializeSecondTime in onResume. :

    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;

These two methods are used to activate the 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();
}

The Camera Preview is started,stopeed and restarted like this:

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

The Activity lifecycle methods have been implemented like this:

@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();
}

The SurfaceHolder.Callbacks methods have been implemented here:

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

The orientation event listener is enabled in onResume and surfaceChanged whichever gets called fastest I guess and is then disabled in onPause.The OrientationEventListener is only instantiated in initializeFirstTime.

EDIT:

Is this happening because I did not enable the OrientationEventListener correctly.Also did I set the rotation for parameters which affects image rotation correctly:

  mParameters.setRotation(rotation);

Upvotes: 3

Views: 3396

Answers (1)

KD_
KD_

Reputation: 31

Call this when surface is created

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


}

Upvotes: 1

Related Questions