In API level 9, Android added the CameraInfo class, which includes information on each physical camera in the device. In particular, it includes an orientation attribute, which is "the angle that the camera image needs to be rotated clockwise so it shows correctly on the display in its natural orientation." This is distinct from the actual rotation of the device, which is found from getContext().getWindowManager().getDefaultDisplay().getRotation().
Android's sample code subtracts the rotation of the device from the orientation of the camera for rear-facing cameras (it's slightly more complicated for front-facing ones), and rotates the camera preview by this amount. This allows the preview to display properly in both portrait and landscape orientations of the screen.
How can I get the intrinsic orientation of the camera in API levels less than 9, where there is no CameraInfo class?
There is some platform specific solutions. But there is no easy general solution.
Android has a Hardware Abstract Layer(HAL), different vendors will implement the HAL differently. For example, different camera device may have different drivers, so they have different ways to get their data out, including your cameraInfo. When Android adds an API into the HAL, it requires its vendors to implement that API based on their hardwares. Then the Android framework and Android application can use that feature in a uniform way.
However, as you said, the getCameraInfo is not in the HAL Before Froyo. So a straightforward approach would be get those info from the driver or platform-specific library yourself.
For MSM Camera, there is a mm_camera_get_camera_info function in liboemcamera.so. You can use it to get a list of camera_info_t structs.
typedef struct {
int modes_supported;
int8_t camera_id;
cam_position_t position;
uint32_t sensor_mount_angle;
}camera_info_t;
The function encapsulates the actual system call to the target camera device. ioctl(controlfd, MSM_CAM_IOCTL_GET_CAMERA_INFO, &cameraInfo). You may directly call it if you like.
So unfortunately, you need to get that info based on the device you are working on. But may be you are expecting a general approach. Then I think the only way to achieve this is to implement the HAL yourself. Many if-else to decide which device or which ioctl command you need to use. Good luck man.
Related
So I have different Samsung devices (up to S22 Ultra) and it is very easy to access ultra wide lens camera because CameraManager.cameraIdList returns 4 cameras which includes general back lens camera and ultra wide lens camera as well.
But many other devices (Xiaomi, Vivo and many others) return only two general cameras - back and front.
Some users of my apps said that they are able to use ultra wide lens camera with apps like mcpro24fps and gcam. One user with Xiaomi POCO X3 (Android 11)
How do such apps can access all cameras?
Also Camera2 API usually returns that video stabilization is not supported (manufacture doesn't exposes it within this api)
val characteristics = getCameraCharacteristics(context, cameraIdx)
val modes =
characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)
?: intArrayOf()
val supported = CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON in modes
supported usually false but even if it returns true for some devices it seems it still doesn't really do any video stabilization and there is no any crop at the frames, no effect basically, based on users responses of my app
so the following code doesn't change anything if camera2 api returns that video stabilization is supported:
if (isVideoStabilizationSupported()) {
captureRequestBuilder.set(
CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON
)
but again mcpro24fps and gcam supports this as well but it seems mb a custom solution but I don't really understand how you can implement something custom with camera2 API without effecting performance, because it has to implemented on low level
Update Mb such apps can access ultra wide lens camera by using new zoom ratio camera parameter:
captureRequestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, 0.6f)
It works for my Samsung devices, 0.6...10 zoom ratio. So can switch between lens without changing camera id
The long-term goal for Android's camera APIs is that multi-camera clusters (such as a combination of ultrawide/wide/tele cameras) can be used by applications without having to specially code for it.
That's done via the logical multi-camera APIs. When implemented, that means there'll be one logical camera, composed of two or more physical cameras. What you see in the camera ID list is the logical camera, and you can also get the list of the physical cameras from CameraCharacteristics#getPhysicalCameraIds(). With this arrangement, you can see extended zoom ranges such as what you mention ( 0.6 ... 10), and the camera implementation will automatically switch to the ultrawide or telephoto cameras when you zoom out or zoom in. That's subject to various other conditions; for example, most telephoto lenses can't focus very close, so if you zoom in while focused on a nearby object, the camera will likely stay with the default wide camera; similarly tele cameras are often worse in low light, so digital zoom may result in better quality than optical zoom plus more amplification.
If you have a particular reason to use the underlying uw/wide/tele camera, you can include them in the stream configuration via setPhysicalCameraId() and use them directly; that lets you force which camera is streamed from if you want to provide a 'use telephoto' button in your UI, instead of letting the logical camera try to use its best judgement to select the active camera.
Unfortunately, not all devices have migrated to the logical camera API; those devices might be listing the multi-camera clusters as individual camera IDs as you've seen, or may just hide some cameras from apps entirely. The main problem with this is that it requires an app to do extra work to just zoom out/in with best quality, and the variety of implementations makes it hard to code up in an app so that it works on all devices.
I am trying to figure out the limitations of using camera2 with devices that have hardware level support LEGACY. From the official docs for android camera2 api:
LEGACY: These devices expose capabilities to apps through the Camera API2 interfaces that are approximately the same capabilities as those exposed to apps through the Camera API1 interfaces. The legacy frameworks code conceptually translates Camera API2 calls into Camera API1 calls; legacy devices do not support Camera API2 features such as per-frame controls.
I have found this to be false... In fact I expected that sensor orientation obtained through Camera.CameraInfo camInfo -> camInfo.orientation (docs) would be the same as cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) (docs)
However it is not the case!
Camera API 1 returns an orientation angle of 90°
Camera API 2 returns an orientation angle of 270°
Notice that this is quite different! Landscape orientation != inverse landscape orientation! For example it would completely break the Matrix transformation from the screen preview coordinates to the camera sensor space.
Am I missing something? Is this intended behaviour?
I am using a Xiaomi Redmi 5 plus with Android 8.1 (is this a manufacturer issue?)
Thanks
If the two queries apply to the same camera, this is definitely a bug, and Xiaomi is responsible. Bugs do happen even on mainstream devices, and the camera API adaptation layers tend to be more buggy than other APIs.
You may find that for LEGACY devices, camera2 layer introduces extra overhead, and vice versa. You get best performance if you work trhough the deprecated Camera API for LEGACY devices, and through the camera2 API for other devices. I know it's painful to support two versions of your code, but when you need to utilize the device in the best way, you have to pay this price.
When Android 9(API 28) was released, I was very happy to discover that the physical cameras of the phones with multiple cameras would be exposed, I had been very frustrated to not be able to access them. Today I stumbled upon the android Q documentation which says:
Starting from API level 29, some or all physical cameras may not be independently exposed to the application, in which case the physical camera IDs will not be available in CameraManager.getCameraIdList(). But the application can still query the physical cameras' characteristics by calling CameraManager.getCameraCharacteristics(String).
This statement confuses me, does it mean that Android is backtracking? what's the purpose of the change?
I'm interested in managing cameras at a very fine level, will this change prevent me from doing what I'm able to do today with Android 9?
It says that the IDs may not be listed any more but that the characteristics can still be queried, how are we supposed to get the characteristics of cameras without having their IDs? I guess we are supposed to get the physical cameras' IDs via getPhysicalCameraIds() on logical cameras, but does it means that if we wanted to use a "hidden" camera, we'd have to test a bunch of random ID strings?
And will we still be able to create capture sessions with SessionConfiguration on physical cameras that are not exposed?
Can someone shed some light on this?
I tried to open camera using physical ids of first logical back camera of Pixel 5 (Android 11) but it failed with error: unknown camera id....
So Pixel 5 returns only 2 logical camera ids and only those 2 cameras can be opened using cameraManager.openCamera(...) method...
Samsung S10 (also Android 11) returns 4 logical camera ids and doesn't have any physical camera ids for all those logical cameras, all 4 cameras can be used without any problem.
Pixel 5 camera info:
Samsung S10 camera info:
Though for Pixel 5 I didn't try setPhysicalCameraId(cameraId) https://developer.android.com/reference/android/hardware/camera2/params/OutputConfiguration.html#setPhysicalCameraId(java.lang.String)
I think this method can be used to switch between different physical camera (for example we can open wide lens camera)
Update
Yes we can use setPhysicalCameraId method with Pixel 4, 5 (and I guess there more devices and manufactures) to set specific physical camera
So logic is the next:
you open camera using logical camera id using camera manager
then if that logical camera supports multi camera feature then it should have non empty physical camera id list
you can choose any id from physical camera id list and set it to OutputConfiguration:
val outputs = surfaces.map {
OutputConfiguration(it).apply {
setPhysicalCameraId(cameraIdx)
}
}
cameraDevice.createCaptureSessionByOutputConfigurations(
outputs,
stateCallback,
backgroundCameraHandler
)
UPDATE! WARNING! but it previews the same view, so it seems this method doesn't work (though there is no exception), nothing is changed, whether you set physical camera or not
Seems it's broken starting from Android 10 - Android 10 (api 29) camera2 api regression with wide-angle camera
Update
I also tried to create capture session using SessionConfiguration object instead of deprecated method createCaptureSessionByOutputConfigurations
val config = SessionConfiguration(
SessionConfiguration.SESSION_REGULAR,
outputs,
backgroundCameraExecutor!!,
stateCallback
)
cameraDevice.createCaptureSession(config)
But still nothing is changed
This is not backtracking. Actually, this generalization is an important step to provide you with better control of complex camera setups.
Before API 29, if the manufacturer could not provide separate cameraDevice for each of the lenses that constitute a composite camera, they had no way to expose the lens parameters to the developer. Their only choice was to expose the composite camera as whole.
The question is not
And will we still be able to create capture sessions with SessionConfiguration on physical cameras that are not exposed?
but rather,
And now we can read the characteristics of physical cameras that could not be exposed before‼
With the new change, the manufacturer can give you all available info on "Back camera1", "Back camera2", etc. even if there is no way to start separate capture sessions on them.
getPhysicalCameraIds() reference explains:
Prior to API level 29, all returned IDs are guaranteed to be returned by CameraManager.getCameraIdList(), and can be opened directly by CameraManager.openCamera(). Starting from API level 29, for each of the returned ID, if it's also returned by CameraManager.getCameraIdList(), it can be used as a standalone camera by CameraManager.openCamera(). Otherwise, the camera ID can only be used as part of the current logical camera.
This means that you can use any id returned by getPhysicalCameraIds() in CameraManager.getCameraCharacteristics(id):
From API level 29, this function can also be used to query the capabilities of physical cameras that can only be used as part of logical multi-camera. These cameras cannot not be opened directly via openCamera(String, CameraDevice.StateCallback, Handler).
I am working on an app where I have a camera preview and I take pictures in dark settings. Therefore, I need a way to manually control the exposure time of the camera and the settings of shutter speed, aperture, and iso.
I know it must be possible because the application Long Exposure Camera 2 (by AAASDream) has a way to manually change the exposure time and it works perfectly. I am not referring to the exposurecompensation which I already tried but was not sufficient enough.
Based off of this post, I tried setting
Camera.Parameters params = camera1.getParameters();
params.set("mode", "m");
params.set("aperture", 80);
params.set("shutter-speed", 9);
params.set("iso", 1600);
But this did not work at all.
Is there any hidden API or setting that I can use or any third party library I can use to accomplish this.
All help is appreciated, thanks.
I think there is no way to manually set the above mentioned values in android.hardware.camera. But it looks like the new version android.hardware.camera2 supports those functionalities.
Yes, it isn't possible to manually set one of the two mentioned parameters directly via the Camera 1 API. Neither the characteristics can be queried via a standardized method, because it isn't supported.
Of course there is a way around, to query or to set such properties via special methods, as relime9 currently mentioned:
// query all the settings you camera support (API 1)
mCamera.getParameters().flatten();
// set parameters - e.g. aperture
mCamera.getParameters().set("aperture", "80");
Additionally the specific device must support such a setting, which vary from device to device. On some devices there can be set certain values and with other you can't and can only use the ''auto'' mode.
For this reason they developed the Camera 2 API, which is more standardized and supports such functionalities.
I have an HTC One M8, and I have flashed cyanogen to it.
I am using it for testing some cameras that attach via the micro USB port.
When testing applications they seem to have a preference for front or rear, not a camera list, and assuming that different device models have different camera models, features, etc, I can only assume android provides some abstraction level between direct accessing the camera and the application. Furthermore is seems safe to assume that somewhere that is configured as front or rear respectively.
So the question is can that be edited, for instance a device has an internal camera that does not have the feature or resolution I need, can I plug one into the USB port, and change a configuration somewhere that says "when an application requests the rear camera, give it this one?"
Essentially can you edit somewhere what CAMERA_FACING_FRONT and CAMERA_FACING_BACK refers to on a hardware level?
I have looked and not be able to find much, and I do not compile my own android ROMS, so I am afraid it may end up being one of the reason ROMs are device specific because this is compiled into the OS and coded specifically for the camera native to that device, therefor not configurable, however if someone could nudge me in the correct direction that would be great.
Example, http://developer.android.com/training/camera/cameradirect.html states a call to open() on the Camera object returns the first rear facing camera. Something somewhere has instructed android what that camera is and that it is facing rear. It is specifically that configuration point I want to see if I can pick up and redirect. an example of why, I have an application that given the known size of something in the field of the camera, it can accurately measure distance to that object, it only does it through the rear camera, I want to try to make it do it through the thermal camera.
The third camera works fine on the device, and its native app consistently finds it (albeit not sure how or if it is a specific protocol over USB, driver, etc...)
It appears the setting I am looking for is defined in the HAL https://source.android.com/devices/camera/index.html#implementing
camera_common.h defines an important struct, camera_module, which
defines a standard structure to obtain general information about the
camera, such as its ID and properties that are common to all cameras
such as whether or not it is a front or back-facing camera.
Since this is modified in the header file and compiled into the kernel, then without hacking the ROM it would appear it is simply NOT configurable at any level outside a custom ROM.
Id est, I will never force another app into the camera of my choosing unless I choose to build a ROM to do it or without overly invasive hacking at the running ROM :-(