2

the camera preview is showing a distorted image, which is elongated while in portrait mode and flattened while in landscape. I have already resized preview with a million techniques. Then I read somewhere it must be something with resizing the SurfaceView. But so far I have not found anything suitable.

This is my activity.java file:

public class CameraActivity extends Activity {

private Camera mCamera;
private CameraPreview mPreview;
private FrameLayout preview;
private static final String TAG = "CameraActivity";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera);
    if (checkCameraHardware(getBaseContext())){
        // Create an instance of Camera
        mCamera = getCameraInstance();
        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera, CameraActivity.this);
        preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);

    }
}

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if     (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
         Log.d(TAG, "Camera Available");
        return true;
    } else {
        Log.d(TAG, "No Camera Found");
        return false;
    }
}

/** A safe way to get an instance of the Camera object. */
public Camera getCameraInstance(){
    Camera c = null;
    try {
        int i = Camera.getNumberOfCameras();
        releaseCamera(); //in case camera is being accessed by any other app.
        Log.d(TAG, "Number of Cameras "+i +"\n");
        c = Camera.open(); // attempt to get a Camera instance
        Log.d(TAG, "Camera Opened");
    }
    catch (Exception e){
         Log.d(TAG, "Camera Can't Be Accessed");
    }
    return c; // returns null if camera is unavailable
}


 @Override
    protected void onPause() {
        super.onPause();
        releaseCamera();              // release the camera immediately on pause event
    }

    private void releaseCamera(){
        if (mCamera != null){
            //mCamera.setPreviewCallback(null);
            mPreview.getHolder().removeCallback(mPreview);
            mCamera.release();        // release the camera for other applications
        }
    }

This is my camera preview class:

@SuppressLint("ViewConstructor")
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
private Size mPreviewSize; 

@SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera, Activity activity) {
    super(context);
    mCamera = camera;
    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, now tell the camera where to draw the preview.

    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();
    } catch (IOException e) {
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    }
}


public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.

}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.

    if (mHolder.getSurface() == null){
      // preview surface does not exist
      return;
    }

    // stop preview before making changes
    try{
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }


    // set preview size and make any resize, rotate or
    // reformatting changes here
    Camera.Parameters parameters = mCamera.getParameters();
    List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
    mPreviewSize = localSizes.get(0);
    Log.d(TAG, "Width " + mPreviewSize.width);
    Log.d(TAG, "Height " + mPreviewSize.height);

    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height );
    requestLayout();
    mCamera.setParameters(parameters);

    //start preview with new settings
    try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}


public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = -90; break;
         case Surface.ROTATION_180: degrees = 0; break;
         case Surface.ROTATION_270: degrees = -90; 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;
     }
        camera.setDisplayOrientation(result);
    }


   }

And this is my activity.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:baselineAligned="false"
android:layout_width="match_parent"
android:layout_height="match_parent"

tools:context=".CameraActivity" >

<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight = "1"
/>


</LinearLayout>
Neha Shukla
  • 3,572
  • 5
  • 38
  • 69
Haleema
  • 21
  • 1
  • 5

3 Answers3

1

Your SurfaceView (or TextureView) must have the same aspect ratio as your preview images, otherwise you will get the distortion that you describe.

FWIW, you may find it useful to work with my CWAC-Camera library, which offers a CameraFragment that handles a lot of this low-level stuff for you. It's still a work in progress, though.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • My Surface View does have the same aspect ratio. – Haleema Jul 16 '13 at 12:13
  • @user1235240: Not that I can see. `CameraPreview` chooses a semi-random preview size, then only seems to use that to configure the camera. I fail to see anywhere that you are affecting the aspect ratio of `CameraPreview` itself using that preview size. – CommonsWare Jul 16 '13 at 12:16
1

You can find the camera preview width & height as soon as the camera instance is created, in onCreate. Then, choose layout_width and layout_height so that they fit into the preview FrameLayout and preserve the aspect ratio of the camera. You can use FrameLayout.addView(View, LayoutParams).

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • do I specify the layout_width and the layout_height? because I have mentioned in the xml that it has to fill_parent. – Haleema Jul 15 '13 at 16:02
  • Yes, and you would probably prefer to choose them at runtime, not in xml. – Alex Cohn Jul 15 '13 at 17:52
  • I used to the camera parameters to get the width and the height, and set it accordingly, and added them as you mentioned. But it still has no effect. The landscape mode is working fine now since I added cameraorientation: portrait in the Manifest file, but it all stretched when I make the camera vertical. – Haleema Jul 16 '13 at 10:26
  • Maybe, in Portrait mode you should swap width and height? – Alex Cohn Jul 16 '13 at 13:10
  • @Haleema i m also getting same issue can u pls tell me how u resolved your issue? – user3233280 Nov 18 '14 at 15:36
0

Not sure if anyone still reads this but I had the same problem and this answer fixed it. I copy the code here just in case (I also editted it to match this example):

mCamera.Parameters parameters1 = mCamera.getParameters();
parameters1.setPreviewSize(getWidth(), getHeight());
mCamera.setParameters(parameters1);

add these lines just before this:

mCamera.startPreview();
Community
  • 1
  • 1
soroosh.strife
  • 1,181
  • 4
  • 19
  • 45