summaryrefslogtreecommitdiff
path: root/camera2/extensions/service_based_sample/extensions_service/src/com
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2023-03-15 04:18:00 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-15 04:18:00 +0000
commitd9af75e9404044bd50059b043f8f54ab2c19fa46 (patch)
treece783772c791f8c33ec2bd464176cbdfac04d403 /camera2/extensions/service_based_sample/extensions_service/src/com
parent854f3bf6040c3ff50c4819664734f48f86c36fa4 (diff)
parent48f538570bd87f9aa26fc71ce2fcfd57bbbd66c2 (diff)
downloadex-d9af75e9404044bd50059b043f8f54ab2c19fa46.tar.gz
Merge "Add service-based Camera Extensions reference implementation" am: 7d3c8a1ff8 am: 48f538570b
Original change: https://android-review.googlesource.com/c/platform/frameworks/ex/+/2446164 Change-Id: Ie91d26a73c03d92bc20598f8d6c7b36330126bed Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'camera2/extensions/service_based_sample/extensions_service/src/com')
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java270
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java95
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java70
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java71
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java383
5 files changed, 889 insertions, 0 deletions
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java
new file mode 100644
index 00000000..a10c1659
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2023 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 com.android.oemextensions;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AdvancedExtenderImplStub extends IAdvancedExtenderImpl.Stub {
+ private static final String TAG = "AdvancedExtenderStub";
+ private Context mContext;
+ private int mExtensionType;
+ private String mCurrentCameraId;
+ private Map<String, CameraCharacteristics> mCharacteristicsMap = new HashMap<>();
+
+ /**
+ * Construct the AdvancedExtenderImplStub instance.
+ *
+ * @param context a context.
+ * @param extensionType CameraExtensionCharacteristics#EXTENSION_AUTOMATIC for Auto,
+ * CameraExtensionCharacteristics#EXTENSION_NIGHT for Night,
+ * CameraExtensionCharacteristics#EXTENSION_HDR for HDR,
+ * CameraExtensionCharacteristics#EXTENSION_BOKEH for Bokeh,
+ * CameraExtensionCharacteristics#EXTENSION_FACE_RETOUCH for face retouch.
+ */
+ public AdvancedExtenderImplStub(@NonNull Context context, int extensionType) {
+ mContext = context;
+ mExtensionType = extensionType;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId) throws RemoteException {
+ return true;
+ }
+
+ @Override
+ public void init(@NonNull String cameraId) throws RemoteException {
+ mCurrentCameraId = cameraId;
+ }
+
+ @Override
+ @NonNull
+ public LatencyRange getEstimatedCaptureLatencyRange(@NonNull String cameraId,
+ @NonNull androidx.camera.extensions.impl.service.Size outputSize,
+ int format) throws RemoteException {
+ Log.d(TAG, "getEstimatedCaptureLatencyRange format" + format);
+
+ LatencyRange latencyRange = new LatencyRange();
+ latencyRange.min = 100;
+ latencyRange.max = 1000;
+ return latencyRange;
+ }
+
+ private CameraCharacteristics getCameraCharacteristics(String cameraId) {
+ CameraCharacteristics characteristics = mCharacteristicsMap.get(cameraId);
+ if (characteristics != null) {
+ return characteristics;
+ }
+ try {
+ CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
+ characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ mCharacteristicsMap.put(cameraId, characteristics);
+ return characteristics;
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Cannot get CameraCharacteristics", e);
+ return null;
+ }
+ }
+
+ private static SizeList getSupportedSizeByFormat(
+ CameraCharacteristics cameraCharacteristics, int imageFormat) {
+ StreamConfigurationMap streamConfigMap =
+ cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ Size[] sizes = streamConfigMap.getOutputSizes(imageFormat);
+ SizeList sizeList = new SizeList();
+ sizeList.sizes = new ArrayList<>();
+ for (Size size : sizes) {
+ androidx.camera.extensions.impl.service.Size sz =
+ new androidx.camera.extensions.impl.service.Size();
+ sz.width = size.getWidth();
+ sz.height = size.getHeight();
+ sizeList.sizes.add(sz);
+ }
+ sizeList.format = imageFormat;
+ return sizeList;
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedPreviewOutputResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics == null) {
+ return Collections.emptyList();
+ }
+
+ return Arrays.asList(
+ getSupportedSizeByFormat(cameraCharacteristics, ImageFormat.PRIVATE));
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedCaptureOutputResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(
+ getSupportedSizeByFormat(cameraCharacteristics,
+ ImageFormat.JPEG),
+ getSupportedSizeByFormat(cameraCharacteristics,
+ ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedYuvAnalysisResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics == null) {
+ return Collections.emptyList();
+ }
+
+ return Arrays.asList(
+ getSupportedSizeByFormat(cameraCharacteristics, ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ @NonNull
+ public ISessionProcessorImpl getSessionProcessor() throws RemoteException {
+ Log.d(TAG, "getSessionProcessor");
+ return new SimpleSessionProcessorStub(getCameraCharacteristics(mCurrentCameraId),
+ getSupportedCaptureRequestKeys(mCurrentCameraId).keySet(),
+ getSupportedCaptureResultKeys(mCurrentCameraId).keySet());
+ }
+
+ private Map<CaptureRequest.Key, Object> getSupportedCaptureRequestKeys(String cameraId) {
+ Map<CaptureRequest.Key, Object> map = new HashMap<>();
+ map.put(CaptureRequest.CONTROL_ZOOM_RATIO,
+ 1.0f /* don't care, must not be null */);
+ map.put(CaptureRequest.SCALER_CROP_REGION,
+ new Rect() /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AE_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AWB_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureRequest.JPEG_QUALITY,
+ (byte)0 /* don't care, must not be null */);
+ map.put(CaptureRequest.JPEG_ORIENTATION,
+ 0 /* don't care, must not be null */);
+ if (isAfAutoSupported(cameraId)) {
+ Log.e("AAAAA", "support AF: cameraid=" + cameraId);
+ map.put(CaptureRequest.CONTROL_AF_TRIGGER,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AF_MODE,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AF_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ }
+ return map;
+ }
+
+ private Map<CaptureResult.Key, Object> getSupportedCaptureResultKeys(String cameraId) {
+ Map<CaptureResult.Key, Object> map = new HashMap<>();
+ map.put(CaptureResult.CONTROL_ZOOM_RATIO,
+ 1.0f /* don't care, must not be null */);
+ map.put(CaptureResult.SCALER_CROP_REGION,
+ new Rect() /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AE_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AWB_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.JPEG_QUALITY,
+ (byte)0 /* don't care, must not be null */);
+ map.put(CaptureResult.JPEG_ORIENTATION,
+ 0 /* don't care, must not be null */);
+ if (isAfAutoSupported(cameraId)) {
+ map.put(CaptureResult.CONTROL_AF_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_TRIGGER,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_MODE,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_STATE,
+ 0 /* don't care, must not be null */);
+ }
+ return map;
+ }
+
+ private boolean isAfAutoSupported(String cameraId) {
+ int[] afModes = getCameraCharacteristics(cameraId)
+ .get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
+ if (afModes == null) {
+ return false;
+ }
+
+ for (int afMode : afModes) {
+ if (afMode == CameraCharacteristics.CONTROL_AF_MODE_AUTO) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureRequestKeys(String cameraId)
+ throws RemoteException {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(getCameraCharacteristics(cameraId));
+ Map<CaptureRequest.Key, Object> keysmap = getSupportedCaptureRequestKeys(cameraId);
+ for (CaptureRequest.Key key : keysmap.keySet()) {
+ cameraMetadataWrapper.set(key, keysmap.get(key));
+ }
+
+ return cameraMetadataWrapper;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureResultKeys(String cameraId)
+ throws RemoteException {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(getCameraCharacteristics(cameraId));
+ Map<CaptureResult.Key, Object> keysmap = getSupportedCaptureResultKeys(cameraId);
+ for (CaptureResult.Key key : keysmap.keySet()) {
+ cameraMetadataWrapper.set(key, keysmap.get(key));
+ }
+
+ return cameraMetadataWrapper;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java
new file mode 100644
index 00000000..c339ed98
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 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 com.android.oemextensions;
+
+import android.annotation.NonNull;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.view.Surface;
+
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.Size;
+
+import java.util.ArrayList;
+
+public class CameraOutputConfigBuilder {
+ private final CameraOutputConfig mConfig;
+
+ private CameraOutputConfigBuilder(CameraOutputConfig config) {
+ mConfig = config;
+ mConfig.surfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE;
+ }
+
+ public static CameraOutputConfigBuilder createSurfaceOutput(
+ int outputId, @NonNull Surface surface) {
+ CameraOutputConfig config = new CameraOutputConfig();
+ config.type = CameraOutputConfig.TYPE_SURFACE;
+ config.outputId = outputId;
+ config.surface = surface;
+ return new CameraOutputConfigBuilder(config);
+ }
+
+ public static CameraOutputConfigBuilder createImageReaderOutput(
+ int outputId, int width, int height, int imageFormat, int maxImages) {
+ CameraOutputConfig config = new CameraOutputConfig();
+ config.type = CameraOutputConfig.TYPE_IMAGEREADER;
+ config.outputId = outputId;
+ config.size = new Size();
+ config.size.width = width;
+ config.size.height = height;
+ config.imageFormat = imageFormat;
+ config.capacity = maxImages;
+ return new CameraOutputConfigBuilder(config);
+ }
+
+ public CameraOutputConfigBuilder setPhysicalCameraId(String physicalCameraId) {
+ mConfig.physicalCameraId = physicalCameraId;
+ return this;
+ }
+
+ public CameraOutputConfigBuilder setSurfaceGroupId(int surfaceGroupId) {
+ mConfig.surfaceGroupId = surfaceGroupId;
+ return this;
+ }
+
+ public CameraOutputConfigBuilder addSharedOutputConfig(CameraOutputConfig cameraOutputConfig) {
+ if (mConfig.sharedSurfaceConfigs == null) {
+ mConfig.sharedSurfaceConfigs = new ArrayList<>();
+ }
+ mConfig.sharedSurfaceConfigs.add(cameraOutputConfig);
+ return this;
+ }
+
+ public CameraOutputConfig build() {
+ CameraOutputConfig result = new CameraOutputConfig();
+ result.outputId = mConfig.outputId;
+ result.type = mConfig.type;
+ result.surface = mConfig.surface;
+ result.physicalCameraId = mConfig.physicalCameraId;
+ result.surfaceGroupId = mConfig.surfaceGroupId;
+ result.capacity = mConfig.capacity;
+ result.imageFormat = mConfig.imageFormat;
+ if (mConfig.size != null) {
+ result.size = new Size();
+ result.size.width = mConfig.size.width;
+ result.size.height = mConfig.size.height;
+ }
+ if (mConfig.sharedSurfaceConfigs != null) {
+ result.sharedSurfaceConfigs = new ArrayList<>(mConfig.sharedSurfaceConfigs);
+ }
+ return result;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java
new file mode 100644
index 00000000..c3d62351
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023 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 com.android.oemextensions;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.IExtensionsService;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+
+public class ExtensionsService extends Service {
+ private static final String TAG = "ExtensionsService";
+
+ public ExtensionsService() {
+ }
+
+ @Override
+ @NonNull
+ public IBinder onBind(Intent intent) {
+ return new ExtensionsServiceStub();
+ }
+
+ class ExtensionsServiceStub extends IExtensionsService.Stub {
+ @Override
+ public boolean isAdvancedExtenderImplemented() throws RemoteException {
+ return true;
+ }
+
+ @Override
+ public void initialize(String version, IOnExtensionsInitializedCallback callback)
+ throws RemoteException {
+ Log.d(TAG, "initialize");
+ callback.onSuccess();
+ }
+
+ @Override
+ public void deInitialize(IOnExtensionsDeinitializedCallback callback)
+ throws RemoteException {
+ Log.d(TAG, "deInitialize");
+ callback.onSuccess();
+ }
+
+ @Override
+ public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType)
+ throws RemoteException {
+ Log.d(TAG, "initializeAdvancedExtension");
+ return new AdvancedExtenderImplStub(ExtensionsService.this, extensionType);
+ }
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java
new file mode 100644
index 00000000..52bb26b4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 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 com.android.oemextensions;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.Request;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class RequestBuilder {
+ private static final AtomicInteger sNextRequestId = new AtomicInteger(0);
+ private final List<Integer> mTargetOutputConfigIds = new ArrayList<>();
+ private final CameraMetadataWrapper mParameters;
+ private int mTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ private final int mRequestId = 0;
+
+ public RequestBuilder(CameraCharacteristics cameraCharacteristics) {
+ mParameters = new CameraMetadataWrapper(cameraCharacteristics);
+ }
+
+ public RequestBuilder addTargetOutputConfigId(int... outputConfigIds) {
+ for (int id : outputConfigIds) {
+ mTargetOutputConfigIds.add(id);
+ }
+ return this;
+ }
+
+ public <T> RequestBuilder setParameter(CaptureRequest.Key<T> key, T value) {
+ mParameters.set(key, value);
+ return this;
+ }
+
+ public RequestBuilder setTemplateId(int templateId) {
+ mTemplateId = templateId;
+ return this;
+ }
+
+ public Request build() {
+ Request request = new Request();
+ int[] idArray = new int[mTargetOutputConfigIds.size()];
+ for (int i = 0; i < idArray.length; i++) {
+ idArray[i] = mTargetOutputConfigIds.get(i);
+ }
+ request.targetOutputConfigIds = idArray;
+ request.requestId = mRequestId;
+ request.parameters = mParameters;
+ request.templateId = mTemplateId;
+ request.requestId = sNextRequestId.getAndIncrement();
+ return request;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java
new file mode 100644
index 00000000..ed749aec
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2023 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 com.android.oemextensions;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.OutputSurface;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Demonstrates a very simple SessionProcessor which just pass all the output surface into the
+ * camera pipeline directly. No postprocessing is performed.
+ */
+public class SimpleSessionProcessorStub extends ISessionProcessorImpl.Stub {
+ private static final String TAG = "SimpleSessionProcessor";
+ private final CameraCharacteristics mCameraCharacteristics;
+ private final Set<CaptureRequest.Key> mSupportedRequestKeys;
+ private final Set<CaptureResult.Key> mSupportedResultKeys;
+
+ private IRequestProcessorImpl mIRequestProcessor;
+ private AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
+ private Map<CaptureRequest.Key, Object> mParameters = new HashMap<>();
+ private boolean mHasAnalysisOutput = false;
+
+ private static final int PREVIEW_OUTPUT_ID = 1;
+ private static final int CAPTURE_OUTPUT_ID = 2;
+ private static final int ANALYSIS_OUTPUT_ID = 3;
+
+ public SimpleSessionProcessorStub(@NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Set<CaptureRequest.Key> supportedRequestKeys,
+ @NonNull Set<CaptureResult.Key> supportedResultKeys) {
+ mCameraCharacteristics = cameraCharacteristics;
+ mSupportedRequestKeys = supportedRequestKeys;
+ mSupportedResultKeys = supportedResultKeys;
+ }
+
+ @Override
+ public CameraSessionConfig initSession(@NonNull String cameraId,
+ @NonNull OutputSurface outputSurfacePreview,
+ @NonNull OutputSurface outputSurfaceStillCapture,
+ @Nullable OutputSurface outputSurfaceAnalysis) throws RemoteException {
+ Log.d(TAG, "initSession cameraId=" + cameraId);
+ CameraSessionConfig cameraSessionConfig = new CameraSessionConfig();
+ cameraSessionConfig.sessionParameter = new CameraMetadataWrapper(mCameraCharacteristics);
+ // if needed, invoke cameraSessionConfig.sessionParameter.set(...) to set session parameters
+ cameraSessionConfig.sessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ List<CameraOutputConfig> outputConfigList = new ArrayList<>();
+
+ // Preview
+ CameraOutputConfig previewOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(PREVIEW_OUTPUT_ID, outputSurfacePreview.surface)
+ .build();
+ outputConfigList.add(previewOutputConfig);
+
+ // Still capture
+ CameraOutputConfig captureOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(CAPTURE_OUTPUT_ID, outputSurfaceStillCapture.surface)
+ .build();
+ outputConfigList.add(captureOutputConfig);
+
+ // ImageAnalysis
+ if (outputSurfaceAnalysis != null) {
+ mHasAnalysisOutput = true;
+ CameraOutputConfig analysisOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(ANALYSIS_OUTPUT_ID, outputSurfaceAnalysis.surface)
+ .build();
+ outputConfigList.add(analysisOutputConfig);
+ }
+
+ cameraSessionConfig.outputConfigs = outputConfigList;
+ return cameraSessionConfig;
+ }
+
+ @Override
+ public void deInitSession() throws RemoteException {
+ Log.d(TAG, "deInitSession");
+ }
+
+ @Override
+ public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor)
+ throws RemoteException {
+ Log.d(TAG, "onCaptureSessionStart");
+ mIRequestProcessor = requestProcessor;
+ }
+
+ @Override
+ public void onCaptureSessionEnd() throws RemoteException {
+ Log.d(TAG, "onCaptureSessionEnd");
+
+ mIRequestProcessor = null;
+ }
+
+ @Override
+ public void setParameters(CaptureRequest captureRequest) throws RemoteException {
+ Log.d(TAG, "setParameters");
+
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ if (mSupportedRequestKeys.contains(key)) {
+ mParameters.put(key, captureRequest.get(key));
+ }
+ }
+ }
+
+ protected void notifyOnCaptureCompleted(
+ @NonNull int seqId,
+ @NonNull TotalCaptureResult result,
+ @NonNull ICaptureCallback captureCallback) {
+ Long shutterTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (shutterTimestamp != null) {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(mCameraCharacteristics);
+
+ for (CaptureResult.Key key : mSupportedResultKeys) {
+ if (result.get(key) != null) {
+ cameraMetadataWrapper.set(key, result.get(key));
+ }
+ }
+
+ try {
+ captureCallback.onCaptureCompleted(shutterTimestamp, seqId,
+ cameraMetadataWrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot notify onCaptureCompleted", e);
+ }
+ }
+ }
+
+ @Override
+ public int startTrigger(CaptureRequest captureRequest, ICaptureCallback captureCallback)
+ throws RemoteException {
+ Log.d(TAG, "startTrigger");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(PREVIEW_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+
+ if (mHasAnalysisOutput) {
+ requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID);
+ }
+ applyParameters(requestBuilder);
+
+ for (CaptureRequest.Key key : captureRequest.getKeys()) {
+ if (mSupportedRequestKeys.contains(key)) {
+ requestBuilder.setParameter(key, captureRequest.get(key));
+ } else {
+ Log.e(TAG, "startTrigger: key " + key + " not supported");
+ }
+ }
+
+ mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult)
+ throws RemoteException {
+ CaptureResult captureResult = partialResult.toCaptureResult();
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResult) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure();
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+ }
+ });
+ return captureSequenceId;
+ }
+
+ private void applyParameters(RequestBuilder requestBuilder) {
+ for (CaptureRequest.Key key : mParameters.keySet()) {
+ requestBuilder.setParameter(key, mParameters.get(key));
+ }
+ }
+
+ @Override
+ public int startRepeating(ICaptureCallback captureCallback) throws RemoteException {
+ Log.d(TAG, "startRepeating");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(PREVIEW_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+ if (mHasAnalysisOutput) {
+ requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID);
+ }
+ applyParameters(requestBuilder);
+
+ mIRequestProcessor.setRepeating(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult)
+ throws RemoteException {
+ CaptureResult captureResult = partialResult.toCaptureResult();
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResult) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure();
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+ }
+ });
+ return captureSequenceId;
+ }
+
+ @Override
+ public void stopRepeating() throws RemoteException {
+ Log.d(TAG, "stopRepeating");
+
+ mIRequestProcessor.stopRepeating();
+ }
+
+ @Override
+ public int startCapture(ICaptureCallback captureCallback) throws RemoteException {
+ Log.d(TAG, "startCapture");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(CAPTURE_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+ applyParameters(requestBuilder);
+
+ mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId,
+ CaptureResultWrapper captureResultWrapper)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResultWrapper) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResultWrapper.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+
+ }
+ });
+ return captureSequenceId;
+ }
+
+ @Override
+ public void abortCapture(int i) throws RemoteException {
+ Log.d(TAG, "abortCapture");
+ mIRequestProcessor.abortCaptures();
+ }
+}