diff options
author | Igor Murashkin <iam@google.com> | 2014-06-17 12:04:07 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2014-06-17 22:55:16 +0000 |
commit | 4961bc88d7bab869a5296789d26fcfa31ad5f644 (patch) | |
tree | 24fb63dc81e721826259c9d49c1b1dc715d0ec79 /core/java/android/hardware | |
parent | 5834ee75038e9095cefe089cdb26795b3ffe9e38 (diff) | |
download | frameworks_base-4961bc88d7bab869a5296789d26fcfa31ad5f644.zip frameworks_base-4961bc88d7bab869a5296789d26fcfa31ad5f644.tar.gz frameworks_base-4961bc88d7bab869a5296789d26fcfa31ad5f644.tar.bz2 |
camera2: Map camera characteristics in the managed layer
Change-Id: Ic86c8df3d703e7cf89caa856387e2c0a1b977401
Diffstat (limited to 'core/java/android/hardware')
4 files changed, 241 insertions, 9 deletions
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl index 4c50dda..31896f5 100644 --- a/core/java/android/hardware/ICameraService.aidl +++ b/core/java/android/hardware/ICameraService.aidl @@ -69,4 +69,9 @@ interface ICameraService * well-formatted in the generated java method. */ int getCameraVendorTagDescriptor(out BinderHolder desc); + + // Writes the camera1 parameters into a single-element array. + int getLegacyParameters(int cameraId, out String[] parameters); + // Determines if a particular API version is supported; see ICameraService.h for version defines + int supportsCameraApi(int cameraId, int apiVersion); } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 0901562..73188ff 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -19,8 +19,10 @@ package android.hardware.camera2; import android.content.Context; import android.hardware.ICameraService; import android.hardware.ICameraServiceListener; +import android.hardware.CameraInfo; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.legacy.CameraDeviceUserShim; +import android.hardware.camera2.legacy.LegacyMetadataMapper; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; import android.hardware.camera2.utils.BinderHolder; @@ -57,6 +59,10 @@ public final class CameraManager { private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; private static final int USE_CALLING_UID = -1; + @SuppressWarnings("unused") + private static final int API_VERSION_1 = 1; + private static final int API_VERSION_2 = 2; + private final ICameraService mCameraService; private ArrayList<String> mDeviceIdList; @@ -142,6 +148,9 @@ public final class CameraManager { synchronized (mLock) { mListenerMap.put(listener, handler); + + // TODO: fire the current oldest known state when adding a new listener + // (must be done while holding lock) } } @@ -185,16 +194,46 @@ public final class CameraManager { } } - CameraMetadataNative info = new CameraMetadataNative(); - try { - mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info); - } catch(CameraRuntimeException e) { - throw e.asChecked(); - } catch(RemoteException e) { - // impossible - return null; + int id = Integer.valueOf(cameraId); + + /* + * Get the camera characteristics from the camera service directly if it supports it, + * otherwise get them from the legacy shim instead. + */ + + if (!supportsCamera2Api(cameraId)) { + // Legacy backwards compatibility path; build static info from the camera parameters + String[] outParameters = new String[1]; + try { + mCameraService.getLegacyParameters(id, /*out*/outParameters); + String parameters = outParameters[0]; + + CameraInfo info = new CameraInfo(); + mCameraService.getCameraInfo(id, /*out*/info); + + return LegacyMetadataMapper.createCharacteristics(parameters, info); + } catch (RemoteException e) { + // Impossible + return null; + } catch (CameraRuntimeException e) { + throw e.asChecked(); + } + + } else { + // Normal path: Get the camera characteristics directly from the camera service + CameraMetadataNative info = new CameraMetadataNative(); + + try { + mCameraService.getCameraCharacteristics(id, info); + } catch(CameraRuntimeException e) { + throw e.asChecked(); + } catch(RemoteException e) { + // impossible + return null; + } + + return new CameraCharacteristics(info); } - return new CameraCharacteristics(info); } /** @@ -456,6 +495,53 @@ public final class CameraManager { } } + /** + * Queries the camera service if it supports the camera2 api directly, or needs a shim. + * + * @param cameraId a non-{@code null} camera identifier + * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise. + */ + private boolean supportsCamera2Api(String cameraId) { + return supportsCameraApi(cameraId, API_VERSION_2); + } + + /** + * Queries the camera service if it supports a camera api directly, or needs a shim. + * + * @param cameraId a non-{@code null} camera identifier + * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2} + * @return {@code true} if connecting will work for that device version. + */ + private boolean supportsCameraApi(String cameraId, int apiVersion) { + int id = Integer.parseInt(cameraId); + + /* + * Possible return values: + * - NO_ERROR => Camera2 API is supported + * - CAMERA_DEPRECATED_HAL => Camera2 API is *not* supported (thrown as an exception) + * + * Anything else is an unexpected error we don't want to recover from. + */ + + try { + int res = mCameraService.supportsCameraApi(id, apiVersion); + + if (res != CameraBinderDecorator.NO_ERROR) { + throw new AssertionError("Unexpected value " + res); + } + + return true; + } catch (CameraRuntimeException e) { + if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) { + return false; + } else { + throw e; + } + } catch (RemoteException e) { + throw new AssertionError("Camera service unreachable", e); + } + } + // TODO: this class needs unit tests // TODO: extract class into top level private class CameraServiceListener extends ICameraServiceListener.Stub { diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java new file mode 100644 index 0000000..8bb066f --- /dev/null +++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.legacy; + +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.hardware.Camera.CameraInfo; +import android.hardware.Camera.Size; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.params.StreamConfiguration; +import android.hardware.camera2.params.StreamConfigurationDuration; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import static com.android.internal.util.Preconditions.*; +import static android.hardware.camera2.CameraCharacteristics.*; + +/** + * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the + * camera characteristics. + */ +public class LegacyMetadataMapper { + private static final String TAG = "LegacyMetadataMapper"; + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + + // from graphics.h + private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; + private static final int HAL_PIXEL_FORMAT_BLOB = 0x21; + + /** + * Create characteristics for a legacy device by mapping the {@code parameters} + * and {@code info} + * + * @param parameters A string parseable by {@link Camera.Parameters#unflatten} + * @param info Camera info with camera facing direction and angle of orientation + * @return static camera characteristics for a camera device + * + * @throws NullPointerException if any of the args were {@code null} + */ + public static CameraCharacteristics createCharacteristics(String parameters, + android.hardware.CameraInfo info) { + checkNotNull(parameters, "parameters must not be null"); + checkNotNull(info, "info must not be null"); + checkNotNull(info.info, "info.info must not be null"); + + CameraMetadataNative m = new CameraMetadataNative(); + + mapCameraInfo(m, info.info); + + Camera.Parameters params = Camera.getEmptyParameters(); + params.unflatten(parameters); + mapCameraParameters(m, params); + + if (VERBOSE) { + Log.v(TAG, "createCharacteristics metadata:"); + Log.v(TAG, "--------------------------------------------------- (start)"); + m.dumpToLog(); + Log.v(TAG, "--------------------------------------------------- (end)"); + } + + return new CameraCharacteristics(m); + } + + private static void mapCameraInfo(CameraMetadataNative m, CameraInfo i) { + m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ? + LENS_FACING_BACK : LENS_FACING_FRONT); + m.set(SENSOR_ORIENTATION, i.orientation); + } + + private static void mapCameraParameters(CameraMetadataNative m, Camera.Parameters p) { + mapStreamConfigs(m, p); + + // TODO: map other fields + } + + private static void mapStreamConfigs(CameraMetadataNative m, Camera.Parameters p) { + // TODO: set non-empty durations + m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[] {} ); + m.set(SCALER_AVAILABLE_STALL_DURATIONS, new StreamConfigurationDuration[] {} ); + + ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>(); + /* + * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes + * YUV_420_888 cpu callbacks -> use camera1 preview sizes + * Other preview callbacks (CPU) -> use camera1 preview sizes + * JPEG still capture -> use camera1 still capture sizes + * + * Use platform-internal format constants here, since StreamConfigurationMap does the + * remapping to public format constants. + */ + List<Size> previewSizes = p.getSupportedPreviewSizes(); + appendStreamConfig(availableStreamConfigs, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes); + appendStreamConfig(availableStreamConfigs, + ImageFormat.YUV_420_888, previewSizes); + for (int format : p.getSupportedPreviewFormats()) { + if (ImageFormat.isPublicFormat(format)) { + appendStreamConfig(availableStreamConfigs, format, previewSizes); + } else { + /* + * Do not add any formats unknown to us + * (since it would fail runtime checks in StreamConfigurationMap) + */ + Log.w(TAG, + String.format("mapStreamConfigs - Skipping non-public format %x", format)); + } + } + appendStreamConfig(availableStreamConfigs, + HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes()); + m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + availableStreamConfigs.toArray(new StreamConfiguration[0])); + } + + private static void appendStreamConfig( + ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) { + for (Camera.Size size : sizes) { + StreamConfiguration config = + new StreamConfiguration(format, size.width, size.height, /*input*/false); + configs.add(config); + } + } +} diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java index 40cda08..898c746 100644 --- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java +++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java @@ -47,6 +47,8 @@ public class CameraBinderDecorator { * - POLICY_PROHIBITS * - RESOURCE_BUSY * - NO_SUCH_DEVICE + * - NOT_SUPPORTED + * - TOO_MANY_USERS */ public static final int EACCES = -13; public static final int EBUSY = -16; |