Camera.getParameters() return null on Galaxy Tab - android

Here is my surface-changed event handling code:
public void surfaceChanged(SurfaceHolder holder,
int format, int width,
int height) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height,
parameters);
//...
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
// it fails with NullPointerExceptiopn here,
// when accessing "getSupportedPreviewSizes" method:
// that means "parameters" is null
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
///...
}
}
I initialize camera like this:
#Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
This problem doesn't occur on my Galaxy S Plus neither it happen on LG Optimus Black phone. Has anyone thoughts what's wrong here?

I've solved this.
parameters.getSupportedPreviewSizes()
Returns NULL on Galaxy Tab. So I just make a check if it is null and don't set new preview size in such case. To this conclusion I've came after looking into standard Camera application sources.

Looks like the camera variable was never initialized so you are calling getParameters() on null. Try calling camera = Camera.open(); first

camera initialization depends a lot on the specific device. For instance a specific Samsung device GT5500 is reporting null (width = 0, height = 0) as a valid resolution for preview, but crashes the whole phone ("hard" reboot) if you try to use it. We experienced it with mixare augmented reality engine (http://www.mixare.org) and it was PITA to debug (since we didn't have the phone and could not reproduce the bug on any other hardware).
However, about getting the "right" preview size you can take a look at our code (it's a free and open source app) on github. In the file: https://github.com/mixare/mixare/blob/master/src/org/mixare/MixView.java (row 871 and onwards)
List<Camera.Size> supportedSizes = null;
//On older devices (<1.6) the following will fail
//the camera will work nevertheless
supportedSizes = Compatibility.getSupportedPreviewSizes(parameters);
//preview form factor
float ff = (float)w/h;
Log.d("Mixare", "Screen res: w:"+ w + " h:" + h + " aspect ratio:" + ff);
//holder for the best form factor and size
float bff = 0;
int bestw = 0;
int besth = 0;
Iterator<Camera.Size> itr = supportedSizes.iterator();
//we look for the best preview size, it has to be the closest to the
//screen form factor, and be less wide than the screen itself
//the latter requirement is because the HTC Hero with update 2.1 will
//report camera preview sizes larger than the screen, and it will fail
//to initialize the camera
//other devices could work with previews larger than the screen though
while(itr.hasNext()) {
Camera.Size element = itr.next();
//current form factor
float cff = (float)element.width/element.height;
//check if the current element is a candidate to replace the best match so far
//current form factor should be closer to the bff
//preview width should be less than screen width
//preview width should be more than current bestw
//this combination will ensure that the highest resolution will win
Log.d("Mixare", "Candidate camera element: w:"+ element.width + " h:" + element.height + " aspect ratio:" + cff);
if ((ff-cff <= ff-bff) && (element.width <= w) && (element.width >= bestw)) {
bff=cff;
bestw = element.width;
besth = element.height;
}
}
Log.d("Mixare", "Chosen camera element: w:"+ bestw + " h:" + besth + " aspect ratio:" + bff);
//Some Samsung phones will end up with bestw and besth = 0 because their minimum preview size is bigger then the screen size.
//In this case, we use the default values: 480x320
if ((bestw == 0) || (besth == 0)){
Log.d("Mixare", "Using default camera parameters!");
bestw = 480;
besth = 320;
}
parameters.setPreviewSize(bestw, besth);
As you see we're not using directly the call to getSupportedPreviewSizes of the Camera class, but instead added a compatibility layer (the code is here: https://github.com/mixare/mixare/blob/master/src/org/mixare/Compatibility.java ) because we needed compatibility with older phones. If you don't want to support older android releases you can use the method of the Camera class directly.
HTH
Daniele

Related

Android device crashes when setting FPS, while it is in range of getSupportedPreviewFpsRange

I have an innerclass CameraView that extends SurfaceView.
Inside the surfaceChanged() function I use the following code to set Camera parameters:
Camera.Parameters camParams = mCamera.getParameters();
List<Camera.Size> sizes = camParams.getSupportedPreviewSizes();
// Sort the list in ascending order
Collections.sort(sizes, new Comparator<Camera.Size>() {
public int compare(final Camera.Size a, final Camera.Size b) {
return a.width * a.height - b.width * b.height;
}
});
for (int i = 0; i < sizes.size(); i++) {
if ((sizes.get(i).width >= imageWidth && sizes.get(i).height >= imageHeight) || i == sizes.size() - 1) {
imageWidth = sizes.get(i).width;
imageHeight = sizes.get(i).height;
Log.e(LOG_TAG, "Resolution: " + imageWidth + " x " + imageHeight);
break;
}
}
camParams.setPreviewSize(imageWidth, imageHeight);
for(int[] arr : camParams.getSupportedPreviewFpsRange ()){
Log.e(LOG_TAG, "Supported range: " + arr[0] + " - " + arr[1]);
}
camParams.setPreviewFrameRate(frameRate);
mCamera.setParameters(camParams);
The for loop inside this print the following range: Supported range: 4000 - 60000, which means that my device should support between 4 and 60 fps.
Now when I set frameRate = 45 (which is well withing the range), my app crashes with the following exception:
java.lang.RuntimeException: setParameters failed
at android.hardware.Camera.native_setParameters(Native Method)
at android.hardware.Camera.setParameters(Camera.java:1876)
This does not happen if frameRate = 30. Can someone explain why is my app is crashing? Can the getSupportedPreviewFpsRange() not be trusted?
Edit 1
I've now also tried camParams.setPreviewFpsRange(frameRate*1000, frameRate*1000);, same crash result.
I'm afraid you cannot force the fps value for the camera hardware (at least not with any value between 4000 and 60000.
Looking at the documentation, the method is deprecated since api level 9.
As they suggest, you will need to use setPreviewFpsRange in replacement with the exact range returned by camParams.getSupportedPreviewFpsRange.
You can use this question also as reference.
Apparently if you set the fps in a second, different call (So getParameters and then only set the fps and assign the params to the camera) it works. No idea why, but at least that solves this issue...

Android camera - taken picture inconsistent with preview

I'm having an issue with the camera on Android, basically when I take a photo with the Camera class, the taken output picture actually shows more than the preview. The best way to put it would be the preview is cropped. How would I fix this?
I've run the app on Samsung Galaxy S4, Samsung Galaxy S3, HTC One M8 and Nexus One and all exhibit this same issue. (All running Android 4.0 ICS)
The camera preview is full screen in an Activity with no Action Bar and the status bar hidden.
The camera i'm trying to create is portrait so I've set displayOrientation to 90.
The code I use for determining preview size and output photo size is as follows (I believe the problem is most likely here somewhere):
public static Camera.Size getBestAspectPreviewSize(int displayOrientation,
int width,
int height,
Camera.Parameters parameters,
double closeEnough) {
double targetRatio=(double)width / height;
Camera.Size optimalSize=null;
double minDiff=Double.MAX_VALUE;
if (displayOrientation == 90 || displayOrientation == 270) {
targetRatio=(double)height / width;
}
List<Size> sizes=parameters.getSupportedPreviewSizes();
Collections.sort(sizes,
Collections.reverseOrder(new SizeComparator()));
for (Size size : sizes) {
double ratio=(double)size.width / size.height;
if (Math.abs(ratio - targetRatio) < minDiff) {
optimalSize=size;
minDiff=Math.abs(ratio - targetRatio);
}
if (minDiff < closeEnough) {
break;
}
}
return(optimalSize);
}
public static Camera.Size getLargestPictureSize(CameraHost host,
Camera.Parameters parameters,
boolean enforceProfile) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
// android.util.Log.d("CWAC-Camera",
// String.format("%d x %d", size.width, size.height));
if (!enforceProfile
|| (size.height <= host.getDeviceProfile()
.getMaxPictureHeight() && size.height >= host.getDeviceProfile()
.getMinPictureHeight())) {
if (result == null) {
result=size;
}
else {
int resultArea=result.width * result.height;
int newArea=size.width * size.height;
if (newArea > resultArea) {
result=size;
}
}
}
}
if (result == null && enforceProfile) {
result=getLargestPictureSize(host, parameters, false);
}
return(result);
}
Size comparator class:
private static class SizeComparator implements
Comparator<Camera.Size> {
#Override
public int compare(Size lhs, Size rhs) {
int left=lhs.width * lhs.height;
int right=rhs.width * rhs.height;
if (left < right) {
return(-1);
}
else if (left > right) {
return(1);
}
return(0);
}
}
This is using cwac-camera and using SimpleCameraHost with no changes.
Any help is appreciated!
How would I fix this?
If you are using the full-bleed preview, the preview will be cropped in most cases, as the aspect ratio of the CameraView is unlikely to match the aspect ratio of the preview frames.
Quoting the documentation:
The original default behavior of CameraFragment and CameraView was to show the entire
preview, as supplied by the underlying Camera API. Since the aspect ratio of
the preview frames may be different than the aspect ratio of the CameraView,
this results in a "letterbox" effect, where the background will show through on
one axis on the sides.
The new default behavior is to completely fill the CameraView, at the cost of
cropping off some of the actual preview frame, what is known as "full-bleed preview"
(stealing some terminology from the world of print media).
To control this behavior:
Have your CameraHost
return true or false from useFullBleedPreview()
Or, call useFullBleedPreview()
on your SimpleCameraHost.Builder, passing in a boolean value to use by default.
Note that the pictures and videos taken by this library are unaffected by
useFullBleedPreview(). Hence, if useFullBleedPreview() returns true, the
picture or video may contain additional content on the edges that was not
visible in the preview.

How come that a camera preview in a textureview is much more fuzzy than in a surfaceview?

I have found out that when using a textureview instead of a surfaceview as a camera preview (both hooked up to the camera via a mediarecorder) then the preview is much more fuzzy.
What I mean by fuzzy is that in a texture view you can see the pixels, especially when zooming. That is not the case when using a surfaceview. Why is that the case?
UPD:
Sorry,but after I re-write my shit code, the key is the preview size too small that caused "fuzziness", so you should set a reasonable preview Size,not the reason strikeout below, but auto-focus is suggested ...
Size size = getBestSupportSize(parameters.getSupportedPreviewSizes(), width, height);
parameters.setPreviewSize(size.width, size.height);
As to the method getBestSupportSize(), how to get the bestSize for your project needs, in this case, it is as large as the screen width andhe ratio is 4/3 your's may be some other, I calculate the ration dividing width/height.
private Size getBestSupportSize(List<Size> sizes, int width, int height) {
Size bestsize = sizes.get(0);
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int dt = Integer.MAX_VALUE;
for (int i = sizes.size() - 1; i >= 0; i--) {
Log.d(TAG, "-index : " + i);
Size s = sizes.get(i);
if (s.width * 3.0f / 4 == s.height) {
int newDT = Math.abs(screenWidth - s.width);
if (newDT < dt && screenWidth < s.width) {
dt = newDT;
bestsize = s;
}
}
}
return bestsize;//note that if no "4/3" size supported,default return size[0]
}
So this "fuzziness" was caused by a small previewSize calcualate a best size for the camera using this getSupportedPreviewSizes() method
And I will keep the autoFocus snippet below, strikeout though, FYR if is needed.
Well i got the solution for this "fuzzy" problem,and my case is just using TextureView andsurfaceTexture to take a pic instead of old surfaceView withsurfaceHolderway.
The key is set this mCamera.autofocus(), why the pic is"fuzzy" is bacause we lack of this autoFocus setting.
like below :
mCamera.setPreviewTexture(surface);
//enable autoFocus if moving
mCamera.setAutoFocusMoveCallback(new AutoFocusMoveCallback() {
#Override
public void onAutoFocusMoving(boolean start, Camera camera) {
if (start) { //true means you are moving the camera
mCamera.autoFocus(myAutoFocus);
}
}
});
mCamera.startPreview();
The autoFocusCallback like this:
AutoFocusCallback myAutoFocus = new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
}
};

takePicture() fails with Error -2147483648

I use Camera.Parameters#setPictureSize() in my application to get the higher resolution image for Camera#takePicture().
I use Camera.Parameters#getSupportedPictureSizes to get this size.
This works fine, except on a Sony Xperia S : in Logcat, the only thing I get after calling Camera#takePicture() is a line saying :
Error -2147483648
I finally managed to discover that the best picture size of this phone was 4000x3000, which seemed far too big for me.
Si I tried by setting the picture size manually at 1920x1080, and takePicture worked, then.
Here is my code for getting best picture size :
private Camera.Size getBestPictureSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
Log.d(this.getClass().getName(), "getBestPictureSize() - s(n) = "
+ size.width + "x" + size.height);
if (result == null) {
result = size;
} else {
if (size.width > result.width) {
result = size;
}
}
}
return result;
}
So, do you know a way to get the best picture size of a device, and being sure that takePicture will work as expected ?
Maybe not the best solution, but this is what I use in a project I'm working on.-
private Size getPreferredPictureSize() {
Size res = null;
List<Size> sizes = camera.getParameters().getSupportedPictureSizes();
for (Size s : sizes) {
float ratio = (float) s.width / (float) s.height;
if (ratio == defaultCameraRatio && s.height <= PHOTO_HEIGHT_THRESHOLD) {
res = s;
break;
}
}
return res;
}
Where defaultCameraRatio is the aspect ratio of the default camera resolution; you can get it like this.-
Camera.Parameters params = camera.getParameters();
defaultCameraRatio = (float) params.getPictureSize().width / (float) params.getPictureSize().height;
And PHOTO_HEIGHT_THRESHOLD is a 'reasonable' max height, such as 960. So, in summary, you will get a smaller resolution keeping the same aspect ratio as the default one.

Find Mobile's Camera pixels programmatically

I searched for past two days and i was not successful yet .
I my case , i want to check the camera pixel resolution/Megapixels . If the camera's Mp is more than 4 then i need to re-size and upload .
Here is my code :
//to check the resolution
Camera mcamera ;
mcamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Camera.Parameters param = mcamera.getParameters();
Camera.Size size = param.getPictureSize();
cam_height = size.height ;
cam_width = size.width ;
mcamera.release();
// my functionality
BitmapFactory.Options resample = new BitmapFactory.Options();
if(cam_height > pict_height || cam_width > pict_width )
resample.inSampleSize = 2; // whatever number seems appropriate 2 means 1/2 of the original
else
resample.inSampleSize = 1;
capturedimg = BitmapFactory.decodeFile(fileUri.getPath() , resample);
resized_uri = bitmaptouri(capturedimg);
but this returns only the picture resolution which is the same as the Screen resolution of the mobile but i want the Mobile camera's resolution .
Any related answers are welcomed , Thanks in advance .
How about getSupportedPictureSizes()?
First find height and width like below:
android.hardware.Camera.Parameters parameters = camera.getParameters();
android.hardware.Camera.Size size = parameters.getPictureSize();
int height = size.height;
int width = size.width;
then get mega pixel using below equation:
int mg = height * width / 1024000;
where mg is your mega pixels.
First check the supported picture sizes available for the Camera using Camera.Parameters. There is a function called getSupportedPictureSizes() in Camera Parameters.
For e.g:
List<Camera.Size> mList = mParams.getSupportedPictureSizes();
Camera.Size mSize = mList.get(mList.size() - 1);
From the mList you get all the supported Picture Sizes. The final one in the list will be the largest possible resolution.
Try the code from here. It returns resolution in mp for back camera. You should use getSupportedPictureSize instead of getPictureSize
https://stackoverflow.com/a/27000029/1554031

Categories

Resources