Surfaceview using Mobile Vision Displays the Camera in Landscape - android

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();
}
}

Related

How to automatically turn on flashlight for video recording when the scene is dark?

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: ");
}
}

How to save camera instance?

How to save the state of the camera so when i close the screen and turn it on again the camera gets back to its previous state.Should i bundle it?
public void getCamera() {
if (camera == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
Log.e(e.getMessage(), "Camera Error. Failed to Open. Error:Application will close! ");
finish();
}
}
}
Generally you don't want to do this- you want to release the camera in onPause and recapture it in onResume so other apps can use it as well.

What are all the automatic parameters of android's camera2 API

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();
}
}

How to set the camera light on torch in Tokbox?

I am using TokBox for an android project. I need to add a button which would turn the flash light on torch mode.
Tokbox Publisher object already provides a swapCamera() method which switches between all the available cameras of the device. But I couldn't find any API to change the flash light mode for the currently selected camera.
I tried getting an instance of android.hardware.Camera myself to change it manually, but it didn't work because I got the "java.lang.RuntimeException: Fail to connect to camera service" exception. It is because the Camera object is being used by Tokbox and is not released.
I could find no way to access the Camera instance that Tokbox is using either. It is even deprecated since android API level 21.
Can anyone suggest a way to change the camera parameters? I have access to the View that the video is being previewed on it.
I needed to stop the stream to be able to start the camera app to take a picture. I've found code to release the camera and attach it. Maybe you can use this code to release the camera, turn on the light and then attach the camera again
The following code releases the camera:
public void ReleaseCamera()
{
if (_myPub != null) {
_myPub.PublishVideo = false;
BaseVideoCapturer bvc = _myPub.Capturer;
if (bvc != null) {
bvc.StopCapture ();
bvc.Destroy ();
}
}
}
And this code attaches the camera again:
public void AttachCamera()
{
if (_myPub != null) {
BaseVideoCapturer bvc = _myPub.Capturer;
if (bvc != null) {
if (bvc.IsCaptureStarted == false) {
bvc.Init ();
bvc.StartCapture ();
_myPub.PublishVideo = true;
}
}
}
}
torch light will work only with back camera, so if you are publishing video with front camera then it will freez tokbox video.
if(publisher.cameraPosition == .back){
if let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo), device.hasTorch {
do {
try device.lockForConfiguration()
let torchOn = !device.isTorchActive
try device.setTorchModeOnWithLevel(1.0)
device.torchMode = torchOn ? .on : .off
device.unlockForConfiguration()
} catch {
print("error")
}
}
}

Switching cameras for video on the fly on android

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

Categories

Resources