Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android camera preview look strange

I am implementing a camera app and when I look at the preview (especially with front camera), the image is very fat. It looks like the image get stretched horizontally. I follow the sdk sample with the optimzed camera size but it doesn't help. How can I adjust my camera setting so that it will preview like the other camera app?

Thanks.

My code is below.

public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback {

Camera m_camera;
SurfaceView m_surfaceView;
int m_numOfCamera;
int m_defaultCameraId;
int m_currentCamera;
int m_surfaceWidth;
int m_surfaceHeight;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera);
    getActionBar().setDisplayHomeAsUpEnabled(true);


    m_surfaceView = (SurfaceView)findViewById(R.id.cameraPreview);
    m_surfaceView.getHolder().addCallback(this);

    m_camera = Camera.open();

    m_numOfCamera = Camera.getNumberOfCameras();

    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < m_numOfCamera; ++i) {
        Camera.getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            m_defaultCameraId = i;
            m_currentCamera = m_defaultCameraId;
        }       
    }

    if (m_numOfCamera < 1) {
        MenuItem switchCam = (MenuItem)findViewById(R.id.menu_switch_camera);
        switchCam.setVisible(false);
    }
}

@Override
public void onPause() {
    super.onPause();
    m_camera.stopPreview();
}

@Override
public void onDestroy() {
    super.onDestroy();
    m_camera.release();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_camera, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(final MenuItem item) 
{
    if (item.getItemId() == android.R.id.home) 
    {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);

        return true;
    } 
    else if (item.getItemId() == R.id.menu_switch_camera)
    {
        if (m_camera != null) {
            m_camera.stopPreview();
            m_camera.release();
            m_camera = null;
        }   

        m_camera = Camera.open((m_currentCamera + 1) % m_numOfCamera);
        m_currentCamera = (m_currentCamera + 1) % m_numOfCamera;

        Camera.Parameters params = m_camera.getParameters();
        List<Camera.Size> sizes = params.getSupportedPreviewSizes();
        Camera.Size size = getOptimalPreviewSize(sizes, m_surfaceWidth, m_surfaceHeight);

        params.setPreviewSize(size.width,  size.height);

        m_camera.setParameters(params);
        setCameraDisplayOrientation(this, m_currentCamera, m_camera);
        m_camera.startPreview();
        try {
            m_camera.setPreviewDisplay(m_surfaceView.getHolder());
        } catch (Exception e) {
            e.printStackTrace();
        }   
        return true;
    }
    return true;
}

public void onPictureTaken(byte[] arg0, Camera arg1) {
    // TODO Auto-generated method stub

}

public void onShutter() {
    // TODO Auto-generated method stub

}

public void surfaceChanged(SurfaceHolder arg0, int format, int w, int h) {
    m_surfaceWidth = w;
    m_surfaceHeight = h;
    Camera.Parameters params = m_camera.getParameters();
    List<Camera.Size> sizes = params.getSupportedPreviewSizes();
    Camera.Size selected = getOptimalPreviewSize(sizes, w, h);

    params.setPreviewSize(selected.width,  selected.height);


    m_camera.setParameters(params);
    setCameraDisplayOrientation(this, m_currentCamera, m_camera);
    m_camera.startPreview();    
}

private 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 = 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;
     }
     camera.setDisplayOrientation(result);
 }


public void surfaceCreated(SurfaceHolder arg0) {
    try {
        m_camera.setPreviewDisplay(m_surfaceView.getHolder());
    } catch (Exception e) {
        e.printStackTrace();
    }   
}

public void surfaceDestroyed(SurfaceHolder arg0) {
    // TODO Auto-generated method stub

}

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {


    final double ASPECT_TOLERANCE = 0.1;
    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) {
        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;
}

}
like image 766
Kintarō Avatar asked Oct 05 '12 17:10

Kintarō


People also ask

How to set camera preview orientation in Android?

To force portrait orientation: set android:screenOrientation="portrait" in your AndroidManifest. xml and call camera. setDisplayOrientation(90); before calling camera.

What is camera preview in Android?

PreviewView is a subclass of FrameLayout . To display the camera feed, it uses either a SurfaceView or TextureView , provides a preview surface to the camera when it's ready, tries to keep it valid as long as the camera is using it, and when released prematurely, provides a new surface if the camera is still in use.

What is preview in camera?

Live preview is a feature that allows a digital camera's display screen to be used as a viewfinder. This provides a means of previewing framing and other exposure before taking the photograph.


1 Answers

The camera preview always fills up the SurfaceView showing it. If the aspect ratio of m_surfaceView doesn't match with the camera's aspect ratio, the preview will be stretched.

You'll need to create m_surfaceView matching the aspect ratio. That means, you'll need to create it from code, not from layout XML file.

There is a sample project APIDemos that you'll find in android sample projects. In the project there is a thing named CameraPreview. This one has a good demonstration for setting up camera preview in a SurfaceView. It has a class that extends ViewGroup, and adds the SurfaceView as its child from the code. The onMeasure() method has been overridden to determine the height and width of the SurfaceView, so the aspect ratio is preserved. Take a look on the project, and I hope it will be clear.

[Sorry I couldn't post the link here - this is supposed to be the link, but I found it broken. But if you have installed the sample projects with the Android SDK, you can find the project in the samples. Open a new Android Sample Project, select APIDemos, then look for a class named CameraPreview. It should be in the package com.example.android.apis.graphics, as far as I remember.]

like image 95
Sufian Latif Avatar answered Oct 26 '22 16:10

Sufian Latif