Portrait mode in CameraView

774 views Asked by At

I'm going to develop an android application using BeyondAR framework. I try to use a CameraView component at the first half of the screen (app running only in portrait mode), but when i rotate camera 90 degrees image stretches and aspect ratio is wrong.Any help?

CameraView class (Beyondar framework)

public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
    Camera.PictureCallback {

/**
 * 
 * @author Joan Puig Sanz ([email protected])
 * 
 */
public static interface IPictureCallback {
    /**
     * This method is called when the snapshot of the camera is ready. If
     * there is an error, the image will be null
     * 
     * @param picture
     */
    void onPictureTaken(Bitmap picture);
}

private SurfaceHolder mHolder;
private Camera mCamera;
private IPictureCallback mCameraCallback;
private BitmapFactory.Options mOptions;

private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private List<String> mSupportedFlashModes;

public CameraView(Context context) {
    super(context);
    init(context);
}

public CameraView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

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

private void init(Context context) {
    mHolder = getHolder();
    mHolder.addCallback(this);

    try {
        mCamera = Camera.open();
        //mCamera.setDisplayOrientation(90);


        //Camera.Parameters params = mCamera.getParameters();
        //params.setPreviewSize(427, 1240); 
        //mCamera.setParameters(params);
        setCamera(mCamera);
    } catch (Exception e) {
        Log.e(Constants.TAG, "ERROR: Unable to open the camera", e);
    }

    if (android.os.Build.VERSION.SDK_INT <= 10) {// Android 2.3.x or lower
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
}

public void setCamera(Camera camera) {
    mCamera = camera;
    if (mCamera != null) {
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
        // Set the camera to Auto Flash mode.
        if (mSupportedFlashModes != null
                && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
            //parameters.setPreviewSize(300, 200);
            mCamera.setParameters(parameters);
        }
    }
}

public void setSupportedPreviewSizes(List<Size> supportedPreviewSizes) {
    mSupportedPreviewSizes = supportedPreviewSizes;
}

public Size getPreviewSize() {
    return mPreviewSize;
}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, acquire the camera and tell it where
    // to draw.
    try {

        if (mCamera == null) {
            init(getContext());
            if (mCamera == null) {
                return;
            }
        }

        mCamera.setPreviewDisplay(holder);
    } catch (IOException exception) {
        if (mCamera != null) {
            mCamera.release();
        }
        mCamera = null;
        Log.e(Constants.TAG, "CameraView -- ERROR en SurfaceCreated", exception);
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // Surface will be destroyed when we return, so stop the preview.
    // Because the CameraDevice object is not a shared resource, it's very
    // important to release it when the activity is paused.
    if (mCamera == null) {
        return;
    }
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    setMeasuredDimension(width, height);

    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

private Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {

    Size result = null;

    for (Camera.Size size : sizes) {
        if (size.width <= width && size.height <= height) {
            if (result == null) {
                result = size;
            } else {
                int resultArea = result.width * result.height;
                int newArea = size.width * size.height;

                if (newArea > resultArea) {
                    result = size;
                }
            }
        }
    }

    return result;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (mCamera == null || getPreviewSize() == null) {
        return;
    }

    Camera.Parameters parameters = mCamera.getParameters();
    Size previewSize = getPreviewSize();
    parameters.setPreviewSize(previewSize.width, previewSize.height);

    mCamera.setParameters(parameters);
    previewCamera();

}

@Override
public void onPictureTaken(byte[] imageData, Camera camera) {
    if (imageData != null && mCameraCallback != null) {
        mCameraCallback.onPictureTaken(StoreByteImage(imageData));
    }
    previewCamera();
}

public void previewCamera() {
    if (mCamera == null){
        return;
    }
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        Log.d(Constants.TAG, "Cannot start preview.", e);
    }
}

private Bitmap StoreByteImage(byte[] imageData) {

    Bitmap myImage = DebugBitmap.decodeByteArray(imageData, 0, imageData.length, mOptions);

    imageData = null;
    System.gc();

    return myImage;
}

public void tackePicture(IPictureCallback cameraCallback) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    tackePicture(cameraCallback, options);
}

public void tackePicture(IPictureCallback cameraCallback, BitmapFactory.Options options) {
    if (mCamera == null) {
        return;
    }
    mCameraCallback = cameraCallback;
    mCamera.takePicture(null, this, this);
    mOptions = options;
}


}

Edit

MyLayout xml file

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="0dip"
    android:layout_weight="1"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/padding"
    android:paddingLeft="@dimen/padding"
    android:paddingRight="@dimen/padding"
    android:paddingTop="@dimen/padding" >  

    <FrameLayout 
   android:orientation="vertical"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   >
    <com.beyondar.android.opengl.views.BeyondarGLSurfaceView
    android:id="@+id/customGLSurface"
    android:layout_width="match_parent" 
    android:layout_height="match_parent" />    
    <com.beyondar.android.views.CameraView 
    android:id="@+id/camera"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" />

<TextView  
    android:id="@+id/labelText"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="Touch an AR Object"
    android:background="#000000"
    android:textColor="#FFFFFF"
    />


    </FrameLayout>
   </LinearLayout
2

There are 2 answers

3
Turnsole On

If you look at the example application for BeyondAR, you can see that it has a similar problem in that the camera's image gets stretched to fill the screen and so doesn't have the proper aspect ratio in both landscape in portrait. This is a common problem when working with the camera preview since it locks to a particular orientation when you first start it.

In order to get that, you need to resize the view on rotation to an aspect ratio that matches the device's camera. Here's the official Android guide.

Notice the part specifically called "Set the Preview Orientation".

0
Joan P.S On

BeyondAR has been updated, now it is way easier thanks to fragments. Check the web page and update your library:

https://github.com/BeyondAR/beyondar