I'm developing a camera app using the Android camera2 API, And I need the camera to have always the same configuration, like focus, white balance, exposure, etc.
I already disabled AF, AE and AWB, but it still seems to automatically set the white balance. I was wondering if is there some other automatic configuration I should disable.
I didn't find anything like it on Google.
i just ran into the same issue... In my case it turned out, that there was a function in the template i was using, which reset the control mode to automatic.
protected void updatePreview() {
if(null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Related
My app shows a preview and video recording starts with a button press.
What I'm trying to achieve is to automatically turn on flashlight (torch mode) as soon as the video recording starts.
However I couldn't find a way to do so. On Camera2 API we can use FLASH_MODE_AUTO which will use the flashlight when capturing photo when the scene is dark, but that doesn't work for video recording.
There's this FLASH_MODE_TORCH which I could use to turn on the flashlight just like I wanted, but there isn't a FLASH_MODE_TORCH_AUTO to automatically do so when the scene is dark..
There were some answers that uses Ambient light sensor (Sensor.TYPE_LIGHT) of the device to determine whether we are in a dark scene, however that uses the front ambient light sensor instead of the camera itself I think. This is not ideal as the ambient light can be low but the rear camera is able to adjust exposure level to achieve good enough image quality without using flash. So ideally if the camera says 'flash is required' then only the app activates FLASH_MODE_TORCH.
Since the app shows a preview the device already know whether flash is needed before the button press, is there a way to determine whether flash is required during preview?
Please try the below method where you need you can use it
below is for Camera API
public void switchFlashOnMode() {
Camera.Parameters p = getCamera().getParameters();
try {
//p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
p.setFlashMode(Parameters.FLASH_MODE_AUTO);
getCamera().setParameters(p);
getCamera().startPreview();
isFlashTorch = true;
}catch (Exception e){
e.printStackTrace();
}
}
public void switchFlashOffMode() {
Camera.Parameters p = getCamera().getParameters();
try {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
getCamera().setParameters(p);
Thread.sleep(200);
getCamera().stopPreview();
isFlashTorch = false;
}catch (Exception e){
e.printStackTrace();
}
}
below is for Camera2 API
void switchFlashMode() {
if (!flashSupport) return;
try {
if (isFlashTorch) {
isFlashTorch = false;
requestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
} else {
isFlashTorch = true;
//requestBuilder.set(CaptureRequest.FLASH_MODE,CameraMetadata.FLASH_MODE_TORCH);
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
cameraCaptureSession.setRepeatingRequest(requestBuilder.build(), null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
hope it will help you
Finally figured this out, gpuser's answer used the right flag but it is not complete - still need to code the callback and turn on the torchlight when needed.
I also found that for video recording, we still use the same Camera2 API init and configuration steps, just that some of the callbacks will be fired multiple times, so I added a flag to perform the flash detection only once.
1)After camera started capturing, run this code
performAutoTorchDetectionOnce = true; // set this flag first, will be used later
captureRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // CONTROL_AE_MODE_ON_AUTO_FLASH is important here, to enable flash detection
captureSession.setRepeatingRequest(captureRequestBuilder.build(), captureCallback, null);
2)And this is my captureCallback implementation, change it depending on your needs. The gist of it is that eventually the camera capture will fall into one of the two states, CONTROL_AE_STATE_CONVERGED or CONTROL_AE_STATE_FLASH_REQUIRED. These two states mean that auto exposure algorithm has finished running, if it is converged means no flash is needed whereas flash_required will mean that we have to turn on flash. In the latter we will then need to manually turn on the flash in the next step.
private CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState != null) {
if (performAutoTorchDetectionOnce) {
if (aeState == CameraMetadata.CONTROL_AE_STATE_CONVERGED // CONTROL_AE_STATE_CONVERGED means Auto-exposure has finished
|| aeState == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED) { // CONTROL_AE_STATE_FLASH_REQUIRED means Auto-exposure has finished, but flash is required
performAutoTorchDetectionOnce = false;
enableTorch(aeState == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED);
}
}
}
}
};
3)Here's the enableTorch implementation. I tried leaving CONTROL_AE_MODE as CONTROL_AE_MODE_ON_AUTO_FLASH but it didn't work, torch light does not turn on, so I have to change it to CONTROL_AE_MODE_ON.
public synchronized void enableTorch(boolean enable) {
Timber.d("enableTorch(" + enable + ") called");
try {
if (isCaptureStarted()) {
if (enable) {
captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
} else {
captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
}
} catch (CameraAccessException e) {
Timber.e(e, "enableTorch(" + enable + ") failed: ");
}
}
I want to capture pictures through Camera2 API, and I need to control the exposure time. But when I set CameraDevice.TEMPLATE_MANUAL or just set the exposure time, I get black picture. When I cancel the setting, I can get the right picture again.
The following is my setting code.
// if the phone's level is full or other which can control mannually
mCaptureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CONTROL_AE_MODE_OFF);
mCaptureRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureValue);
mCaptureRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, isoValue);
mCaptureRequestBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION,valueFrame);
//exposureValue and isoValue and valueFrame is valid.
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
Log.e(TAG, "onConfigured: startPreview");
mPreviewCaptureSession = session;
try {
mPreviewCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Log.e(TAG, "onConfigureFailed: startPreview");
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
After setting like above, when I capture a picture or save the preview frame, I can just get a black picture. But when I cancel the manual setting, I can save the picture.
I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
I need to set up CONTROL_SCENE_MODE_ACTION for my app camera2API.
i tryed to set it captureStillPicture() method then in lockFocus() method then in stateCallback but is doesn't work...
In documentation i found only explanation what it is, but any lines how this mode have to be set up...
There are 2 question:
Where exacly i have to set up this mode
How i can check that it is working
Or maybe you can suggest me how to reduse expose time...
Thanks in advance
You can modify Camera2BasicFragment from Google Camera2Basic sample by add line
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CaptureRequest.CONTROL_SCENE_MODE_ACTION);
just after line
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
in onConfigured() method of example
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
CaptureRequest.CONTROL_SCENE_MODE_ACTION);
// Flash is automatically enabled when necessary.
setAutoFlash(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
I am using SurfaceView and Google's Mobile Vision library. For many devices it looks fine but when using with few devices like Nexus 7 the camera view comes in Landscape mode. Which makes it difficult for Scanning barcodes etc as it is difficult to focus and position correctly.
In Vision library as I have explored there is no method such that they return the hardware camera so we can manage the orientation like if the camera view returns landscape then we can dynamically rotate the view to make it look like portrait.
So wanted to ask if there is any way for Devices like Nexus 7 to change the Camera or View to Portrait.
Any help will be welcomed! Thanks
Many tabs has their camera mounted rotated, so that when held horizontally, the picture will be taken as "portrait", even though the image is actually wider than it is high.
I learned it the hard way, on an app i built some time ago. The only way was to check the screen-aspect vs the image-aspect and image rotation.
By comparing these, you can infer whether a camera image is rotated correctly, or whether it needs a 90 degree post-rotation.
I found a solution for myself getting an idea from this persons answer:
https://stackoverflow.com/a/41634379/5028531
So what I did:
cameraPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
try {
cameraSource.start(cameraPreview.getHolder());
Field[] declaredFields = CameraSource.class.getDeclaredFields();
for (Field field : declaredFields) {
if (field.getType() == Camera.class) {
field.setAccessible(true);
try {
Camera camera = (Camera) field.get(cameraSource);
if (camera != null) {
Camera.Parameters params= camera.getParameters();
camera.setDisplayOrientation(0);
}
} catch (IllegalAccessException | RuntimeException e) {
e.getMessage();
}
break;
}
}
} catch (IOException e) {
Log.e("CAMERA SOURCE", e.getMessage());
e.printStackTrace();
}
} else {
Log.w("CAMERA SOURCE", "Permission not granted");
Toast.makeText(getActivity(), "Camera permission denied", Toast.LENGTH_SHORT).show();
}
}
I know it is possible as the camera app that comes with my droid phone does it, but for the life of me, I don't seem to be able to switch cameras on the fly either for video or a standard camera (which leads me to suspect I'm not doing it right!)
Currently, I have an event for the button
btnSwitchCamera.Click += new EventHandler(btnSwitchCamera_Click);
prior to that, I check for the number of cameras - if there is only one camera, the event is not enabled.
The switch code looks like this
private void btnSwitchCamera_Click(object s, EventArgs e)
{
if (isBackCamera == false)
{
try
{
RunOnUiThread(delegate
{
camera.Release();
camera = Android.Hardware.Camera.Open(1);
});
}
catch (Java.Lang.RuntimeException)
{
alertMsg(context, Application.Context.Resources.GetString(Resource.String.videoErrorTitle),
Application.Context.Resources.GetString(Resource.String.videoFailToConnect));
return;
}
isBackCamera = true;
}
else
{
try
{
RunOnUiThread(delegate
{
camera.Release();
camera = Android.Hardware.Camera.Open(0);
});
}
catch (Java.Lang.RuntimeException)
{
alertMsg(context, Application.Context.Resources.GetString(Resource.String.videoErrorTitle),
Application.Context.Resources.GetString(Resource.String.videoFailToConnect));
return;
}
isBackCamera = false;
}
}
If I click the button, the app dies claiming that I cannot connect to the service.
The video record code is nothing special - it's a bog standard set the surface, do the holder, and start/stop recording.
Am I doing this right? From the docs, I need to release the camera then open the camera with the appropriate camera number (Android.Hardware.Camera.NumberOfCameras - 1)
The manifest is correctly set.
Thanks
Paul