I'm working on an Android app that uses the camera to preview and take pictures. I use FOCUS_MODE_CONTINUOUS_PICTURE with the galaxy S4 and find that the focusing works very well.
However, on the galaxy S5 the FOCUS_MODE_CONTINUOUS_PICTURE rarely ever finds the focus properly. The camera will zoom into focus, but then zoom back out of focus repeatedly.
Does anyone have an idea of why the FOCUS_MODE_CONTINUOUS_PICTURE works so poorly on the S5, or can anyone confirm whether or not they have the same issue?
I too have experienced these same issues.
The Galaxy S5, and possibly other devices, don't seem to have reliable behavior in continuous picture focus mode. This is very frustrating as a developer, when code works perfectly on most devices, but then along comes the S5 (a very popular device) and we look pretty bad.
After much head scratching, I think I have a solution (more of a workaround) that is working well.
set camera to FOCUS_MODE_CONTINUOUS_PICTURE
in gesture handler for taking a photo (e.g. button tap, touch event), switch camera to FOCUS_MODE_AUTO, then call Camera.autoFocus() in a deferred manner
this provides the nice continuous focus UI during photo preview, but takes the picture in reliable auto-focus mode.
Here is the code:
protected void onTakePicture()
{
// mCamera is the Camera object
// mAutoFocusCallback is a Camera.AutoFocusCallback handler
try
{
// determine current focus mode
Camera.Parameters params = mCamera.getParameters();
if (params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
{
mCamera.cancelAutoFocus(); // cancels continuous focus
List<String> lModes = params.getSupportedFocusModes();
if (lModes != null)
{
if (lModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))
{
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // auto-focus mode if supported
mCamera.setParameters(params); // set parameters on device
}
}
// start an auto-focus after a slight (100ms) delay
new Handler().postDelayed(new Runnable() {
public void run()
{
mCamera.autoFocus(mAutoFocusCallback); // auto-focus now
}
}, 100);
return;
}
mCamera.autoFocus(mAutoFocusCallback); // do the focus, callback is mAutoFocusCallback
}
catch (Exception e)
{
Log.e("myApp", e.getMessage());
}
}
please give this a try and report back your results
Related
I will explain my case.
I'm trying to do an application in which every 5 seconds will take an image, one without flash, and then after 5 seconds one with flash, and repeat this every time. So it will take one without flash, one with flash, one without flash, one with flash... infinitely.
The case is that with my code I can do this in some devices, but the same code won't work in others as I want. i.e:
BQ Aquaris X5 Plus : The no-flash image is correct, but the flash image will be just white.
BQ Aquaris E5 : Won't fire the flash.
How can this be possible, all devices in which I have tried are LEGACY hardware support level for Camera2 API.
This are some important methods in my code (I can't post all code due to char limit). I started from the Google Example:
This setAutoFlash does the mentioned above.
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
if(phototaken) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}else{
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
}
}
}
This other one works in some devices and the bq aquaris e5 but doesn't fire the flash in the bq aquaris x5 plus.
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
if(phototaken) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}else{
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}
}
}
And my captureStillPicture
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
// Orientation
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
phototaken = !phototaken;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
The question is, what am i doing wrong so it doesn't work in all devices? Any help will be great.
There are two levels of control for the flash - manual, and controlled by the auto-exposure routine. You're currently mixing them together.
If you want to fire the flash manually, then you need to set AE_MODE to either AE_MODE_OFF or AE_MODE_ON; not any of the FLASH modes. Then, FLASH_MODE will control whether the flash will be in torch mode, off, or fire once for a given request.
Since you're always leave AE_MODE in one of the FLASH states, what you do to FLASH_MODE should not matter, barring a bug in some specific device.
If you want to guarantee flash firing in every other picture, you need to use AE_MODE_ON_ALWAYS_FLASH for the force-flash photos, and you need to use AE_MODE_ON for the no-flash phoots; don't touch FLASH_MODE.
Right now, with AUTO_FLASH, it's up to the device whether to fire a flash or not, so you'll see different behavior from different devices and lighting conditions - some will fire, some won't.
The other key thing you're not doing is running a precapture sequence; this is essential for flash pictures, because it allows the device to fire the preflash to determine correct flash power, focus, and white balance.
To run precapture, set the AE_MODE as desired, and then set AE_PRECAPTURE_TRIGGER to START for one request. This will transition AE_STATE to PRECAPTURE, and it'll stay there for some number of frames; once AE_STATE is no longer PRECAPTURE, you can issue the actual image capture request. Make sure you keep the AE_MODE consistent throughout this.
The sample app Camera2Basic implements the precapture sequence, so take a look there; it also has some optimizations that skip precapture in case the scene is not dark enough to need flash, but since you want to force-fire flash, that's not relevant to you.
I have a small app I have been working on that uses the front camera. The way I have been obtaining use of the front camera seems to work on most phones, but users have been reporting trouble on the S3 and various other new devices. The way I have been accessing the front camera is like so:
// Find the ID of the front camera
CameraInfo cameraInfo = new CameraInfo();
for(int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if(cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
defaultCameraId = i;
mCameraFound = true;
}
}
if(!mCameraFound)
displayDialog(8);
From some of the error reporting I've added into the app, I've noticed the S3 actually finds the front camera, but users report it only shows a blank screen? I have only been able to test on the devices I have (GNex and N7). I was hoping someone here may have some experience with this or may be able to help me solve this issue. If you want to try the app out on your S3, check the link below. Thanks in advance.
https://play.google.com/store/apps/details?id=com.wckd_dev.mirror
EDIT: I created a MirrorView object which contains a TextureView used for the preview. The MirrorView object implements a SurfaceTextureListener. Within the onSurfaceTextureAvailable() method is where the preview is started. I also created a method for restarting the preview after the app has gone from hidden back to visible.
So this is called when the app is first started:
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
try {
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
requestLayout();
mCamera.setParameters(parameters);
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
}
}
catch(RuntimeException e) {
// Log.e(TAG, "RuntimeException caused by setPreviewTexture()", exception);
}
catch (IOException e) {
// Log.e(TAG, "IOException caused by setPreviewTexture()", exception);
}
}
The restartPreview call is to an identical (but separate) method. From some of the debug data I've been collecting through users, I've noticed that the app finds two camera on the S III and selects the id matching CAMERA_FACING_FRONT. Also, this issue doesn't seem to be happening on all S III. I have users who have feedback reporting as much. The latest report from a user experiencing this issue was an AT&T S III user. Any help would be appreciated!
Got some face time with an S3 tonight that was experiencing this issue with my app. Here what was going on. The TextureView relies on 2d hardware acceleration which is supposed to on by default (from what I understood) on 4.0+ devices. It wasn't turning on (for my app at least) on his phone. The fix was as simple as adding a single line in the manifest (under application).
android:hardwareAcceleration = "true"
In my current application, I've got a class holding an instance of a Camera object and trying to do the following:
1) Wait for a specified time, e.g. nothing (this is done via a TimerTask)
2) Request to focus via autoFocus
3) In autoFocus callback, request OneShotPreviewCallback
4) In preview callback, save image
5) Repeat
While the white balancing is working fine prior to the first autoFocus, it stops after the first focussing has been done. Well, of course I looked up the API, and there is one interesting statement in the autoFocus description.
But auto-focus routine may stop auto-exposure and auto-white balance transiently during focusing.
But it seems it is non stopped only transiently, but permantly. Funny enough, with the subsequent call of autoFocus, the camera tries to ajust the whitening again, but the correct value is mostly only with the second or third autoFocus.
I also tried to set the white balancing in code, but it didn't change anything.
setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
Does anyone else know this issue, or am I missing some point ? I know that I could permanently call autoFocus to force the white balancing, but that doesn't seem the optimal way for me, because prior to the first call auf autoFocus, it works perfectly fine.
P.S.: I'm testing on a Samsung Galaxy S2 with Android 4.0.3.
I have ran into similar issue on Samsung Galaxy 2 Duos 2. In this case, the auto exposure settings have stopped working instead of the WB. I tried to cycle (on/off) the auto exposure param and it worked for me.
mCamera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean b, Camera camera) {
Camera.Parameters params = camera.getParameters();
if (params.isAutoExposureLockSupported()) {
params.setAutoExposureLock(true);
camera.setParameters(params);
params = camera.getParameters();
params.setAutoExposureLock(false);
camera.setParameters(params);
}
}
});
I've got the similar problem on Samsung Galaxy Ace - after first autofocus, camera white balancing turns off and does not turn on again, no matter how much I do autofocus after.
As there are no API methods to tell camera to resume white balancing, and resetting the camera parameters in autofocus callback doesn't do the trick, my guess is that it is a bug in camera driver in Samsung phones - I've tried my application with different phones and only on this Samsung Galaxy Ace (GT-S5830; updated to Android 2.3.3), camera white balancing does not resume after autofocusing.
Maybe we should issue a bug ticket on developer.samsung.com?
It seems that
mCamera.stopPreview();
mCamera.startPreview();
in AutoFocusCallback can enable auto exposure again, but bringing a very short pause on the preview as side effect.
I am trying to get a camera preview with a color effect applied to it, such as for example the NEGATIVE effect. There are no errors, and the preview is visible without problems, but independent of the ColorEffect I set - the camera preview remains unchanged. I tested if the effects I am trying to use are available to my phone by running params.getSupportedColorEffects() (also these effects also work in the built in photo app).
I have no idea what is wrong with the code - I am posting it below. Perhaps someone here has an idea what could make this work? Thanks in advance.
public class CustomCameraView extends SurfaceView{
Camera mCamera;
SurfaceHolder mHolder;
public CustomCameraView(Context context){
super(context);
mHolder = this.getHolder();
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.addCallback(mSurfaceHolderListener);
}
SurfaceHolder.Callback mSurfaceHolderListener = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
mCamera=Camera.open();
try {
mCamera.setPreviewDisplay(mHolder);
}
catch (Exception e){ }
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{
Camera.Parameters params = mCamera.getParameters();
params.setColorEffect(Camera.Parameters.EFFECT_NEGATIVE);
mCamera.setParameters(params);
mCamera.startPreview();
}
public void surfaceDestroyed(SurfaceHolder arg0)
{
mCamera.stopPreview();
mCamera.release();
}
};
}
After some testing it turned out the problem could be related to the HTC Desire I was testing on (or maybe its OS version). The code works correctly on some other Samsung phones. I haven't figured out what could be the problem on the HTC.
UPDATE:
I have managed to get the effects working, but truly by accident, and I still don't understand why. But I will give the answer here - perhaps someone will find it useful, or maybe will be able to explain why it happens this way:
I added the following line to the surfaceChanged method because I was trying to decrease the size of the preview:
previewHolder.setFixedSize(width, height-1);
This had the result of making the selected effect visible.
When I changed this line to:
previewHolder.setFixedSize(width, height);
the effect was not visible any more once again. So odd.... it works for set height being anything less than the received height parameter.
I have been struggling with this as well. I found out that the HTC Desire its camera needs a strange order of executing the setParameters, setPreviewDisplay and startPreview for the color effect to work. The order is:
Camera.Parameters parameters = camera.getParameters();
//set the parameters
camera.setParameters(parameters);
camera.startPreview();
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceHolder);
Calling startPreview before setPreviewDisplay is documented in the Android SDK as a way of initializing the camera and the surfaceView in parallel.
Regarding your update about getting the effects to work by accident, the same happend to me! I assume for the same reason, some of my code got called twice in quick succesion (in my case due to a changing database object). This caused the method to (re)set the parameters and (re)start the preview to be called twice producing the desired result. After realising this and some more experimenting the above order seemed to work on both my HTC Desire and Acer Iconia A500 and I was quite happy with it.
However I have just received a comment for my application saying it produces corrupted images on the HTC Desire HD so I would recommend not using this order of camera initialization as a default but rather as a fix for the HTC Desire.
After setting new parameters to camera and starting preview invalidate() are calling on your SurfaceView . But it only Invalidate the whole view. If the view is visible, onDraw(android.graphics.Canvas) will be called at some point in the future. So there is no guarantees that onDraw() will be called immediately. But onDraw() are always invoking after calling onMeasure() with size differs from current. So it can be a reason of this odd behavior.
Simple answers use following type :
Camera camera = null;
camera = Camera.open();
if (camera != null) {
try {
Camera.Parameters parameters = camera.getParameters();
// Set all kind of stuffs here..
parameters.setSceneMode(Camera.Parameters.FLASH_MODE_AUTO);
parameters.setColorEffect(Camera.Parameters.EFFECT_SEPIA); // whatever effect you want
camera.setParameters(parameters);
camera.setPreviewDisplay(surface_holder);
camera.startPreview();
} catch (IOException exception) {
camera.release();
camera = null;
}
}
I have some trouble with the onAutoFocus callback of the Android Camera API. In the constructor of my Preview class I set the focus mode to FOCUS_MODE_AUTO and the flash mode to FLASH_MODE_AUTO. The button I present to the user to take a picture has a custom animation attached to it. When the user pressed the button, the animation starts and so does the auto focus:
public void onAnimationStart(Animation animation) {
isAutoFocusing = true;
AutoFocusCallBackImpl autoFocusCallBack = new AutoFocusCallBackImpl();
camera.autoFocus(autoFocusCallBack);
}
Then in the onAutoFocus method I take the picture:
public void onAutoFocus(boolean success, Camera camera) {
if (camera != null) {
try {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
} catch(Exception e) {
// If something went wrong, we return
// the user to the dashboard.
setResult(Constants.PICTURE_CAMERA_ERROR);
finish();
}
}
}
This works perfectly when there is enough light (so without the flash). In the dark however, the flash goes off and the picture is taken, but it appears that the camera did not focus properly. I know that the onAutoFocus callback is called immediately if auto focus isn't supported by the camera, but that clearly isn't the case here. Is auto focus impossible in the dark (even with the flash)?
This obviously is a hardware issue: To focus automatically, your device needs an image. No image (in the dark) -> no autofocus. There is no way for the camera to tell whether the image is sharp if there is no image, that's why focusing in the dark does not work.
That's why cameras (and I guess some android devices too) have a small light which gets switched on while focusing. But I guess most phones don't have this focus-light :/