I have implemented custom camera in my app. It is working fine in all device except Nexus 5 and Nexus 7. In both devices, It is crashing with SetParameters failed on camera. I have implemented custom camera with below code:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mCamera != null) {
Log.e(TAG, "surfaceChanged called");
Camera.Parameters parameters = mCamera.getParameters();
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, w,
h);
}
Log.e(TAG, "surfaceChanged : mPreviewSize height:"
+ mPreviewSize.height + " width: " + mPreviewSize.width);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
Log.e(TAG, "surfaceChanged called setParameters success");
}
}
I have found at many places comments that it is due to unsupported preview size but In my case, I am already taking it from supported preview sizes.
I had the same issue with a Nexus tablet: the same code changing the preview size to another supported preview size worked on various tablets but not the nexus tablet I had.
In my case, the issue was that I had already started previewing before changing the preview size. Changing the preview size before starting the preview size solved my issue.
Related
I have a problem for my application, specifically, when I want to take a picture (from android Camera API) and send it to my server, I got some strange pictures like following example:
which contain many noise points and actually the size/resolution are very small (176*144 pixels). And this is my original code for surfaceChanged:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.e(LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
mCamera.startPreview();
}
And I tried to ask some classmates for this issue, they don't know but one of them give the following code:
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
try {
// camera.stopPreview();
// Camera.Parameters mParameters = camera.getParameters();
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size optiSize = getBestPreviewSize(720, 720);
if (optiSize != null) {
parameters.setPreviewSize(optiSize.width, optiSize.height);
parameters.setPictureSize(optiSize.width, optiSize.height);
}
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
mCamera.setParameters(parameters);
// mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
// camera.setParameters(mParameters); // apply the changes
} catch (Exception e) {
// older phone - doesn't support these calls
}
mCamera.startPreview();
}
private Camera.Size getBestPreviewSize(int width, int height) {
List<Camera.Size> sizes = mCamera.getParameters()
.getSupportedPreviewSizes();
if (sizes == null)
return null;
Camera.Size optimalSize = null;
int tmpSize;
int minWidthDiff = 1000;
for (Camera.Size size : sizes) {
if (size.width > size.height)
tmpSize = size.height;
else
tmpSize = size.width;
if (Math.abs(tmpSize - width) < minWidthDiff) {
minWidthDiff = Math.abs(tmpSize - width);
optimalSize = size;
}
}
return optimalSize;
}
And this one works pretty well, it can store the original picture with the full resolution. Although I modify a little bit of my other codes to make the new codes compatible with my system, (add AutoFocus, for example). But I think the problem occurs because the method surfaceChanged because if I take image only with Autofocus, it still not work.
Therefore my question is: why this method will influence the quality of my image. I thought this method is only called when we "change" the surface, something like rotate the screen. But apparently it do something more than that?
Can anybody give me some help? Or some posts to explain this fact? Thank you very much in advance.
This method is called when the surface is changed, e.g. it is resized. It is common to adjust some of the camera's parameters to better fit the new configurations (such as setting an appropriate preview size).
What you are doing in the first code is you're getting the camera's Camera.Parameters, set a key-value pair (by the way, the documentation does not mention any parameter with the key "orientation" - it probably has no meaning). What you forgot to do is to apply the new parameters to the camera using Camera.setParameters(). Then again, without actually setting any valid parameters, this would have no effect.
This leads to the low-quality picture issue. You should use the Camera.Parameters object to set a desired preview and picture size. In the second block of code, this is done inside getBestPreviewSize(). A list of available preview sizes is got and the most fitting one is chosen based on the preview's size. It might be helpful to set a satisfactory picture size, too.
The thing is, different devices have different set of supported values for the parameters. If you want to provide a consistent functionality, you should check the supported values using Camera.Parameters.getSupported* methods and set them accordingly.
I'm facing following problem. I'm using SurfaceView to show Camera preview, but when I set surface view to visible, I get following exception.
java.lang.RuntimeException: getParameters failed (empty parameters)
at android.hardware.Camera.native_getParameters(Native Method)
at android.hardware.Camera.getParameters(Camera.java:1460)
at com.the.package.activity.ShowPhotoActivity$2.surfaceChanged(ShowPhotoActivity.java:111)
at android.view.SurfaceView.updateWindow(SurfaceView.java:558)
at android.view.SurfaceView.setVisibility(SurfaceView.java:248)
ShowPhotoActivity:
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = mCamera.getParameters(); // <-- line 101
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (mInPreview) {
mCamera.stopPreview();
}
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
mCamera.setDisplayOrientation(90);
parameters = mCamera.getParameters(); // <---- line 111
size = getBestPreviewSize(width, height, parameters);
}
if (display.getRotation() == Surface.ROTATION_270) {
mCamera.setDisplayOrientation(180);
parameters = mCamera.getParameters();
size = getBestPreviewSize(width, height, parameters);
}
Camera.Size s = getBestResolution(parameters);
parameters.setPreviewSize(size.width, size.height);
parameters.setPictureSize(s.width, s.height);
mCamera.setParameters(parameters);
if (mInPreview) {
mCamera.startPreview();
}
}
It really drives me crazy, why line 101 is processed with no problem and line 111 throws exception. This happens only on device Sony st26i (Xperia J) with Android 4.1.1. I haven't noticed any problems on Galaxy Nexus, Galaxy SIII or 4.1.2 emulator. Thanks for every idea.
It has been answered over here, check the accepted answer:
Correct handling of exception: "getParameters failed (empty parameters)"
My guess is that stopPreview here is problematic, potentially called from the wrong thread. Check your logs around the time you call stopPreview, it might give you a clue.
I'm using camera on my app. Camera is working perfect on all devices upto Samsung S3 even. Image is correct from all other devices.
While taking image from S4 , image gets corrupted and image gets saved with some lines in horizontal.
I tried changing resolution and everything but still issue is there .
Any help
I've been pulling my hair out over this and I think I found the issue, at least with regards to my app - it's got something to do with the aspect ratio of the preview image versus the captured image.
In my case, my code was sniffing out the ideal preview size based on the aspect ratio of the screen. The S4 is a 1080p phone, so the preview image was 1920x1080, which is a 16:9 aspect ratio. But my code was hardcoded to capturing a 1600x1200 image, which is 4:3, because that's all I needed. But 1600x1200 is not one of the valid sizes the S4 supports.
Without setting the size, the S4 captured 4128x3096, which is the maximum size, and is 4:3, but the lines still appeared. Once I told the camera to capture a 16:9 photo, the lines went away. In your case, you might want to adjust the preview's aspect ratio.
Here's some code which can tell you the available sizes.
List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();
int i = 1;
for (Size previewSize : previewSizes) {
Log.v("DebugCamera", "previewSize " + i++ + " width: " + previewSize.width + " height: " + previewSize.height);
}
Just tried this code on S4 and it works. Try it:
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;
}
public void surfaceCreated(SurfaceHolder holder) {
if(myCamera == null){
myCamera = getCameraInstance();
try {
myCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
// Surface will be destroyed when we return, so stop the preview.
if (myCamera != null)
{
myCamera.stopPreview();
myCamera.setPreviewCallback(null);
myCamera.release();
}
}
#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();
}
I have an application that taking a photo in android.
It crashed some devices. I set the photo size as follows.
What could be the reason for the crash?
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
Camera.Parameters parameters = camera.getParameters();
List<Size> sizes = parameters.getSupportedPictureSizes();
if (sizes == null || sizes.size() == 0)
{
parameters.setPreviewSize(w, h);
} else
{
parameters.setPictureSize(sizes.get(0).width, sizes.get(0).height);
for(Size s : sizes)
{
if( s.width < 700)
{
parameters.setPictureSize(s.width, s.height);
break;
}
}
}
camera.setParameters(parameters);
camera.startPreview();
}
Guys I know that it's a old post though I came across the same issue though this time everything worked on Samsung and Nexus line though not on HTC (due Sense for sure). What I've done to fix this issue was loop through all supported sizes and get the one that is supported.
In fact it's crash when I did try to setParamters, because the maximun Picture size supported value. So I did a small method that loop through it and set the one that is accepted by the device.
private void setCameraParameters() {
if (camera != null) {
mParameters = camera.getParameters();
List<Camera.Size> sizes = mParameters.getSupportedPreviewSizes();
Camera.Size selected = sizes.get(0);
if (android.os.Build.MANUFACTURER.contains("HTC")) {
getHTCBestSupportedResolution(sizes);
}
mParameters.setColorEffect(Camera.Parameters.EFFECT_MONO);
mParameters.setJpegQuality(100);
mParameters.setPreviewSize(selected.width, selected.height);
mParameters.setRotation(90);
mParameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
mParameters.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(mParameters);
camera.setDisplayOrientation(90);
camera.startPreview();
}
}
private void getHTCBestSupportedResolution(List<Camera.Size> sizes) {
for (Size size : sizes) {
try {
mParameters.setPictureSize(size.width, size.height);
camera.setParameters(mParameters);
// Log.e("Size worked", size.width + " x " + size.height);
break;
} catch (Exception e) {
continue;
}
}
}
Now it's works fine on all devices, as rule of thumb you can remove the condition that compare for HTC and just let it generic for all devices.
I hope that this help those ones facing the same issue.
Thanks
Check Logcat, I guess it crashes on
camera.setParameters(parameters);
On some devices some of the reported supported resolutions don't seem to be actually supported. You can try to find a legacy resolution, that is supported on all devices. Or catch the exception and try to set another resolution.
I have the following problem:I have an app where I'm using the camera of the android device.
I have built my own camera.The BIG problem is that when the preview starts all the image looks resized.Every object looks longer, larger...
in surfaceChanged() method I've done this:
List<Size> previews = p.getSupportedPreviewSizes();
I looped this list previews but I haven't found a better size for my preview.
The list previews has the size equal to 7 but nne of this items make my image look better!!
Here is how my method looks like:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged");
if (mPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters p = mCamera.getParameters();
List<Size> sizes = p.getSupportedPictureSizes();
List<Size> previews = p.getSupportedPreviewSizes();
Size preview = previews.get(3);
// the size of preview is 7 and looped each item....
p.setPreviewSize(preview.width,preview.height);
int f=p.getJpegQuality();
Size size = sizes.get(3);
p.setJpegQuality(f);
p.setPictureSize(size.width,size.height);
mCamera.setParameters(p);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
mPreviewRunning = true;
}
Anyone any idea?
Take a look at the PreviewFrameLayout class from the default Camera app. It's used to display SurfaceView using the aspect ratio it must have.
You need to maintain your aspect ratio.
Try setting your preview size to 640x480 if your device supports it. This will maintain an aspect ratio of 4:3.
If your dev doesn't support 640x480 try setting it to a different resolution which maintains an aspect ratio of 4:3.
You can set the preview size on the camera like this -
mCameraDevPara.setPreviewSize(PREVIEW_WIDTH, PREVIEW_HEIGHT);
mCameraDev.setParameters(mCameraDevPara);
Only after you set the preview size you can call the API mCameraDev.setPreviewDisplay(mSurfaceHolder); and mCameraDev.startPreview();