Picture distorted with Camera and getOptimalPreviewSize - android

I am on a Camera App which taking basic pictures. I have an issue when I get the best optimal preview size.
In fact, with this first code :
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (isPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters parameters = mCamera.getParameters();
mCamera.setParameters(parameters);
mCamera.startPreview();
isPreviewRunning = true;
}
The picture has a good quality :
http://img689.imageshack.us/i/04042011172937.jpg/
But, with this code :
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
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;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
if (isPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, w, h);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();
isPreviewRunning =true;
}
The picture is totally distorted :
http://img97.imageshack.us/i/04042011173220.jpg/
How can I resolve this problem??
I am using a HTC Desire HD.
It is probably my saving method too ? :
PictureCallback mPictureCallbackJpeg = new PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera camera) {
....
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 5;
Bitmap myImage = BitmapFactory.decodeByteArray(imageData, 0,imageData.length,options);
FileOutputStream fOut = new FileOutputStream(path + "/"+fl);
BufferedOutputStream bos = new BufferedOutputStream(fOut);
myImage.compress(CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
....
}
Thanks

I just suffered through the same problem, and came up with a similar but lighter weight solution. I don't see anything wrong with your saving method though.
private Camera.Size getBestPreviewSize(int width, int height)
{
Camera.Size result=null;
Camera.Parameters p = camera.getParameters();
for (Camera.Size size : p.getSupportedPreviewSizes()) {
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;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//This line helped me set the preview Display Orientation to Portrait
//Only works API Level 8 and higher unfortunately.
camera.setDisplayOrientation(90);
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height);
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
camera.startPreview();
}

The best way is to get preview size with the closest aspect ratio:
Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result=null;
float dr = Float.MAX_VALUE;
float ratio = (float)width/(float)height;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
float r = (float)size.width/(float)size.height;
if( Math.abs(r - ratio) < dr && size.width <= width && size.height <= height ) {
dr = Math.abs(r - ratio);
result = size;
}
}
return result;
}
Where width and height parameters are your surface size.

Related

preview is not stretching but when i click on start record preview stretching

When i try to record using my custom camera its preview showing normally and in good shape but when i click on start button preview changed and stretching.
public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e("Ji", str.width + "/" + str.height);
setKeepScreenOn(true);
// 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);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// 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();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
Here is onMesuare method for calculations
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
And For getting Size of Screen here is method.
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
Thanks for help in advance...

Stretching preview in the custom camera android

I'm using code inside this book "Pro Android Media
Developing Graphics, Music, Video, and Rich Media Apps for Smartphones and Tablets", and i have problem with preview of camera
and I used camera API in my app
I face some problem :
1) The display appear in the case of stretched, in the case of the lowest link shows the difference between the camera original phone and custom camera
here video for my problem i face
OR here video for my problem i face
The following code which I found somewhere helped me.
You essentially have to scale the preview in accordance with your screen size and for that this method should suffice,
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.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);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
Now you are to Override the onMeasure in your preview Activity which I presume is extending the SurfaceView like this,
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if(mCamera != null) {
List<Camera.Size> mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
}
and finally start the preview with the tuned PreviewSize calculated in onMeasure like this,
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
isSafeToTakePicture = true;
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}

Extending android surface view for camera to support all devices

I have created a CameraSurfaceView class which provides logic for implementing the camera preview. Everything works fine on the devices I have tried. Nexus 5, Nexus 5X, Nexus 6P and even a Samsung Galaxy S5.
But for some reason on the Samsung Galaxy S6 Edge, I get a Runtime exception of
android.hardware.Camera.native_setParameters(Native Method)
I have narrowed it down to the the following in class
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height);
Here is my class:
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private Camera mCamera;
private SurfaceHolder mSurfaceHolder;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mSurfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
try {
// stop preview before making changes
mCamera.stopPreview();
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height);
if (parameters.getSupportedFocusModes()
.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
Timber.e(e, "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if (mPreviewSize.height >= mPreviewSize.width) {
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
} else {
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
}
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double aspectTolerance = 0.1;
double targetRatio = (double) h / w;
if (sizes == null) {
return null;
}
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > aspectTolerance) {
continue;
}
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
How do I set the picture size correctly for this device or any others with the same issue?
Does anyone have a good example of Camera SurfaceView logic that would work for most devices?
Thanks.
Turns out I was using the supportedPreviewSizes to set the picture size as opposed to the supportedPictureSizes in the camera parameters.
Below is my new CameraSurfaceView class:
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private Camera mCamera;
private SurfaceHolder mSurfaceHolder;
private List<Camera.Size> mSupportedPreviewSizes;
private List<Camera.Size> mSupportedPictureSizes;
private Camera.Size mPreviewSize;
private Camera.Size mPictureSize;
public CameraSurfaceView(Context context, Camera camera) {
super(context);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
mCamera = camera;
Camera.Parameters parameters = mCamera.getParameters();
mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
mSupportedPictureSizes = parameters.getSupportedPictureSizes();
if (parameters.getSupportedFocusModes()
.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
mCamera.setParameters(parameters);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mSurfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
try {
// stop preview before making changes
mCamera.stopPreview();
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
Timber.e(e, "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
if (mSupportedPictureSizes != null) {
mPictureSize = getOptimalPreviewSize(mSupportedPictureSizes, mPreviewSize.width,
mPreviewSize.height);
}
float ratio;
if (mPreviewSize.height >= mPreviewSize.width) {
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
} else {
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
}
setMeasuredDimension(width, (int) (width * ratio));
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double aspectTolerance = 0.1;
double targetRatio = (double) h / w;
if (sizes == null) {
return null;
}
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > aspectTolerance) {
continue;
}
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}

SetParameter is failing for few android device

I have built a android camera app, which works fine for few devices and in some devices it crashes before starting the preview. Tried with all stackOverflow solution, but nothing worked for me.
My Preview Class
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
protected List<Camera.Size> mSupportedPreviewSizes;
private List<Camera.Size> mSupportedPictureSizes;
private Camera.Size mPreviewSize;
private Camera.Size mPictureSize;
private Camera mCamera;
public CameraPreview(Context context) {
super(context);
}
public CameraPreview(Activity activity, Camera camera) {
super(activity);
mCamera = camera;
setCamera(mCamera);
mCamera.getParameters().getSupportedPreviewFpsRange();
SurfaceHolder mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.setKeepScreenOn(true);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mCamera.setDisplayOrientation(getDisplayOrientation());
Camera.Parameters parameters = mCamera.getParameters();
mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
mSupportedPictureSizes = parameters.getSupportedPictureSizes();
requestLayout();
parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
int index = parameters.getExposureCompensation();
parameters.setExposureCompensation(index);
mCamera.setParameters(parameters);
}
}
public int getDisplayOrientation() {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int rotation = display.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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degree) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degree + 360) % 360;
}
return result;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException e) {
Log.d("DG_DEBUG", "Error setting camera preview in surfaceCreated: " + e.getMessage());
}
}
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);
}
if(mSupportedPictureSizes != null){
mPictureSize = getOptimalPictureSize();
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height) {
Camera.Size optimalSize = null;
final double ASPECT_TOLERANCE = 0.01;
double targetRatio = (double) height / width;
double minDiff = Double.MAX_VALUE;
int targetHeight = height;
for (Camera.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);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
// Here it is returning optimal preview size.
For Example : Moto G has 720*1280 screen resolution, it works perfectly fine for by returning optimalSize as 720*1280.
But for Moto X which has same resolution 720*1280 it crashes before starting the preview. It is return width = 640, height=480 which is incorrect.
Log.d("getOptimalPreviewSize",
String.format(
"getOptimalPreviewSize result: width = %d, height = %d for input width = %d, height = %d",
optimalSize.width, optimalSize.height, width,
height));
return optimalSize;
}
private Camera.Size getOptimalPictureSize() {
if (mCamera == null) {
return null;
}
List<Camera.Size> cameraSizes = mCamera.getParameters().getSupportedPictureSizes();
Camera.Size optimalSize = mCamera.new Size(0, 0);
double previewRatio = (double) mPreviewSize.width / mPreviewSize.height;
for (Camera.Size size : cameraSizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - previewRatio) > 0.01f)
continue;
if (size.height > optimalSize.height) {
optimalSize = size;
}
}
if (optimalSize.height == 0) {
for (Camera.Size size : cameraSizes) {
if (size.height > optimalSize.height) {
optimalSize = size;
}
}
}
return optimalSize;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
Camera.Size mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(mPictureSize.width, mPictureSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
} catch (Exception e) {
Log.d("SurfaceDestroyed", " Error handling surface destroy method");
}
}
}

android camera preview wrong aspect ratio

i created a camera app based on tutorial. the preview class i use is from api-Demos "CameraPreview". I added a modification from here (preview was always rotated by 90°). So this is how i set preview size:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
mCamera.setDisplayOrientation(90);
}
if (display.getRotation() == Surface.ROTATION_90) {
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
}
if (display.getRotation() == Surface.ROTATION_180) {
parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
}
if (display.getRotation() == Surface.ROTATION_270) {
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setDisplayOrientation(180);
}
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
But the Preview is displayed with wrong aspect ratio. Is it because of the code above or probably because of the layout i use?:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/button_capture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/capture" />
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="100dp"
android:layout_height="match_parent"/>
So how to get the correct aspect ratio? Thanks in advance.
P.S. i read the answer from: Android camera preview look strange
But this isn't working for me.
Try changing the preview sizes with adding this function:
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w/h;
if (sizes==null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Find size
for (Camera.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);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
And the setting the sizes from these optimized values:
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
The following code modifies the width/height of the camera preview container to match the aspect ratio of the camera preview.
Camera.Size size = camera.getParameters().getPreviewSize();
//landscape
float ratio = (float)size.width/size.height;
//portrait
//float ratio = (float)size.height/size.width;
preview = (FrameLayout) findViewById(R.id.camera_preview);
int new_width=0, new_height=0;
if(preview.getWidth()/preview.getHeight()<ratio){
new_width = Math.round(preview.getHeight()*ratio);
new_height = cameraPreview.getHeight();
}else{
new_width = preview.getWidth();
new_height = Math.round(preview.getWidth()/ratio);
}
preview.setLayoutParams(new FrameLayout.LayoutParams(new_width, new_height));
Using the above solution, using the method private Size getOptimalPreviewSize(List sizes, int w, int h).
Worked fine! I was having problems with the aspect ratio on portrait orientation: Here it´s my solution using. Mixing it with android's documentation:
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 params = mCamera.getParameters();
params.set("orientation", "portrait");
Size optimalSize=getOptimalPreviewSize(params.getSupportedPreviewSizes(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
params.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(params);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
problem is really in way you layout things.
there is overriden onLayout in Preview class. idea of its work is to set child SurfaceView size according to found optimal Size. but it doesn't take rotation into account, so you need to do it by yourself:
if (mPreviewSize != null) {
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
}
instead of
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
Trick is to swap width and height which is done because of 90 degree rotation achieved by
mCamera.setDisplayOrientation(90);
You might also consider forking child preview size setting depending on orientation that you set in
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//...
}
(in provided by me code it is always for 90 degree rotation, for 180 you don't have to do anyhing and when you don't set any rotation, there is no need to swap width and height)
Another thing worth mentioning - when calculating getOptimalPreviewSize for case when you have rotation and you swap child width and height you also should pass parent(Preview) width and height swapped in onMeasure:
if (mSupportedPreviewSizes != null) {
//noinspection SuspiciousNameCombination
final int previewWidth = height;
//noinspection SuspiciousNameCombination
final int previewHeight = width;
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight);
}
Henric's answer didn't work for me, so I've created another method which determines the optimal preview size for any camera given the target view current width and height and also the activity orientation:
public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) {
if (CommonUtils.isEmpty(cameraPreviewSizes)) {
return null;
}
int optimalHeight = Integer.MIN_VALUE;
int optimalWidth = Integer.MIN_VALUE;
for (Camera.Size cameraPreviewSize : cameraPreviewSizes) {
boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width;
int actualCameraWidth = cameraPreviewSize.width;
int actualCameraHeight = cameraPreviewSize.height;
if (isActivityPortrait) {
if (!isCameraPreviewHeightBigger) {
int temp = cameraPreviewSize.width;
actualCameraWidth = cameraPreviewSize.height;
actualCameraHeight = temp;
}
} else {
if (isCameraPreviewHeightBigger) {
int temp = cameraPreviewSize.width;
actualCameraWidth = cameraPreviewSize.height;
actualCameraHeight = temp;
}
}
if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) {
// finds only smaller preview sizes than target size
continue;
}
if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) {
// finds only better sizes
optimalWidth = actualCameraWidth;
optimalHeight = actualCameraHeight;
}
}
Size optimalSize = null;
if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) {
optimalSize = new Size(optimalWidth, optimalHeight);
}
return optimalSize;
}
This uses a custom Size object, because Android's Size is available after API 21.
public class Size {
private int width;
private int height;
public Size(int width, int height) {
this.width = width;
this.height = height;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
}
You can determine the width and height of a view by listening for its global layout changes and then you can set the new dimensions. This also shows how to programmatically determine activity orientation:
cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// gets called after layout has been done but before display.
cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait);
if (optimalCameraPreviewSize != null) {
LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight());
cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams);
}
}
});

Categories

Resources