diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2023-03-15 04:18:00 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-03-15 04:18:00 +0000 |
commit | d9af75e9404044bd50059b043f8f54ab2c19fa46 (patch) | |
tree | ce783772c791f8c33ec2bd464176cbdfac04d403 | |
parent | 854f3bf6040c3ff50c4819664734f48f86c36fa4 (diff) | |
parent | 48f538570bd87f9aa26fc71ce2fcfd57bbbd66c2 (diff) | |
download | ex-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>
81 files changed, 6812 insertions, 0 deletions
diff --git a/camera2/extensions/service_based_sample/extensions_service/Android.bp b/camera2/extensions/service_based_sample/extensions_service/Android.bp new file mode 100644 index 00000000..383a3c0b --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/Android.bp @@ -0,0 +1,31 @@ +// +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +android_app { + name: "ExtensionsService", + srcs: ["src/**/*.java"], + libs: ["service_based_camera_extensions"], + static_libs: [ + "androidx.annotation_annotation", + ], + platform_apis: true, + certificate: "platform", + enforce_uses_libs: false, +} diff --git a/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml b/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml new file mode 100644 index 00000000..abd40763 --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.oemextensions"> + <queries> + <intent> + <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" /> + </intent> + </queries> + + <application + android:label="@string/app_name" + android:defaultToDeviceProtectedStorage="true" + android:directBootAware="true"> + <uses-library android:name="androidx.camera.extensions.impl" android:required="true" /> + <service + android:name="ExtensionsService" + android:enabled="true" + android:exported="true"> + <intent-filter> + <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" /> + </intent-filter> + </service> + </application> + +</manifest> diff --git a/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml b/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml new file mode 100644 index 00000000..7a8f9d4a --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">Camera Extensions Service</string> + +</resources> 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(); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/Android.bp b/camera2/extensions/service_based_sample/oem_library/Android.bp new file mode 100644 index 00000000..adfb1b51 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/Android.bp @@ -0,0 +1,45 @@ +// 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +java_library { + name: "service_based_camera_extensions", + installable: true, + srcs: [ + "src/java/**/*.java", + "src/java/**/*.aidl", + ], + static_libs: [ + "androidx.annotation_annotation", + ], + aidl: { + local_include_dirs: ["src/java"], + include_dirs: [ + "frameworks/native/aidl/gui", // For SurfaceView AIDL + "frameworks/av/camera/aidl", // For CaptureRequest AIDL + ] + }, + system_ext_specific: true, + platform_apis: true, +} + +prebuilt_etc { + name: "service_based_camera_extensions.xml", + src: "service_based_camera_extensions.xml", + sub_dir: "permissions", + system_ext_specific: true, +} diff --git a/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml b/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml new file mode 100644 index 00000000..54b5b10a --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + package="androidx.camera.extensions.impl" > +</manifest> diff --git a/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml b/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml new file mode 100644 index 00000000..6501b9b4 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<permissions> + <library name="androidx.camera.extensions.impl" + file="/system_ext/framework/service_based_camera_extensions.jar"/> +</permissions> diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java new file mode 100755 index 00000000..514ca3b5 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.util.Pair; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for auto image capture use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderImpl { + public AutoImageCaptureExtenderImpl() {} + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureProcessorImpl getCaptureProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<CaptureStageImpl> getCaptureStages() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public int getMaxCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } + +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java new file mode 100755 index 00000000..85b63df7 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.util.Pair; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for auto preview use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl { + public AutoPreviewExtenderImpl() { + } + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public CaptureStageImpl getCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public ProcessorType getProcessorType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public ProcessorImpl getProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java new file mode 100755 index 00000000..c547f772 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.util.Pair; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for beauty image capture use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtenderImpl { + public BeautyImageCaptureExtenderImpl() {} + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureProcessorImpl getCaptureProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<CaptureStageImpl> getCaptureStages() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public int getMaxCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java new file mode 100755 index 00000000..da5748cc --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.util.Pair; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for beauty preview use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl { + public BeautyPreviewExtenderImpl() { + } + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public CaptureStageImpl getCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public ProcessorType getProcessorType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public ProcessorImpl getProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java new file mode 100644 index 00000000..6901e5f3 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java @@ -0,0 +1,121 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.util.Pair; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for bokeh image capture use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtenderImpl { + public BokehImageCaptureExtenderImpl() {} + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + return true; + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + } + + @Nullable + @Override + public CaptureProcessorImpl getCaptureProcessor() { + return null; + } + + @Nullable + @Override + public List<CaptureStageImpl> getCaptureStages() { + return null; + } + + @Override + public int getMaxCaptureStage() { + return 2; + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + } + + @Override + public void onDeInit() { + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + return null; + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + return null; + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + return null; + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + return null; + } + + @Nullable + @Override + public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) { + return null; + } + + @NonNull + @Override + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + return null; + } + + @NonNull + @Override + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + return null; + } + +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java new file mode 100644 index 00000000..55902f04 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java @@ -0,0 +1,100 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.util.Pair; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for bokeh preview use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl { + public BokehPreviewExtenderImpl() {} + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + return true; + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + } + + @NonNull + @Override + public CaptureStageImpl getCaptureStage() { + return null; + } + + @NonNull + @Override + public ProcessorType getProcessorType() { + return ProcessorType.PROCESSOR_TYPE_NONE; + } + + @Nullable + @Override + public ProcessorImpl getProcessor() { + return null; + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + } + + @Override + public void onDeInit() { + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + return null; + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + return null; + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + return null; + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + return null; + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java new file mode 100644 index 00000000..3eee146a --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.annotation.SuppressLint; +import android.graphics.ImageFormat; +import android.hardware.camera2.TotalCaptureResult; +import android.media.Image; +import android.util.Pair; +import android.view.Surface; + +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * The interface for processing a set of {@link Image}s that have captured. + * + * @since 1.0 + */ +@SuppressLint("UnknownNullness") +public interface CaptureProcessorImpl extends ProcessorImpl { + /** + * Process a set images captured that were requested. + * + * <p> The result of the processing step should be written to the {@link Surface} that was + * received by {@link #onOutputSurface(Surface, int)}. + * + * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata to + * process. The {@link Image} that are contained within the map will become + * invalid after this method completes, so no references to them should be kept. + */ + void process(Map<Integer, Pair<Image, TotalCaptureResult>> results); + + /** + * Process a set images captured that were requested. + * + * <p> The result of the processing step should be written to the {@link Surface} that was + * received by {@link #onOutputSurface(Surface, int)}. + * + * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata + * to process. The {@link Image} that are contained within the map will + * become invalid after this method completes, so no references to them + * should be kept. + * @param resultCallback Capture result callback to be called once the capture result + * values of the processed image are ready. + * @param executor The executor to run the callback on. If null then the callback will + * run on any arbitrary executor. + * @since 1.3 + */ + void process(Map<Integer, Pair<Image, TotalCaptureResult>> results, + ProcessResultImpl resultCallback, Executor executor); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java new file mode 100644 index 00000000..c4f4a47d --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.hardware.camera2.CaptureRequest; +import android.util.Pair; + +import androidx.annotation.NonNull; + +import java.util.List; + +/** + * The set of parameters that defines a single capture that will be sent to the camera. + * + * @since 1.0 + */ +public interface CaptureStageImpl { + /** Returns the identifier for the {@link CaptureStageImpl}. */ + int getId(); + + /** + * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be + * set for a single {@link CaptureRequest}. + */ + @NonNull + List<Pair<CaptureRequest.Key, Object>> getParameters(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java new file mode 100644 index 00000000..a74a8804 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java @@ -0,0 +1,91 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.SessionConfiguration; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * Provides interfaces that the OEM needs to implement to handle the state change. + * + * @since 1.0 + */ +public interface ExtenderStateListener { + + /** + * Notify to initialize the extension. This will be called after bindToLifeCycle. This is + * where the use case is started and would be able to allocate resources here. After onInit() is + * called, the camera ID, cameraCharacteristics and context will not change until onDeInit() + * has been called. + * + * @param cameraId The camera2 id string of the camera. + * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera. + * @param context The {@link Context} used for CameraX. + */ + void onInit(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context); + + /** + * Notify to de-initialize the extension. This callback will be invoked after unbind. + * After onDeInit() was called, it is expected that the camera ID, cameraCharacteristics will + * no longer hold, this should be where to clear all resources allocated for this use case. + */ + void onDeInit(); + + /** + * This will be invoked before creating a + * {@link CameraCaptureSession}. The {@link CaptureRequest} + * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as + * part of the capture session initialization via + * {@link SessionConfiguration#setSessionParameters(CaptureRequest)} which only supported from + * API level 28. The valid parameter is a subset of the available capture request parameters. + * + * @return The request information to set the session wide camera parameters. + */ + @Nullable + CaptureStageImpl onPresetSession(); + + /** + * This will be invoked once after the {@link CameraCaptureSession} + * has been created. The {@link CaptureRequest} parameters returned via + * {@link CaptureStageImpl} will be used to generate a single request to the current + * configured {@link CameraDevice}. The generated request will be submitted to camera before + * processing other single requests. + * + * @return The request information to create a single capture request to camera device. + */ + @Nullable + CaptureStageImpl onEnableSession(); + + /** + * This will be invoked before the {@link CameraCaptureSession} is + * closed. The {@link CaptureRequest} parameters returned via {@link CaptureStageImpl} will + * be used to generate a single request to the currently configured {@link CameraDevice}. The + * generated request will be submitted to camera before the CameraCaptureSession is closed. + * + * @return The request information to customize the session. + */ + @Nullable + CaptureStageImpl onDisableSession(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java new file mode 100644 index 00000000..cc357b1a --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java @@ -0,0 +1,84 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import androidx.annotation.NonNull; + +/** + * Stub implementation for the extension version check. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public class ExtensionVersionImpl { + public ExtensionVersionImpl() { + } + + /** + * Provide the current CameraX extension library version to vendor library and vendor would + * need to return the supported version for this device. If the returned version is not + * supported by CameraX library, the Preview and ImageCapture would not be able to enable the + * specific effects provided by the vendor. + * + * <p>CameraX library provides the Semantic Versioning string in a form of + * MAJOR.MINOR.PATCH-description + * We will increment the + * MAJOR version when make incompatible API changes, + * MINOR version when add functionality in a backwards-compatible manner, and + * PATCH version when make backwards-compatible bug fixes. And the description can be ignored. + * + * <p>Vendor library should provide MAJOR.MINOR.PATCH to CameraX. The MAJOR and MINOR + * version is used to map to the version of CameraX that it supports, and CameraX extension + * would only available when MAJOR version is matched with CameraX current version. The PATCH + * version does not indicate compatibility. The patch version should be incremented whenever + * the vendor library makes bug fixes or updates to the algorithm. + * + * @param version the version of CameraX library formatted as MAJOR.MINOR.PATCH-description. + * @return the version that vendor supported in this device. The MAJOR.MINOR.PATCH format + * should be used. + */ + @SuppressWarnings("unused") + @NonNull + public String checkApiVersion(@NonNull String version) { + // This sample implements Extensions-Interface 1.3.0. + return "1.3.0"; + } + + /** + * Specify whether or not CameraX should invoke the AdvancedExtenderImpl instead of + * PreviewExtenderImpl/ImageCaptureExtenderImpl. + * + * <p>Starting from version 1.2, a set of alternative interfaces called advanced extender for + * implementing extensions are provided to OEMs as another option. OEMs can continue using + * previous interfaces (PreviewExtenderImpl/ImageCaptureExtenderImpl, also called basic + * extender). + * + * <p>OEMs should return false here if only basic extender is implemented. When returning true, + * CameraX will invoke the AdvancedExtenderImpl implementation in advanced package for all + * types of extension modes. + * + * <p>ExtensionVersionImpl, InitializerImpl will still be called for both basic and advanced + * extender implementation paths. + * + * @return true if AdvancedExtenderImpl is implemented + * @since 1.2 + */ + public boolean isAdvancedExtenderImplemented() { + return true; + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java new file mode 100644 index 00000000..507f2143 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.util.Pair; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for HDR image capture use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderImpl { + public HdrImageCaptureExtenderImpl() {} + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureProcessorImpl getCaptureProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<CaptureStageImpl> getCaptureStages() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public int getMaxCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java new file mode 100644 index 00000000..83f1a348 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.util.Pair; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for HDR preview use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl { + public HdrPreviewExtenderImpl() { + } + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public CaptureStageImpl getCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public ProcessorType getProcessorType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public ProcessorImpl getProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java new file mode 100644 index 00000000..10b45134 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java @@ -0,0 +1,171 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.util.Pair; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Provides abstract methods that the OEM needs to implement to enable extensions for image capture. + * + * @since 1.0 + */ +public interface ImageCaptureExtenderImpl extends ExtenderStateListener { + /** + * Indicates whether the extension is supported on the device. + * + * @param cameraId The camera2 id string of the camera. + * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera. + * @return true if the extension is supported, otherwise false + */ + boolean isExtensionAvailable(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics); + + /** + * Initializes the extender to be used with the specified camera. + * + * <p>This should be called before any other method on the extender. The exception is {@link + * #isExtensionAvailable(String, CameraCharacteristics)}. + * + * @param cameraId The camera2 id string of the camera. + * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera. + */ + void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics); + + /** + * The processing that will be done on a set of captures to create and image with the effect. + */ + @Nullable + CaptureProcessorImpl getCaptureProcessor(); + + /** The set of captures that are needed to create an image with the effect. */ + @Nullable + List<CaptureStageImpl> getCaptureStages(); + + /** + * Returns the maximum size of the list returned by {@link #getCaptureStages()}. + * @return the maximum count. + */ + int getMaxCaptureStage(); + + /** + * Returns the customized supported resolutions. + * + * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned. + * + * <p>The returned resolutions should be subset of the supported sizes retrieved from + * {@link StreamConfigurationMap} for the camera device. If the + * returned list is not null, it will be used to find the best resolutions combination for + * the bound use cases. + * + * @return the customized supported resolutions, or null to support all sizes retrieved from + * {@link StreamConfigurationMap}. + * @since 1.1 + */ + @Nullable + List<Pair<Integer, Size[]>> getSupportedResolutions(); + + /** + * Returns the estimated capture latency range in milliseconds for the target capture + * resolution. + * + * <p>This includes the time spent processing the multi-frame capture request along with any + * additional time for encoding of the processed buffer in the framework if necessary.</p> + * + * @param captureOutputSize size of the capture output surface. If it is null or not in the + * supported output sizes, maximum capture output size is used for + * the estimation. + * @return the range of estimated minimal and maximal capture latency in milliseconds, or + * null if no capture latency info can be provided. + * @since 1.2 + */ + @Nullable + Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize); + + /** + * Return a list of orthogonal capture request keys. + * + * <p>Any keys included in the list will be configurable by clients of the extension and will + * affect the extension functionality.</p> + * + * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p> + * + * <p>Also note that the keys {@link CaptureRequest#JPEG_QUALITY} and + * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the + * list or not. To support common camera operations like zoom, tap-to-focus, flash and + * exposure compensation, we recommend supporting the following keys if possible. + * <pre> + * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO} + * {@link CaptureRequest#SCALER_CROP_REGION} + * tap-to-focus: + * {@link CaptureRequest#CONTROL_AF_MODE} + * {@link CaptureRequest#CONTROL_AF_TRIGGER} + * {@link CaptureRequest#CONTROL_AF_REGIONS} + * {@link CaptureRequest#CONTROL_AE_REGIONS} + * {@link CaptureRequest#CONTROL_AWB_REGIONS} + * flash: + * {@link CaptureRequest#CONTROL_AE_MODE} + * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER} + * {@link CaptureRequest#FLASH_MODE} + * exposure compensation: + * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION} + * </pre> + * On basic extensions that implement 1.2 or prior version, the above keys are all supported + * explicitly. When migrating from 1.2 or prior to 1.3, please note that both CameraX and + * Camera2 will honor the returned list and support only the keys contained in it. For + * example, if OEM decides to return only {@link CaptureRequest#CONTROL_ZOOM_RATIO} and + * {@link CaptureRequest#SCALER_CROP_REGION} in the 1.3 implementation, it means only zoom is + * supported for the app while tap-to-focus , flash and exposure compensation are not allowed. + * + * @return List of supported orthogonal capture keys, or an empty list if no capture settings + * are not supported. + * @since 1.3 + */ + @NonNull + List<CaptureRequest.Key> getAvailableCaptureRequestKeys(); + + /** + * Return a list of supported capture result keys. + * + * <p>Any keys included in this list must be available as part of the registered + * {@link ProcessResultImpl} callback. In case frame processing is not supported, + * then the Camera2/CameraX framework will use the list to filter and notify camera clients + * using the respective camera results.</p> + * + * <p>At the very minimum, it is expected that the result key list is a superset of the + * capture request keys.</p> + * + * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p> + * + * @return List of supported capture result keys, or an empty list if capture results are not + * supported. + * @since 1.3 + */ + @NonNull + List<CaptureResult.Key> getAvailableCaptureResultKeys(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java new file mode 100644 index 00000000..5a9f0ffc --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java @@ -0,0 +1,115 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.camera.extensions.impl.serviceforward.ServiceManager; + +import java.util.concurrent.Executor; + +/** + * Used for initializing the extensions library. + * + * @since 1.1 + */ +public class InitializerImpl { + private InitializerImpl() { + } + + /** An unknown error has occurred. */ + public static final int ERROR_UNKNOWN = 0; + + /** + * Error reported if the application version of extensions is incompatible with the on device + * library version. + */ + public static final int ERROR_INITIALIZE_VERSION_INCOMPATIBLE = 1; + + /** + * Initializes the {@link Context}. + * + * <p>Before this call has been made no calls to the extensions library should be made except + * for {@link ExtensionVersionImpl#checkApiVersion(String)}. + * + * @param version The version of the extension used by the application. + * @param context The {@link Context} of the calling application. + * @param executor The executor to run the callback on. If null then the callback will run on + * any arbitrary executor. + */ + public static void init(@NonNull String version, @NonNull Context context, + @NonNull OnExtensionsInitializedCallback callback, @Nullable Executor executor) { + ServiceManager.init(context, version, callback, executor); + } + + /** + * Deinitializes the extensions to release resources. + * + * <p>After this call has been made no calls to the extensions library should be made except + * for {@link ExtensionVersionImpl#checkApiVersion(String)}. + * + * @param executor The executor to run the callback on. If null then the callback will run on + * any arbitrary executor. + */ + public static void deinit(@NonNull OnExtensionsDeinitializedCallback callback, + @Nullable Executor executor) { + ServiceManager.getInstance().deinit(callback, executor); + } + + /** + * Callback that gets called when the library has finished initializing and is ready for used. + */ + public interface OnExtensionsInitializedCallback { + /** Called if the library successfully initializes. */ + void onSuccess(); + + /** + * Called if the library is unable to successfully initialize. + * + * @param error The reason for failing to initialize. + */ + void onFailure(int error); + } + + /** + * Callback that gets called when the library has finished deinitialized. + * + * <p> Once this interface has been called then + * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} can be called + * again regardless of whether or not the deinitialization has succeeded or failed. + */ + public interface OnExtensionsDeinitializedCallback { + /** + * Called if the library successfully deinitializes. + */ + void onSuccess(); + + /** + * Called if the library encountered some error during the deinitialization. + * + * <p>Even if the library fails to deinitialize it is now valid for + * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} to be called + * again. + * + * @param error The reason for failing to deinitialize. + */ + void onFailure(int error); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java new file mode 100755 index 00000000..05a195e1 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.util.Pair; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for night image capture use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class NightImageCaptureExtenderImpl implements ImageCaptureExtenderImpl { + public NightImageCaptureExtenderImpl() {} + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureProcessorImpl getCaptureProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<CaptureStageImpl> getCaptureStages() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public int getMaxCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java new file mode 100755 index 00000000..eeb254b2 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java @@ -0,0 +1,105 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.util.Pair; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Stub implementation for night preview use case. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.0 + */ +public final class NightPreviewExtenderImpl implements PreviewExtenderImpl { + public NightPreviewExtenderImpl() { + } + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @Nullable CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void init(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public CaptureStageImpl getCaptureStage() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @NonNull + @Override + public ProcessorType getProcessorType() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public ProcessorImpl getProcessor() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onInit(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Context context) { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Override + public void onDeInit() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onPresetSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onEnableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public CaptureStageImpl onDisableSession() { + throw new RuntimeException("Stub, replace with implementation."); + } + + @Nullable + @Override + public List<Pair<Integer, Size[]>> getSupportedResolutions() { + throw new RuntimeException("Stub, replace with implementation."); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java new file mode 100644 index 00000000..b3208137 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.TotalCaptureResult; +import android.util.Pair; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; + +/** + * Provides abstract methods that the OEM needs to implement to enable extensions in the preview. + * + * @since 1.0 + */ +public interface PreviewExtenderImpl extends ExtenderStateListener { + /** The different types of the preview processing. */ + enum ProcessorType { + /** Processor which only updates the {@link CaptureStageImpl}. */ + PROCESSOR_TYPE_REQUEST_UPDATE_ONLY, + /** Processor which updates the received {@link android.media.Image}. */ + PROCESSOR_TYPE_IMAGE_PROCESSOR, + /** No processor, only a {@link CaptureStageImpl} is defined. */ + PROCESSOR_TYPE_NONE + } + + /** + * Indicates whether the extension is supported on the device. + * + * @param cameraId The camera2 id string of the camera. + * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera. + * @return true if the extension is supported, otherwise false + */ + boolean isExtensionAvailable(@NonNull String cameraId, + @NonNull CameraCharacteristics cameraCharacteristics); + + /** + * Initializes the extender to be used with the specified camera. + * + * <p>This should be called before any other method on the extender. The exception is {@link + * #isExtensionAvailable(String, CameraCharacteristics)}. + * + * @param cameraId The camera2 id string of the camera. + * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera. + */ + void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics); + + /** + * The set of parameters required to produce the effect on the preview stream. + * + * <p> This will be the initial set of parameters used for the preview + * {@link CaptureRequest}. If the {@link ProcessorType} is defined as + * {@link ProcessorType#PROCESSOR_TYPE_REQUEST_UPDATE_ONLY} then this will be updated when + * the {@link RequestUpdateProcessorImpl#process(TotalCaptureResult)} from {@link + * #getProcessor()} has been called, this should be updated to reflect the new {@link + * CaptureStageImpl}. If the processing step returns a {@code null}, meaning the required + * parameters has not changed, then calling this will return the previous non-null value. + */ + @NonNull + CaptureStageImpl getCaptureStage(); + + /** The type of preview processing to use. */ + @NonNull + ProcessorType getProcessorType(); + + /** + * Returns a processor which only updates the {@link CaptureStageImpl}. + * + * <p>The type of processor is dependent on the return of {@link #getProcessorType()}. The + * type of ProcessorImpl returned will be according to the following table. + * + * <table> + * <tr><th> ProcessorType </th> <th> ProcessorImpl </th> </tr> + * <tr><td> PROCESSOR_TYPE_REQUEST_UPDATE_ONLY </td> <td> RequestUpdateProcessorImpl </td> </tr> + * <tr><td> PROCESSOR_TYPE_IMAGE_PROCESSOR </td> <td> PreviewImageProcessorImpl </td> </tr> + * <tr><td> PROCESSOR_TYPE_NONE </td> <td> null </td> </tr> + * </table> + */ + @Nullable + ProcessorImpl getProcessor(); + + /** + * Returns the customized supported resolutions. + * + * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned. + * + * <p>The returned resolutions should be subset of the supported sizes retrieved from + * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the + * returned list is not null, it will be used to find the best resolutions combination for + * the bound use cases. + * + * @return the customized supported resolutions. + * @since 1.1 + */ + @Nullable + List<Pair<Integer, Size[]>> getSupportedResolutions(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java new file mode 100644 index 00000000..f203ebad --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java @@ -0,0 +1,64 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.annotation.SuppressLint; +import android.graphics.ImageFormat; +import android.hardware.camera2.TotalCaptureResult; +import android.media.Image; + +import java.util.concurrent.Executor; + +/** + * Processes a single {@link Image} and {@link TotalCaptureResult} to produce an output to a + * stream. + * + * @since 1.0 + */ +@SuppressLint("UnknownNullness") +public interface PreviewImageProcessorImpl extends ProcessorImpl { + /** + * Processes the requested image capture. + * + * <p> The result of the processing step should be written to the {@link android.view.Surface} + * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}. + * + * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will be + * invalid after the method completes so no reference to it should be kept. + * @param result The metadata associated with the image to process. + */ + void process(Image image, TotalCaptureResult result); + + /** + * Processes the requested image capture. + * + * <p> The result of the processing step should be written to the {@link android.view.Surface} + * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}. + * + * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will + * be invalid after the method completes so no reference to it should be + * kept. + * @param result The metadata associated with the image to process. + * @param resultCallback Capture result callback to be called once the capture result + * values of the processed image are ready. + * @param executor The executor to run the callback on. If null then the callback will + * run on any arbitrary executor. + * @since 1.3 + */ + void process(Image image, TotalCaptureResult result, ProcessResultImpl resultCallback, + Executor executor); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java new file mode 100644 index 00000000..d0e3605d --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java @@ -0,0 +1,45 @@ +/* + * Copyright 2022 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 androidx.camera.extensions.impl; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CaptureResult; +import android.util.Pair; + +import java.util.List; + +/** + * Allows clients to receive information about the capture result values of processed frames. + * + * @since 1.3 + */ +@SuppressLint("UnknownNullness") +public interface ProcessResultImpl { + /** + * Capture result callback that needs to be called when the process capture results are + * ready as part of frame post-processing. + * + * @param shutterTimestamp The shutter time stamp of the processed frame. + * @param result Key value pairs for all supported capture results. Do note that + * if results 'android.jpeg.quality' and 'android.jpeg.orientation' + * are present in the process capture input results, then the values + * must also be passed as part of this callback. Both Camera2 and + * CameraX guarantee that those two settings and results are always + * supported and applied by the corresponding framework. + */ + void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java new file mode 100644 index 00000000..e5ca19e9 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.util.Size; +import android.view.Surface; + +import androidx.annotation.NonNull; + +/** + * Processes an input image stream and produces an output image stream. + * + * @since 1.0 + */ +public interface ProcessorImpl { + /** + * Updates where the ProcessorImpl should write the output to. + * + * @param surface The {@link Surface} that the ProcessorImpl should write data into. + * @param imageFormat The format of that the surface expects. + */ + void onOutputSurface(@NonNull Surface surface, int imageFormat); + + /** + * Invoked when CameraX changes the configured output resolution. + * + * <p>After this call, {@link CaptureProcessorImpl} should expect any + * {@link android.media.Image} received as input to be at the specified resolution. + * + * @param size for the surface. + */ + void onResolutionUpdate(@NonNull Size size); + + /** + * Invoked when CameraX changes the configured input image format. + * + * <p>After this call, {@link CaptureProcessorImpl} should expect any + * {@link android.media.Image} received as input to have the specified image format. + * + * @param imageFormat for the surface. + */ + void onImageFormatUpdate(int imageFormat); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java new file mode 100644 index 00000000..ac3bfb3e --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 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 androidx.camera.extensions.impl; + +import android.hardware.camera2.TotalCaptureResult; + +import androidx.annotation.Nullable; + +/** + * Processes a {@link TotalCaptureResult} to update a CaptureStage. + * + * @since 1.0 + */ +public interface RequestUpdateProcessorImpl extends ProcessorImpl { + /** + * Process the {@link TotalCaptureResult} to update the {@link CaptureStageImpl} + * + * @param result The metadata associated with the image. Can be null if the image and meta have + * not been synced. + * @return The updated parameters used for the repeating requests. If this is {@code null} then + * the previous parameters will be used. + */ + @Nullable + CaptureStageImpl process(@Nullable TotalCaptureResult result); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java new file mode 100644 index 00000000..465bfe88 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java @@ -0,0 +1,188 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.util.Range; +import android.util.Size; + +import androidx.camera.extensions.impl.ExtensionVersionImpl; + +import java.util.List; +import java.util.Map; + +/** + * Advanced OEM contract for implementing Extensions. ImageCapture/Preview Extensions are both + * implemented on this interface. + * + * <p>This advanced OEM contract empowers OEM to gain access to more Camera2 capability. This + * includes: (1) Add custom surfaces with specific formats like YUV, RAW, RAW_DEPTH. (2) Access to + * the capture request callbacks as well as all the images retrieved of various image formats. (3) + * Able to triggers single or repeating request with the capabilities to specify target surfaces, + * template id and parameters. + * + * <p>OEM needs to implement it with class name HdrAdvancedExtenderImpl for HDR, + * NightAdvancedExtenderImpl for night mode, BeautyAdvancedExtenderImpl for beauty mode, + * BokehAdvancedExtenderImpl for bokeh mode and AutoAdvancedExtenderImpl for auto mode. + * + * <p>OEMs are required to return true in + * {@link ExtensionVersionImpl#isAdvancedExtenderImplemented()} in order to request CameraX to + * use advanced extender over basic extender. OEM is okay to implement advanced + * extender only Or basic extender only. However the caveat of advanced-only implementation is, + * extensions will be unavailable on the apps using interfaces prior to 1.2. + * + * @since 1.2 + */ +@SuppressLint("UnknownNullness") +public interface AdvancedExtenderImpl { + + /** + * Indicates whether the extension is supported on the device. + * + * @param cameraId The camera2 id string of the camera. + * @param characteristicsMap A map consisting of the camera ids and the + * {@link CameraCharacteristics}s. For every camera, the map + * contains at least the CameraCharacteristics for the camera id. + * If the camera is logical camera, it will also contain associated + * physical camera ids and their CameraCharacteristics. + * @return true if the extension is supported, otherwise false + */ + boolean isExtensionAvailable(String cameraId, + Map<String, CameraCharacteristics> characteristicsMap); + + /** + * Initializes the extender to be used with the specified camera. + * + * <p>This should be called before any other method on the extender. The exception is {@link + * #isExtensionAvailable}. + * + * @param cameraId The camera2 id string of the camera. + * @param characteristicsMap A map consisting of the camera ids and the + * {@link CameraCharacteristics}s. For every camera, the map + * contains at least the CameraCharacteristics for the camera id. + * If the camera is logical camera, it will also contain associated + * physical camera ids and their CameraCharacteristics. + */ + void init(String cameraId, Map<String, CameraCharacteristics> characteristicsMap); + + /** + * Returns the estimated capture latency range in milliseconds for the + * target capture resolution during the calls to + * {@link SessionProcessorImpl#startCapture}. This + * includes the time spent processing the multi-frame capture request along with any additional + * time for encoding of the processed buffer in the framework if necessary. + * + * @param cameraId the camera id + * @param captureOutputSize size of the capture output surface. If it is null or not in the + * supported output sizes, maximum capture output size is used for + * the estimation. + * @param imageFormat the image format of the capture output surface. + * @return the range of estimated minimal and maximal capture latency in milliseconds. + * Returns null if no capture latency info can be provided. + */ + Range<Long> getEstimatedCaptureLatencyRange(String cameraId, + Size captureOutputSize, int imageFormat); + + /** + * Returns supported output format/size map for preview. The format could be PRIVATE or + * YUV_420_888. OEM must support PRIVATE format at least. CameraX will only use resolutions + * for preview from the list. + * + * <p>The preview surface format in the CameraCaptureSession may not be identical to the + * supported preview output format returned here. Like in the basic extender interface, the + * preview PRIVATE surface could be added to the CameraCaptureSession and OEM processes it in + * the HAL. Alternatively OEM can configure a intermediate YUV surface of the same size and + * writes the output to the preview output surface. + */ + Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId); + + /** + * Returns supported output format/size map for image capture. OEM is required to support + * both JPEG and YUV_420_888 format output. + * + * <p>Like in the basic extender interface, the surface created with this supported + * format/size could be either added in CameraCaptureSession with HAL processing OR it + * configures intermediate surfaces(YUV/RAW..) and writes the output to the output surface. + */ + Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId); + + /** + * Returns supported output sizes for Image Analysis (YUV_420_888 format). + * + * <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture + * output surfaces. If imageAnalysis YUV surface is not supported, OEM should return null or + * empty list. + */ + List<Size> getSupportedYuvAnalysisResolutions(String cameraId); + + /** + * Returns a processor for activating extension sessions. It implements all the interactions + * required for starting a extension and cleanup. + */ + SessionProcessorImpl createSessionProcessor(); + + /** + * Returns a list of orthogonal capture request keys. + * + * <p>Any keys included in the list will be configurable by clients of the extension and will + * affect the extension functionality.</p> + * + * <p>Please note that the keys {@link CaptureRequest#JPEG_QUALITY} and + * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the + * list or not. To support common camera operations like zoom, tap-to-focus, flash and + * exposure compensation, we recommend supporting the following keys if possible. + * <pre> + * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO} + * {@link CaptureRequest#SCALER_CROP_REGION} + * tap-to-focus: + * {@link CaptureRequest#CONTROL_AF_MODE} + * {@link CaptureRequest#CONTROL_AF_TRIGGER} + * {@link CaptureRequest#CONTROL_AF_REGIONS} + * {@link CaptureRequest#CONTROL_AE_REGIONS} + * {@link CaptureRequest#CONTROL_AWB_REGIONS} + * flash: + * {@link CaptureRequest#CONTROL_AE_MODE} + * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER} + * {@link CaptureRequest#FLASH_MODE} + * exposure compensation: + * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION} + * </pre> + * + * @return List of supported orthogonal capture keys, or an empty list if no capture settings + * are not supported. + * @since 1.3 + */ + List<CaptureRequest.Key> getAvailableCaptureRequestKeys(); + + /** + * Returns a list of supported capture result keys. + * + * <p>Any keys included in this list must be available as part of the registered + * {@link SessionProcessorImpl.CaptureCallback#onCaptureCompleted} callback.</p> + * + * <p>At the very minimum, it is expected that the result key list is a superset of the + * capture request keys.</p> + * + * @return List of supported capture result keys, or + * an empty list if capture results are not supported. + * @since 1.3 + */ + List<CaptureResult.Key> getAvailableCaptureResultKeys(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java new file mode 100644 index 00000000..c67dc799 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraExtensionCharacteristics; + +import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender; + +/** + * Stub advanced extender implementation for auto. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.2 + */ +@SuppressLint("UnknownNullness") +public class AutoAdvancedExtenderImpl extends ForwardAdvancedExtender { + public AutoAdvancedExtenderImpl() { + super(CameraExtensionCharacteristics.EXTENSION_AUTOMATIC); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java new file mode 100644 index 00000000..2e10e255 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraExtensionCharacteristics; + +import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender; + +/** + * Stub advanced extender implementation for beauty. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.2 + */ +@SuppressLint("UnknownNullness") +public class BeautyAdvancedExtenderImpl extends ForwardAdvancedExtender { + public BeautyAdvancedExtenderImpl() { + super(CameraExtensionCharacteristics.EXTENSION_BEAUTY); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java new file mode 100644 index 00000000..ae55790b --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraExtensionCharacteristics; + +import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender; + +/** + * Stub advanced extender implementation for bokeh. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.2 + */ +@SuppressLint("UnknownNullness") +public class BokehAdvancedExtenderImpl extends ForwardAdvancedExtender { + public BokehAdvancedExtenderImpl() { + super(CameraExtensionCharacteristics.EXTENSION_BOKEH); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java new file mode 100644 index 00000000..68de01b6 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; + +import java.util.List; + +/** + * A config representing a {@link android.hardware.camera2.params.OutputConfiguration} where + * Surface will be created by the information in this config. + */ +@SuppressLint("UnknownNullness") +public interface Camera2OutputConfigImpl { + /** + * Gets thd id of this output config. The id can be used to identify the stream in vendor + * implementations. + */ + int getId(); + + /** + * Gets the surface group id. Vendor can use the surface group id to share memory between + * Surfaces. + */ + int getSurfaceGroupId(); + + /** + * Gets the physical camera id. Returns null if not specified. + */ + String getPhysicalCameraId(); + + /** + * If non-null, enable surface sharing and add the surface constructed by the return + * Camera2OutputConfig. + */ + List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java new file mode 100644 index 00000000..718870f4 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java @@ -0,0 +1,243 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.params.OutputConfiguration; +import android.util.Size; +import android.view.Surface; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A builder implementation to help OEM build the {@link Camera2OutputConfigImpl} instance. + */ +@SuppressLint("UnknownNullness") +public class Camera2OutputConfigImplBuilder { + static AtomicInteger sLastId = new AtomicInteger(0); + private OutputConfigImplImpl mOutputConfig; + private int mSurfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE; + private int mOutputConfigId = -1; + private String mPhysicalCameraId; + private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs; + + private Camera2OutputConfigImplBuilder(OutputConfigImplImpl outputConfig) { + mOutputConfig = outputConfig; + } + + private int getNextId() { + return sLastId.getAndIncrement(); + } + + /** + * Creates a {@link Camera2OutputConfigImpl} that represents a {@link android.media.ImageReader} + * with the given parameters. + */ + public static Camera2OutputConfigImplBuilder newImageReaderConfig( + Size size, int imageFormat, int maxImages) { + return new Camera2OutputConfigImplBuilder( + new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages)); + } + + /** + * Creates a {@link Camera2OutputConfigImpl} that represents a MultiResolutionImageReader with + * the given parameters. + */ + public static Camera2OutputConfigImplBuilder newMultiResolutionImageReaderConfig( + int imageFormat, int maxImages) { + return new Camera2OutputConfigImplBuilder( + new MultiResolutionImageReaderOutputConfigImplImpl(imageFormat, maxImages)); + } + + /** + * Creates a {@link Camera2OutputConfigImpl} that contains the Surface directly. + */ + public static Camera2OutputConfigImplBuilder newSurfaceConfig(Surface surface) { + return new Camera2OutputConfigImplBuilder(new SurfaceOutputConfigImplImpl(surface)); + } + + /** + * Adds a {@link Camera2SessionConfigImpl} to be shared with current config. + */ + public Camera2OutputConfigImplBuilder addSurfaceSharingOutputConfig( + Camera2OutputConfigImpl camera2OutputConfig) { + if (mSurfaceSharingConfigs == null) { + mSurfaceSharingConfigs = new ArrayList<>(); + } + + mSurfaceSharingConfigs.add(camera2OutputConfig); + return this; + } + + /** + * Sets a physical camera id. + */ + public Camera2OutputConfigImplBuilder setPhysicalCameraId(String physicalCameraId) { + mPhysicalCameraId = physicalCameraId; + return this; + } + + /** + * Sets surface group id. + */ + public Camera2OutputConfigImplBuilder setSurfaceGroupId(int surfaceGroupId) { + mSurfaceGroupId = surfaceGroupId; + return this; + } + + /** + * Sets output config id. + */ + public Camera2OutputConfigImplBuilder setOutputConfigId(int outputConfigId) { + mOutputConfigId = outputConfigId; + return this; + } + + + /** + * Build a {@link Camera2OutputConfigImpl} instance. + */ + public Camera2OutputConfigImpl build() { + // Use the Atomic Integer if setOutputConfigId is never called + if(mOutputConfigId == -1) { + mOutputConfig.setId(getNextId()); + } + else { + mOutputConfig.setId(mOutputConfigId); + } + mOutputConfig.setPhysicalCameraId(mPhysicalCameraId); + mOutputConfig.setSurfaceGroup(mSurfaceGroupId); + mOutputConfig.setSurfaceSharingConfigs(mSurfaceSharingConfigs); + return mOutputConfig; + } + + private static class OutputConfigImplImpl implements Camera2OutputConfigImpl { + private int mId; + private int mSurfaceGroup; + private String mPhysicalCameraId; + private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs; + + OutputConfigImplImpl() { + mId = -1; + mSurfaceGroup = 0; + mPhysicalCameraId = null; + mSurfaceSharingConfigs = null; + } + + @Override + public int getId() { + return mId; + } + + @Override + public int getSurfaceGroupId() { + return mSurfaceGroup; + } + + @Override + public String getPhysicalCameraId() { + return mPhysicalCameraId; + } + + @Override + public List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs() { + return mSurfaceSharingConfigs; + } + + public void setId(int id) { + mId = id; + } + + public void setSurfaceGroup(int surfaceGroup) { + mSurfaceGroup = surfaceGroup; + } + + public void setPhysicalCameraId(String physicalCameraId) { + mPhysicalCameraId = physicalCameraId; + } + + public void setSurfaceSharingConfigs( + List<Camera2OutputConfigImpl> surfaceSharingConfigs) { + mSurfaceSharingConfigs = surfaceSharingConfigs; + } + } + + private static class SurfaceOutputConfigImplImpl extends OutputConfigImplImpl + implements SurfaceOutputConfigImpl { + private Surface mSurface; + + SurfaceOutputConfigImplImpl(Surface surface) { + mSurface = surface; + } + + @Override + public Surface getSurface() { + return mSurface; + } + } + + private static class ImageReaderOutputConfigImplImpl extends OutputConfigImplImpl + implements ImageReaderOutputConfigImpl { + private Size mSize; + private int mImageFormat; + private int mMaxImages; + + ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages) { + mSize = size; + mImageFormat = imageFormat; + mMaxImages = maxImages; + } + + @Override + public Size getSize() { + return mSize; + } + + @Override + public int getImageFormat() { + return mImageFormat; + } + + @Override + public int getMaxImages() { + return mMaxImages; + } + } + + private static class MultiResolutionImageReaderOutputConfigImplImpl extends OutputConfigImplImpl + implements MultiResolutionImageReaderOutputConfigImpl { + private int mImageFormat; + private int mMaxImages; + + MultiResolutionImageReaderOutputConfigImplImpl(int imageFormat, int maxImages) { + mImageFormat = imageFormat; + mMaxImages = maxImages; + } + + @Override + public int getImageFormat() { + return mImageFormat; + } + + @Override + public int getMaxImages() { + return mMaxImages; + } + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java new file mode 100644 index 00000000..d1217177 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CaptureRequest; + +import java.util.List; +import java.util.Map; + +/** + * A config representing a {@link android.hardware.camera2.params.SessionConfiguration} + */ +@SuppressLint("UnknownNullness") +public interface Camera2SessionConfigImpl { + /** + * Returns all the {@link Camera2OutputConfigImpl}s that will be used to create + * {@link android.hardware.camera2.params.OutputConfiguration}. + */ + List<Camera2OutputConfigImpl> getOutputConfigs(); + + /** + * Gets all the parameters to create the session parameters with. + */ + Map<CaptureRequest.Key<?>, Object> getSessionParameters(); + + /** + * Gets the template id used for creating {@link CaptureRequest}s to be passed in + * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}. + */ + int getSessionTemplateId(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java new file mode 100644 index 00000000..a3011666 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java @@ -0,0 +1,123 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CaptureRequest; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A builder implementation to help OEM build the {@link Camera2SessionConfigImpl} instance. + */ +@SuppressLint("UnknownNullness") +public class Camera2SessionConfigImplBuilder { + private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW; + Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>(); + List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>(); + + public Camera2SessionConfigImplBuilder() { + } + + /** + * Adds a output config. + */ + public Camera2SessionConfigImplBuilder addOutputConfig( + Camera2OutputConfigImpl outputConfig) { + mCamera2OutputConfigs.add(outputConfig); + return this; + } + + /** + * Sets session parameters. + */ + public <T> Camera2SessionConfigImplBuilder addSessionParameter( + CaptureRequest.Key<T> key, T value) { + mSessionParameters.put(key, value); + return this; + } + + /** + * Sets the template id for session parameters request. + */ + public Camera2SessionConfigImplBuilder setSessionTemplateId(int templateId) { + mSessionTemplateId = templateId; + return this; + } + + /** + * Gets the session template id. + */ + public int getSessionTemplateId() { + return mSessionTemplateId; + } + + /** + * Gets the session parameters. + */ + public Map<CaptureRequest.Key<?>, Object> getSessionParameters() { + return mSessionParameters; + } + + /** + * Gets all the output configs. + */ + public List<Camera2OutputConfigImpl> getCamera2OutputConfigs() { + return mCamera2OutputConfigs; + } + + /** + * Builds a {@link Camera2SessionConfigImpl} instance. + */ + public Camera2SessionConfigImpl build() { + return new Camera2SessionConfigImplImpl(this); + } + + private static class Camera2SessionConfigImplImpl implements + Camera2SessionConfigImpl { + int mSessionTemplateId; + Map<CaptureRequest.Key<?>, Object> mSessionParameters; + List<Camera2OutputConfigImpl> mCamera2OutputConfigs; + + Camera2SessionConfigImplImpl(Camera2SessionConfigImplBuilder builder) { + mSessionTemplateId = builder.getSessionTemplateId(); + mSessionParameters = builder.getSessionParameters(); + mCamera2OutputConfigs = builder.getCamera2OutputConfigs(); + } + + @Override + public List<Camera2OutputConfigImpl> getOutputConfigs() { + return mCamera2OutputConfigs; + } + + @Override + public Map<CaptureRequest.Key<?>, Object> getSessionParameters() { + return mSessionParameters; + } + + @Override + public int getSessionTemplateId() { + return mSessionTemplateId; + } + } +} + diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java new file mode 100644 index 00000000..e7dbb7d8 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraExtensionCharacteristics; + +import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender; + +/** + * Stub advanced extender implementation for hdr. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.2 + */ +@SuppressLint("UnknownNullness") +public class HdrAdvancedExtenderImpl extends ForwardAdvancedExtender { + public HdrAdvancedExtenderImpl() { + super(CameraExtensionCharacteristics.EXTENSION_HDR); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java new file mode 100644 index 00000000..ce17c4f7 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; + +/** + * A interface to receive and process the upcoming next available Image. + * + * <p>Implemented by OEM. + */ +@SuppressLint("UnknownNullness") +public interface ImageProcessorImpl { + /** + * The reference count will be decremented when this method returns. If an extension wants + * to hold onto the image it should increment the reference count in this method and + * decrement it when the image is no longer needed. + * + * <p>If OEM is not closing(decrement) the image fast enough, the imageReference passed + * in this method might contain null image meaning that the Image was closed to prevent + * preview from stalling. + * + * @param outputConfigId the id of {@link Camera2OutputConfigImpl} which identifies + * corresponding Surface + * @param timestampNs the timestamp in nanoseconds associated with this image + * @param imageReference A reference to the {@link android.media.Image} which might contain + * null if OEM close(decrement) the image too slowly + * @param physicalCameraId used to distinguish which physical camera id the image comes from + * when the output configuration is + * MultiResolutionImageReaderOutputConfigImpl. It is also set if + * physicalCameraId is set in other Camera2OutputConfigImpl types. + * + */ + void onNextImageAvailable( + int outputConfigId, + long timestampNs, + ImageReferenceImpl imageReference, + String physicalCameraId + ); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java new file mode 100644 index 00000000..ca4dcafa --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.util.Size; + +/** + * Surface will be created by constructing a ImageReader. + */ +@SuppressLint("UnknownNullness") +public interface ImageReaderOutputConfigImpl extends Camera2OutputConfigImpl { + /** + * Returns the size of the surface. + */ + Size getSize(); + + /** + * Gets the image format of the surface. + */ + int getImageFormat(); + + /** + * Gets the capacity for TYPE_IMAGEREADER. + */ + int getMaxImages(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java new file mode 100644 index 00000000..95f2c3b9 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java @@ -0,0 +1,50 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.media.Image; + +/** + * A Image reference container that enables the Image sharing between Camera2/CameraX and OEM + * using reference counting. The wrapped Image will be closed once the reference count + * reaches 0. + * + * <p>Implemented by Camera2/CameraX. + */ +@SuppressLint("UnknownNullness") +public interface ImageReferenceImpl { + + /** + * Increment the reference count. Returns true if the value was incremented. + * (returns false if the reference count has already reached zero.) + */ + boolean increment(); + + /** + * Decrement the reference count. Image will be closed if reference count reaches 0. + * Returns true if the value was decremented (returns false if the reference count has + * already reached zero) + */ + boolean decrement(); + + /** + * Return the Android image. This object MUST not be closed directly. + * Returns null when the reference count is zero. + */ + Image get(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java new file mode 100644 index 00000000..c3ad61bc --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +/** + * Surface will be created by constructing a MultiResolutionImageReader. + */ +public interface MultiResolutionImageReaderOutputConfigImpl extends Camera2OutputConfigImpl { + /** + * Gets the image format of the surface. + */ + int getImageFormat(); + + /** + * Gets the max images of the ImageReader. + */ + int getMaxImages(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java new file mode 100644 index 00000000..be298443 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CameraExtensionCharacteristics; + +import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender; + +/** + * Stub advanced extender implementation for night. + * + * <p>This class should be implemented by OEM and deployed to the target devices. + * + * @since 1.2 + */ +@SuppressLint("UnknownNullness") +public class NightAdvancedExtenderImpl extends ForwardAdvancedExtender { + public NightAdvancedExtenderImpl() { + super(CameraExtensionCharacteristics.EXTENSION_NIGHT); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java new file mode 100644 index 00000000..f6920296 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java @@ -0,0 +1,42 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.util.Size; +import android.view.Surface; + +/** + * For specifying output surface of the extension. + */ +@SuppressLint("UnknownNullness") +public interface OutputSurfaceImpl { + /** + * Gets the surface. + */ + Surface getSurface(); + + /** + * Gets the size. + */ + Size getSize(); + + /** + * Gets the image format. + */ + int getImageFormat(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java new file mode 100644 index 00000000..51853334 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; + +import java.util.List; +import java.util.Map; + +/** + * An Interface to execute Camera2 capture requests. + */ +@SuppressLint("UnknownNullness") +public interface RequestProcessorImpl { + /** + * Sets a {@link ImageProcessorImpl} to receive {@link ImageReferenceImpl} to process. + */ + void setImageProcessor(int outputconfigId, ImageProcessorImpl imageProcessor); + + /** + * Submits a request. + * @return the id of the capture sequence or -1 in case the processor encounters a fatal error + * or receives an invalid argument. + */ + int submit(Request request, Callback callback); + + /** + * Submits a list of requests. + * @return the id of the capture sequence or -1 in case the processor encounters a fatal error + * or receives an invalid argument. + */ + int submit(List<Request> requests, Callback callback); + + /** + * Set repeating requests. + * @return the id of the capture sequence or -1 in case the processor encounters a fatal error + * or receives an invalid argument. + */ + int setRepeating(Request request, Callback callback); + + + /** + * Abort captures. + */ + void abortCaptures(); + + /** + * Stop Repeating. + */ + void stopRepeating(); + + /** + * A interface representing a capture request configuration used for submitting requests in + * {@link RequestProcessorImpl}. + */ + interface Request { + /** + * Gets the target ids of {@link Camera2OutputConfigImpl} which identifies corresponding + * Surface to be the targeted for the request. + */ + List<Integer> getTargetOutputConfigIds(); + + /** + * Gets all the parameters. + */ + Map<CaptureRequest.Key<?>, Object> getParameters(); + + /** + * Gets the template id. + */ + Integer getTemplateId(); + } + + /** + * Callback to be invoked during the capture. + */ + interface Callback { + void onCaptureStarted( + Request request, + long frameNumber, + long timestamp); + + void onCaptureProgressed( + Request request, + CaptureResult partialResult); + + void onCaptureCompleted( + Request request, + TotalCaptureResult totalCaptureResult); + + void onCaptureFailed( + Request request, + CaptureFailure captureFailure); + + void onCaptureBufferLost( + Request request, + long frameNumber, + int outputStreamId); + + void onCaptureSequenceCompleted(int sequenceId, long frameNumber); + + void onCaptureSequenceAborted(int sequenceId); + + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java new file mode 100644 index 00000000..fabfc2bf --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java @@ -0,0 +1,281 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.view.Surface; + +import java.util.Map; + +/** + * Interface for creating Camera2 CameraCaptureSessions with extension enabled based on + * advanced vendor implementation. + * + * <p><pre> + * The flow of a extension session is shown below: + * (1) {@link #initSession}: CameraX prepares streams configuration for creating + * CameraCaptureSession. Output surfaces for Preview, ImageCapture and ImageAnalysis are passed + * in and vendor is responsible for outputting the results to these surfaces. + * + * (2) {@link #onCaptureSessionStart}: It is called after CameraCaptureSession is configured. + * A {@link RequestProcessorImpl} is passed for vendor to send repeating requests and + * single requests. + * + * (3) {@link #startRepeating}: CameraX will call this method to start the repeating request + * after CameraCaptureSession is called. Vendor should start the repeating request by + * {@link RequestProcessorImpl}. Vendor can also update the repeating request if needed later. + * + * (4) {@link #setParameters(Map)}: The passed parameters will be attached to the repeating request + * and single requests but vendor can choose to apply some of them only. + * + * (5) {@link #startCapture(CaptureCallback)}: It is called when apps want to + * start a multi-frame image capture. {@link CaptureCallback} will be called + * to report the status and the output image will be written to the capture output surface + * specified in {@link #initSession}. + * + * (5) {@link #onCaptureSessionEnd}: It is called right BEFORE CameraCaptureSession.close() is + * called. + * + * (6) {@link #deInitSession}: called when CameraCaptureSession is closed. + * </pre> + */ +@SuppressLint("UnknownNullness") +public interface SessionProcessorImpl { + /** + * Initializes the session for the extension. This is where the OEMs allocate resources for + * preparing a CameraCaptureSession. After initSession() is called, the camera ID, + * cameraCharacteristics and context will not change until deInitSession() has been called. + * + * <p>CameraX specifies the output surface configurations for preview, image capture and image + * analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which consists of a + * list of {@link Camera2OutputConfigImpl} and session parameters. The + * {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession. + * + * <p>OEM is responsible for outputting correct camera images output to these output surfaces. + * OEM can have the following options to enable the output: + * <pre> + * (1) Add these output surfaces in CameraCaptureSession directly using + * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in + * HAL. + * + * (2) Use surface sharing with other surface by calling + * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)} + * to add the output surface to the other {@link Camera2OutputConfigImpl}. + * + * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output + * surface. The output surface won't be contained in the returned + * {@link Camera2SessionConfigImpl}. + * </pre> + * + * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder} + * implementations are provided in the stub for OEM to construct the + * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances. + * + * @param previewSurfaceConfig output surface for preview + * @param imageCaptureSurfaceConfig output surface for image capture. + * @param imageAnalysisSurfaceConfig an optional output config for image analysis + * (YUV_420_888). + * @return a {@link Camera2SessionConfigImpl} consisting of a list of + * {@link Camera2OutputConfigImpl} and session parameters which will decide the + * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the + * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any + * supported or mandatory stream combination BUT OEM must ensure this list will always + * produce a valid camera capture session. + */ + Camera2SessionConfigImpl initSession( + String cameraId, + Map<String, CameraCharacteristics> cameraCharacteristicsMap, + Context context, + OutputSurfaceImpl previewSurfaceConfig, + OutputSurfaceImpl imageCaptureSurfaceConfig, + OutputSurfaceImpl imageAnalysisSurfaceConfig); + + /** + * Notify to de-initialize the extension. This callback will be invoked after + * CameraCaptureSession is closed. After onDeInit() was called, it is expected that the + * camera ID, cameraCharacteristics will no longer hold and tear down any resources allocated + * for this extension. Aborts all pending captures. + */ + void deInitSession(); + + /** + * CameraX / Camera2 would call these API’s to pass parameters from the app to the OEM. It’s + * expected that the OEM would (eventually) update the repeating request if the keys are + * supported. Setting a value to null explicitly un-sets the value. + */ + void setParameters(Map<CaptureRequest.Key<?>, Object> parameters); + + /** + * CameraX / Camera2 will call this interface in response to client requests involving + * the output preview surface. Typical examples include requests that include AF/AE triggers. + * Extensions can disregard any capture request keys that were not advertised in + * {@link AdvancedExtenderImpl#getAvailableCaptureRequestKeys}. + * + * @param triggers Capture request key value map. + * @param callback a callback to report the status. + * @return the id of the capture sequence. + * + * @throws IllegalArgumentException If there are no valid settings that can be applied + * + * @since 1.3 + */ + int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback); + + /** + * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession} + * has been created. {@link RequestProcessorImpl} is passed for OEM to submit single + * requests or set repeating requests. This ExtensionRequestProcessor will be valid to use + * until onCaptureSessionEnd is called. + */ + void onCaptureSessionStart(RequestProcessorImpl requestProcessor); + + /** + * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is + * closed. {@link RequestProcessorImpl} passed in onCaptureSessionStart will no longer + * accept any requests after onCaptureSessionEnd() returns. + */ + void onCaptureSessionEnd(); + + /** + * Starts the repeating request after CameraCaptureSession is called. Vendor should start the + * repeating request by {@link RequestProcessorImpl}. Vendor can also update the + * repeating request when needed later. + * + * @param callback a callback to report the status. + * @return the id of the capture sequence. + */ + int startRepeating(CaptureCallback callback); + + /** + * Stop the repeating request. To prevent OEM from not calling stopRepeating, CameraX will + * first stop the repeating request of current CameraCaptureSession and call this API to signal + * OEM that the repeating request was stopped and going forward calling + * {@link RequestProcessorImpl#setRepeating} will simply do nothing. + */ + void stopRepeating(); + + /** + * Start a multi-frame capture. + * + * When the capture is completed, {@link CaptureCallback#onCaptureSequenceCompleted} + * is called and {@code OnImageAvailableListener#onImageAvailable} + * will also be called on the ImageReader that creates the image capture output surface. + * + * <p>Only one capture can perform at a time. Starting a capture when another capture is running + * will cause onCaptureFailed to be called immediately. + * + * @param callback a callback to report the status. + * @return the id of the capture sequence. + */ + int startCapture(CaptureCallback callback); + + /** + * Abort all capture tasks. + */ + void abortCapture(int captureSequenceId); + + /** + * Callback for notifying the status of {@link #startCapture(CaptureCallback)} and + * {@link #startRepeating(CaptureCallback)}. + */ + interface CaptureCallback { + /** + * This method is called when the camera device has started capturing the initial input + * image. + * + * For a multi-frame capture, the method is called when the + * CameraCaptureSession.CaptureCallback onCaptureStarted of first frame is called and its + * timestamp is directly forwarded to timestamp parameter of + * this method. + * + * @param captureSequenceId id of the current capture sequence + * @param timestamp the timestamp at start of capture for repeating + * request or the timestamp at start of capture of the + * first frame in a multi-frame capture, in nanoseconds. + */ + void onCaptureStarted(int captureSequenceId, long timestamp); + + /** + * This method is called when an image (or images in case of multi-frame + * capture) is captured and device-specific extension processing is triggered. + * + * @param captureSequenceId id of the current capture sequence + */ + void onCaptureProcessStarted(int captureSequenceId); + + /** + * This method is called instead of + * {@link #onCaptureProcessStarted} when the camera device failed + * to produce the required input for the device-specific extension. The + * cause could be a failed camera capture request, a failed + * capture result or dropped camera frame. + * + * @param captureSequenceId id of the current capture sequence + */ + void onCaptureFailed(int captureSequenceId); + + /** + * This method is called independently of the others in the CaptureCallback, when a capture + * sequence finishes. + * + * <p>In total, there will be at least one + * {@link #onCaptureProcessStarted}/{@link #onCaptureFailed} + * invocation before this callback is triggered. If the capture + * sequence is aborted before any requests have begun processing, + * {@link #onCaptureSequenceAborted} is invoked instead.</p> + * + * @param captureSequenceId id of the current capture sequence + */ + void onCaptureSequenceCompleted(int captureSequenceId); + + /** + * This method is called when a capture sequence aborts. + * + * @param captureSequenceId id of the current capture sequence + */ + void onCaptureSequenceAborted(int captureSequenceId); + + /** + * Capture result callback that needs to be called when the process capture results are + * ready as part of frame post-processing. + * + * This callback will fire after {@link #onCaptureStarted}, {@link #onCaptureProcessStarted} + * and before {@link #onCaptureSequenceCompleted}. The callback is not expected to fire + * in case of capture failure {@link #onCaptureFailed} or capture abort + * {@link #onCaptureSequenceAborted}. + * + * @param timestamp The timestamp at start of capture. The same timestamp value + * passed to {@link #onCaptureStarted}. + * @param captureSequenceId the capture id of the request that generated the capture + * results. This is the return value of either + * {@link #startRepeating} or {@link #startCapture}. + * @param result Map containing the supported capture results. Do note + * that if results 'android.jpeg.quality' and + * 'android.jpeg.orientation' are present in the process + * capture input results, then the values must also be passed + * as part of this callback. Both Camera2 and CameraX guarantee + * that those two settings and results are always supported and + * applied by the corresponding framework. + */ + void onCaptureCompleted(long timestamp, int captureSequenceId, + Map<CaptureResult.Key, Object> result); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java new file mode 100644 index 00000000..7b8d83c1 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java @@ -0,0 +1,31 @@ +/* + * Copyright 2021 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 androidx.camera.extensions.impl.advanced; + +import android.annotation.SuppressLint; +import android.view.Surface; + +/** + * Use Surface directly to create the OutputConfiguration. + */ +@SuppressLint("UnknownNullness") +public interface SurfaceOutputConfigImpl extends Camera2OutputConfigImpl { + /** + * Get the {@link Surface}. It'll return valid surface only when type is TYPE_SURFACE. + */ + Surface getSurface(); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl new file mode 100644 index 00000000..5be2e737 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl @@ -0,0 +1,21 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; + +parcelable CameraMetadataWrapper;
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java new file mode 100644 index 00000000..100203b2 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java @@ -0,0 +1,102 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.impl.CameraMetadataNative; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.camera.extensions.impl.serviceforward.PlatformApi; + +import java.util.ArrayList; + +public class CameraMetadataWrapper implements Parcelable { + private CameraMetadataNative mCameraMetadataNative; + private long mVendorId = Long.MAX_VALUE; + + public CameraMetadataWrapper(CameraCharacteristics cameraCharacteristics) { + mCameraMetadataNative = new CameraMetadataNative(); + if (cameraCharacteristics != null) { + setVendorId(cameraCharacteristics); + } + } + + protected CameraMetadataWrapper(Parcel in) { + mCameraMetadataNative = in.readParcelable(CameraMetadataNative.class.getClassLoader()); + } + + public static final Creator<CameraMetadataWrapper> CREATOR = + new Creator<CameraMetadataWrapper>() { + @Override + public CameraMetadataWrapper createFromParcel(Parcel in) { + return new CameraMetadataWrapper(in); + } + + @Override + public CameraMetadataWrapper[] newArray(int size) { + return new CameraMetadataWrapper[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mCameraMetadataNative, flags); + } + + private void setVendorId(CameraCharacteristics chars) { + Object thisClass = CameraCharacteristics.Key.class; + Class<CameraCharacteristics.Key<?>> keyClass = + (Class<CameraCharacteristics.Key<?>>) thisClass; + ArrayList<CameraCharacteristics.Key<?>> vendorKeys = + chars.getNativeMetadata().getAllVendorKeys(keyClass); + if ((vendorKeys != null) && !vendorKeys.isEmpty()) { + mVendorId = vendorKeys.get(0).getVendorId(); + mCameraMetadataNative.setVendorId(mVendorId); + } + } + + public <T> T get(CaptureRequest.Key<T> key) { + return mCameraMetadataNative.get(key); + } + + public <T> void set(CaptureRequest.Key<T> key, T value) { + mCameraMetadataNative.set(key, value); + } + + public <T> void set(CaptureResult.Key<T> key, T value) { + mCameraMetadataNative.set(key, value); + } + + public CaptureRequest toCaptureRequest() { + CameraMetadataNative cameraMetadataNative = new CameraMetadataNative(mCameraMetadataNative); + return PlatformApi.createCaptureRequest(cameraMetadataNative); + } + + public TotalCaptureResult toTotalCaptureResult() { + CameraMetadataNative cameraMetadataNative = new CameraMetadataNative(mCameraMetadataNative); + return PlatformApi.createTotalCaptureResult(cameraMetadataNative); + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl new file mode 100644 index 00000000..0c008487 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl @@ -0,0 +1,38 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.Size; +import android.view.Surface; + +parcelable CameraOutputConfig +{ + Size size; + Surface surface; + int imageFormat; + int capacity; + + const int TYPE_SURFACE = 0; + const int TYPE_IMAGEREADER = 1; + const int TYPE_MULTIRES_IMAGEREADER = 2; + int type; + + int outputId; + int surfaceGroupId; + String physicalCameraId; + List<CameraOutputConfig> sharedSurfaceConfigs; +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl new file mode 100644 index 00000000..c0d1dece --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl @@ -0,0 +1,27 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; +import androidx.camera.extensions.impl.service.CameraOutputConfig; + +parcelable CameraSessionConfig +{ + List<CameraOutputConfig> outputConfigs; + CameraMetadataWrapper sessionParameter; + int sessionTemplateId; +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl new file mode 100644 index 00000000..bf3b331e --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl @@ -0,0 +1,19 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +parcelable CaptureFailureWrapper;
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java new file mode 100644 index 00000000..7deb089b --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java @@ -0,0 +1,88 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; + +import android.util.Log; + +import android.os.Parcelable; +import android.os.Parcel; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureFailure; + +public class CaptureFailureWrapper implements Parcelable { + private CaptureRequest mRequest; + private int mReason; + private boolean mWasImageCaptured; + private int mSequenceId; + private long mFrameNumber; + private String mErrorPhysicalCameraId; + + public CaptureFailureWrapper(CaptureFailure captureFailure) { + mRequest = captureFailure.getRequest(); + mReason = captureFailure.getReason(); + mWasImageCaptured = captureFailure.wasImageCaptured(); + mSequenceId = captureFailure.getSequenceId(); + mFrameNumber = captureFailure.getFrameNumber(); + mErrorPhysicalCameraId = captureFailure.getPhysicalCameraId(); + } + + public CaptureFailureWrapper(Parcel parcel) { + mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader()); + mReason = parcel.readInt(); + mWasImageCaptured = parcel.readBoolean(); + mSequenceId = parcel.readInt(); + mFrameNumber = parcel.readLong(); + mErrorPhysicalCameraId = parcel.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(mRequest, flags); + parcel.writeInt(mReason); + parcel.writeBoolean(mWasImageCaptured); + parcel.writeInt(mSequenceId); + parcel.writeLong(mFrameNumber); + parcel.writeString(mErrorPhysicalCameraId); + } + + public static final Parcelable.Creator<CaptureFailureWrapper> CREATOR + = new Parcelable.Creator<CaptureFailureWrapper>() { + @Override + public CaptureFailureWrapper createFromParcel(Parcel parcel) { + return new CaptureFailureWrapper(parcel); + } + + @Override + public CaptureFailureWrapper[] newArray(int size) { + return new CaptureFailureWrapper[size]; + } + }; + + public CaptureFailure toCaptureFailure() { + return new CaptureFailure(mRequest, mReason, mWasImageCaptured, mSequenceId, + mFrameNumber, mErrorPhysicalCameraId); + } +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl new file mode 100644 index 00000000..6a01aa3a --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl @@ -0,0 +1,19 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +parcelable CaptureResultWrapper; diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java new file mode 100644 index 00000000..44b5bfa2 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java @@ -0,0 +1,89 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; + +import android.util.Log; + + +import android.os.Parcelable; +import android.os.Parcel; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.impl.PhysicalCaptureResultInfo; +import android.hardware.camera2.impl.CameraMetadataNative; + +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; + +public class CaptureResultWrapper implements Parcelable { + private String mCameraId; + private CameraMetadataNative mResults; + private CaptureRequest mRequest; + private int mSequenceId; + private long mFrameNumber; + + public CaptureResultWrapper(CaptureResult captureResult) { + mCameraId = captureResult.getCameraId(); + mResults = captureResult.getNativeMetadata(); + mRequest = captureResult.getRequest(); + mSequenceId = captureResult.getSequenceId(); + mFrameNumber = captureResult.getFrameNumber(); + } + + public CaptureResultWrapper(Parcel parcel) { + mCameraId = parcel.readString(); + mResults = parcel.readParcelable(CameraMetadataNative.class.getClassLoader()); + mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader()); + mSequenceId = parcel.readInt(); + mFrameNumber = parcel.readLong(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mCameraId); + parcel.writeParcelable(mResults, flags); + parcel.writeParcelable(mRequest, flags); + parcel.writeInt(mSequenceId); + parcel.writeLong(mFrameNumber); + } + + public static final Parcelable.Creator<CaptureResultWrapper> CREATOR = + new Parcelable.Creator<CaptureResultWrapper>() { + @Override + public CaptureResultWrapper createFromParcel(Parcel parcel) { + return new CaptureResultWrapper(parcel); + } + + @Override + public CaptureResultWrapper[] newArray(int size) { + return new CaptureResultWrapper[size]; + } + }; + + public CaptureResult toCaptureResult() { + return new CaptureResult(mCameraId, mResults, mRequest, mSequenceId, mFrameNumber); + } +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl new file mode 100644 index 00000000..7042c0b8 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl @@ -0,0 +1,36 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.LatencyRange; +import androidx.camera.extensions.impl.service.SizeList; +import androidx.camera.extensions.impl.service.Size; +import androidx.camera.extensions.impl.service.ISessionProcessorImpl; +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; + +interface IAdvancedExtenderImpl { + boolean isExtensionAvailable(in String cameraId); + void init(in String cameraId); + LatencyRange getEstimatedCaptureLatencyRange( + in String cameraId, in Size outputSize, int format); + @nullable List<SizeList> getSupportedPreviewOutputResolutions(in String cameraId); + @nullable List<SizeList> getSupportedCaptureOutputResolutions(in String cameraId); + @nullable List<SizeList> getSupportedYuvAnalysisResolutions(in String cameraId); + ISessionProcessorImpl getSessionProcessor(); + CameraMetadataWrapper getAvailableCaptureRequestKeys(in String cameraId); + CameraMetadataWrapper getAvailableCaptureResultKeys(in String cameraId); +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl new file mode 100644 index 00000000..0cf067fa --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl @@ -0,0 +1,29 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; +// Declare any non-default types here with import statements + +interface ICaptureCallback { + void onCaptureStarted(int captureSequenceId, long timestamp); + void onCaptureProcessStarted(int captureSequenceId); + void onCaptureFailed(int captureSequenceId); + void onCaptureSequenceCompleted(int captureSequenceId); + void onCaptureSequenceAborted(int captureSequenceId); + void onCaptureCompleted(long shutterTimestamp, int captureSequenceId, in CameraMetadataWrapper results); +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl new file mode 100644 index 00000000..db73ad00 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl @@ -0,0 +1,29 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback; +import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback; +import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl; +import androidx.camera.extensions.impl.service.Size; + +interface IExtensionsService { + boolean isAdvancedExtenderImplemented(); + void initialize(in String version, in IOnExtensionsInitializedCallback callback); + void deInitialize(in IOnExtensionsDeinitializedCallback callback); + @nullable IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl new file mode 100644 index 00000000..940e0f14 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl @@ -0,0 +1,24 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.ImageWrapper; + +interface IImageProcessorImpl +{ + void onNextImageAvailable(int outputConfigId, in ImageWrapper imageWrapper, + in String physicalCameraId); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl new file mode 100644 index 00000000..c8aa43c8 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl @@ -0,0 +1,22 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +interface IOnExtensionsDeinitializedCallback { + void onSuccess(); + void onFailure(int error); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl new file mode 100644 index 00000000..ada15d89 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl @@ -0,0 +1,22 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +interface IOnExtensionsInitializedCallback { + void onSuccess(); + void onFailure(int error); +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl new file mode 100644 index 00000000..8abed9e9 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl @@ -0,0 +1,33 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import android.hardware.camera2.CaptureRequest; +import androidx.camera.extensions.impl.service.CaptureFailureWrapper; +import androidx.camera.extensions.impl.service.CaptureResultWrapper; +import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper; + +interface IRequestCallback +{ + void onCaptureStarted(int requestId, long frameNumber, long timestamp); + void onCaptureProgressed(int requestId, in CaptureResultWrapper partialResult); + void onCaptureCompleted(int requestId, in TotalCaptureResultWrapper totalCaptureResult); + void onCaptureFailed(int requestId, in CaptureFailureWrapper captureFailure); + void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId); + void onCaptureSequenceCompleted(int sequenceId, long frameNumber); + void onCaptureSequenceAborted(int sequenceId); +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl new file mode 100644 index 00000000..70b30fa7 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl @@ -0,0 +1,30 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.IImageProcessorImpl; +import androidx.camera.extensions.impl.service.IRequestCallback; +import androidx.camera.extensions.impl.service.Request; + +interface IRequestProcessorImpl { + void setImageProcessor(int outputConfigId, in IImageProcessorImpl imageProcessor); + int submit(in Request request, in IRequestCallback callback); + int submitBurst(in List<Request> requests, in IRequestCallback callback); + int setRepeating(in Request request, in IRequestCallback callback); + void abortCaptures(); + void stopRepeating(); +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl new file mode 100644 index 00000000..376a4a44 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl @@ -0,0 +1,39 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.CameraSessionConfig; +import androidx.camera.extensions.impl.service.OutputSurface; +import androidx.camera.extensions.impl.service.IRequestProcessorImpl; +import androidx.camera.extensions.impl.service.ICaptureCallback; +import android.hardware.camera2.CaptureRequest; + +interface ISessionProcessorImpl { + CameraSessionConfig initSession(in String cameraId, + in OutputSurface previewSurface, + in OutputSurface imageCaptureSurface, + in OutputSurface imageAnalysisSurface); + void deInitSession(); + void onCaptureSessionStart(IRequestProcessorImpl requestProcessor); + void onCaptureSessionEnd(); + int startRepeating(in ICaptureCallback callback); + void stopRepeating(); + int startCapture(in ICaptureCallback callback); + void setParameters(in CaptureRequest captureRequest); + int startTrigger(in CaptureRequest captureRequest, in ICaptureCallback callback); + void abortCapture(int captureSequenceId); +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl new file mode 100644 index 00000000..09b7b485 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl @@ -0,0 +1,19 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +parcelable ImageWrapper;
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java new file mode 100644 index 00000000..882980d1 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java @@ -0,0 +1,281 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; + +import android.util.Log; +import android.graphics.Rect; + +import android.graphics.GraphicBuffer; +import android.media.ImageReader; +import android.hardware.SyncFence; + + +import android.os.Parcelable; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureFailure; +import android.hardware.HardwareBuffer; +import android.media.Image; + +import androidx.camera.extensions.impl.advanced.ImageReferenceImpl; + +public class ImageWrapper implements Parcelable, ImageReferenceImpl { + private static final String TAG = "ImageWrapper"; + private int mFormat; + private int mWidth; + private int mHeight; + private int mTransform; + private int mScalingMode; + private long mTimestamp; + private int mPlaneCount; + private Rect mCrop; + private HardwareBuffer mBuffer; + private ParcelFileDescriptor mFence; + + public ImageWrapper(Image image) { + mFormat = image.getFormat(); + mWidth = image.getWidth(); + mHeight = image.getHeight(); + mTransform = image.getTransform(); + mScalingMode = image.getScalingMode(); + mTimestamp = image.getTimestamp(); + if (image.getPlaneCount() <= 0) { + mPlaneCount = image.getPlanes().length; + } else { + mPlaneCount = image.getPlaneCount(); + } + + mCrop = image.getCropRect(); + mBuffer = image.getHardwareBuffer(); + try { + SyncFence fd = image.getFence(); + if (fd.isValid()) { + mFence = fd.getFdDup(); + } + } catch (java.io.IOException e) { + Log.e(TAG, "Failed to parcel buffer fence!"); + } + } + + public ImageWrapper(Parcel parcel) { + mFormat = parcel.readInt(); + mWidth = parcel.readInt(); + mHeight = parcel.readInt(); + mTransform = parcel.readInt(); + mScalingMode = parcel.readInt(); + mTimestamp = parcel.readLong(); + mPlaneCount = parcel.readInt(); + mCrop = parcel.readParcelable(Rect.class.getClassLoader()); + mBuffer = parcel.readParcelable(HardwareBuffer.class.getClassLoader()); + mFence = parcel.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mFormat); + parcel.writeInt(mWidth); + parcel.writeInt(mHeight); + parcel.writeInt(mTransform); + parcel.writeInt(mScalingMode); + parcel.writeLong(mTimestamp); + parcel.writeInt(mPlaneCount); + parcel.writeParcelable(mCrop, flags); + parcel.writeParcelable(mBuffer, flags); + parcel.writeParcelable(mFence, flags); + } + + public static final Parcelable.Creator<ImageWrapper> CREATOR + = new Parcelable.Creator<ImageWrapper>() { + @Override + public ImageWrapper createFromParcel(Parcel parcel) { + return new ImageWrapper(parcel); + } + + @Override + public ImageWrapper[] newArray(int size) { + return new ImageWrapper[size]; + } + }; + + + // ImageReferenceImpl implementations. + private Image mImage = null; + private int mRefCount = 1; + private final Object mImageLock = new Object(); + + @Override + public Image get() { + if (mImage == null) { + mImage = new ExtensionImage(this); + } + return mImage; + } + + @Override + public boolean increment() { + synchronized (mImageLock) { + if (mRefCount <= 0) { + return false; + } + mRefCount++; + } + return true; + } + + @Override + public boolean decrement() { + synchronized (mImageLock) { + if (mRefCount <= 0) { + return false; + } + mRefCount--; + if (mRefCount <= 0) { + mImage.close(); + } + } + return true; + } + + private static class ExtensionImage extends android.media.Image { + private final ImageWrapper mImageWrapper; + private GraphicBuffer mGraphicBuffer; + private ImageReader.ImagePlane[] mPlanes; + + private ExtensionImage(ImageWrapper imageWrapper) { + mImageWrapper = imageWrapper; + mIsImageValid = true; + } + + @Override + public int getFormat() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mFormat; + } + + @Override + public int getWidth() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mWidth; + } + + @Override + public HardwareBuffer getHardwareBuffer() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mBuffer; + } + + @Override + public int getHeight() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mHeight; + } + + @Override + public long getTimestamp() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mTimestamp; + } + + @Override + public int getTransform() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mTransform; + } + + @Override + public int getScalingMode() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mScalingMode; + } + + @Override + public Plane[] getPlanes() { + throwISEIfImageIsInvalid(); + if (mPlanes == null) { + int fenceFd = mImageWrapper.mFence != null ? mImageWrapper.mFence.getFd() : -1; + mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mImageWrapper.mBuffer); + mPlanes = ImageReader.initializeImagePlanes(mImageWrapper.mPlaneCount, + mGraphicBuffer, + fenceFd, mImageWrapper.mFormat, mImageWrapper.mTimestamp, + mImageWrapper.mTransform, mImageWrapper.mScalingMode, mImageWrapper.mCrop); + + } + // Shallow copy is fine. + return mPlanes.clone(); + } + + @Override + protected final void finalize() throws Throwable { + try { + close(); + } finally { + super.finalize(); + } + } + + @Override + public boolean isAttachable() { + throwISEIfImageIsInvalid(); + // Clients must always detach parcelable images + return true; + } + + @Override + public Rect getCropRect() { + throwISEIfImageIsInvalid(); + return mImageWrapper.mCrop; + } + + @Override + public void close() { + mIsImageValid = false; + if (mGraphicBuffer != null) { + ImageReader.unlockGraphicBuffer(mGraphicBuffer); + mGraphicBuffer.destroy(); + mGraphicBuffer = null; + } + + if (mPlanes != null) { + mPlanes = null; + } + + if (mImageWrapper.mBuffer != null) { + mImageWrapper.mBuffer.close(); + mImageWrapper.mBuffer = null; + } + + if (mImageWrapper.mFence != null) { + try { + mImageWrapper.mFence.close(); + } catch (java.io.IOException e) { + e.printStackTrace(); + } + mImageWrapper.mFence = null; + } + } + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl new file mode 100644 index 00000000..9d9e22cf --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl @@ -0,0 +1,23 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +parcelable LatencyRange +{ + long min; + long max; +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl new file mode 100644 index 00000000..558928c3 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl @@ -0,0 +1,27 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +// Declare any non-default types here with import statements +import androidx.camera.extensions.impl.service.Size; +import android.view.Surface; + +parcelable OutputSurface { + Surface surface; + Size size; + int imageFormat; +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl new file mode 100644 index 00000000..08dff963 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl @@ -0,0 +1,27 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; + +parcelable Request +{ + int[] targetOutputConfigIds; + CameraMetadataWrapper parameters; + int templateId; + int requestId; +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl new file mode 100644 index 00000000..5341b604 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl @@ -0,0 +1,23 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +parcelable Size +{ + int width; + int height; +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl new file mode 100644 index 00000000..443c769e --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl @@ -0,0 +1,25 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +import androidx.camera.extensions.impl.service.Size; + +parcelable SizeList +{ + int format; + List<Size> sizes; +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl new file mode 100644 index 00000000..b28861d5 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl @@ -0,0 +1,19 @@ +/** + * 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 androidx.camera.extensions.impl.service; + +parcelable TotalCaptureResultWrapper; diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java new file mode 100644 index 00000000..28bbcb23 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java @@ -0,0 +1,121 @@ +/* + * 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 androidx.camera.extensions.impl.service; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; + +import android.os.Parcelable; +import android.os.Parcel; +import android.util.Log; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.impl.PhysicalCaptureResultInfo; +import android.hardware.camera2.impl.CameraMetadataNative; + +import androidx.camera.extensions.impl.service.CaptureResultWrapper; +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; + +public class TotalCaptureResultWrapper implements Parcelable { + private String mLogicalCameraId; + private CameraMetadataNative mResults; + private CaptureRequest mRequest; + private int mSequenceId; + private long mFrameNumber; + private List<CaptureResultWrapper> mPartials = new ArrayList<>(); + private int mSessionId; + private List<PhysicalCaptureResultInfo> mPhysicalResultList = new ArrayList<>(); + + public TotalCaptureResultWrapper(TotalCaptureResult totalResult) { + mLogicalCameraId = totalResult.getCameraId(); + mResults = totalResult.getNativeMetadata(); + mRequest = totalResult.getRequest(); + mSequenceId = totalResult.getSequenceId(); + mFrameNumber = totalResult.getFrameNumber(); + mSessionId = totalResult.getSessionId(); + for (CaptureResult partial : totalResult.getPartialResults()) { + mPartials.add(new CaptureResultWrapper(partial)); + } + Map<String, TotalCaptureResult> physicalResults = + totalResult.getPhysicalCameraTotalResults(); + for (TotalCaptureResult physicalResult : physicalResults.values()) { + mPhysicalResultList.add(new PhysicalCaptureResultInfo(physicalResult.getCameraId(), + physicalResult.getNativeMetadata())); + } + } + + public TotalCaptureResultWrapper(Parcel parcel) { + mLogicalCameraId = parcel.readString(); + mResults = parcel.readParcelable(CameraMetadataNative.class.getClassLoader()); + mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader()); + mSequenceId = parcel.readInt(); + mFrameNumber = parcel.readLong(); + parcel.readParcelableList(mPartials, CaptureResultWrapper.class.getClassLoader()); + mSessionId = parcel.readInt(); + parcel.readParcelableList(mPhysicalResultList, + PhysicalCaptureResultInfo.class.getClassLoader()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mLogicalCameraId); + parcel.writeParcelable(mResults, flags); + parcel.writeParcelable(mRequest, flags); + parcel.writeInt(mSequenceId); + parcel.writeLong(mFrameNumber); + parcel.writeParcelableList(mPartials, flags); + parcel.writeInt(mSessionId); + parcel.writeParcelableList(mPhysicalResultList, flags); + } + + public static final Parcelable.Creator<TotalCaptureResultWrapper> CREATOR + = new Parcelable.Creator<TotalCaptureResultWrapper>() { + @Override + public TotalCaptureResultWrapper createFromParcel(Parcel parcel) { + return new TotalCaptureResultWrapper(parcel); + } + + @Override + public TotalCaptureResultWrapper[] newArray(int size) { + return new TotalCaptureResultWrapper[size]; + } + }; + + public TotalCaptureResult toTotalCaptureResult() { + PhysicalCaptureResultInfo[] physicalResults = new PhysicalCaptureResultInfo[0]; + if ((mPhysicalResultList != null) && (!mPhysicalResultList.isEmpty())) { + physicalResults = new PhysicalCaptureResultInfo[mPhysicalResultList.size()]; + physicalResults = mPhysicalResultList.toArray(physicalResults); + } + ArrayList<CaptureResult> partials = new ArrayList<>(mPartials.size()); + for (CaptureResultWrapper resultWrapper : mPartials) { + partials.add(resultWrapper.toCaptureResult()); + } + return new TotalCaptureResult( + mLogicalCameraId, mResults, + mRequest, mSequenceId, + mFrameNumber, partials, mSessionId, + physicalResults); + } +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java new file mode 100644 index 00000000..32a765b9 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java @@ -0,0 +1,245 @@ +/* + * 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 androidx.camera.extensions.impl.serviceforward; + +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.os.RemoteException; +import android.util.Log; +import android.util.Range; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl; +import androidx.camera.extensions.impl.advanced.SessionProcessorImpl; +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.HashMap; +import java.util.List; +import java.util.Map; + +public class ForwardAdvancedExtender implements AdvancedExtenderImpl { + private static final String TAG = "ForwardAdvancedExtender"; + private IAdvancedExtenderImpl mIAdvancedExtender; + private String mCameraId; + private final int mExtensionType; + private ForwardSessionProcessor mForwardSessionProcessor; + + public ForwardAdvancedExtender(int extensionType) { + mIAdvancedExtender = ServiceManager.getInstance().createAdvancedExtenderImpl( + extensionType); + mExtensionType = extensionType; + } + + private static ArrayList<Size> getSupportedSizes(SizeList sizesList) { + ArrayList<Size> ret = new ArrayList<>(); + for (androidx.camera.extensions.impl.service.Size size : sizesList.sizes) { + ret.add(new Size(size.width, size.height)); + } + return ret; + } + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId, + @NonNull Map<String, CameraCharacteristics> characteristicsMap) { + try { + return mIAdvancedExtender.isExtensionAvailable(cameraId); + } catch (RemoteException e) { + Log.e(TAG, "isExtensionAvailable failed", e); + throw new IllegalStateException("isExtensionAvailable failed", e); + } + } + + @Override + public void init(@NonNull String cameraId, + @NonNull Map<String, CameraCharacteristics> characteristicsMap) { + try { + mCameraId = cameraId; + mIAdvancedExtender.init(cameraId); + } catch (RemoteException e) { + Log.e(TAG, "init failed", e); + throw new IllegalStateException("init failed", e); + } + } + + @Override + @Nullable + public Range<Long> getEstimatedCaptureLatencyRange(@NonNull String cameraId, + @NonNull Size captureOutputSize, + int imageFormat) { + try { + androidx.camera.extensions.impl.service.Size size = + new androidx.camera.extensions.impl.service.Size(); + size.width = captureOutputSize.getWidth(); + size.height = captureOutputSize.getHeight(); + LatencyRange latencyRange = + mIAdvancedExtender.getEstimatedCaptureLatencyRange(cameraId, + size, imageFormat); + return new Range<>(latencyRange.min, latencyRange.max); + } catch (RemoteException e) { + Log.e(TAG, "getEstimatedCaptureLatencyRange failed", e); + throw new IllegalStateException("getEstimatedCaptureLatencyRange failed", e); + } + } + + @Override + public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId) { + try { + List<SizeList> sizeLists = mIAdvancedExtender.getSupportedPreviewOutputResolutions( + cameraId); + Map<Integer, List<Size>> result = new HashMap<>(); + for (SizeList sizeList : sizeLists) { + result.put(sizeList.format, getSupportedSizes(sizeList)); + } + return result; + } catch (RemoteException e) { + Log.e(TAG, "getSupportedPreviewOutputResolutions failed", e); + throw new IllegalStateException("getSupportedPreviewOutputResolutions failed", e); + } + } + + @Override + public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId) { + try { + List<SizeList> sizeLists = mIAdvancedExtender.getSupportedCaptureOutputResolutions( + cameraId); + Map<Integer, List<Size>> result = new HashMap<>(); + for (SizeList sizeList : sizeLists) { + result.put(sizeList.format, getSupportedSizes(sizeList)); + } + return result; + } catch (RemoteException e) { + Log.e(TAG, "getSupportedCaptureOutputResolutions failed", e); + throw new IllegalStateException("getSupportedCaptureOutputResolutions failed", e); + } + } + + @Override + public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) { + try { + List<SizeList> sizeLists = mIAdvancedExtender.getSupportedYuvAnalysisResolutions( + cameraId); + + if (sizeLists == null) { + return null; + } + + for (SizeList sizeList : sizeLists) { + if (sizeList.format == ImageFormat.YUV_420_888) { + return getSupportedSizes(sizeList); + } + } + return null; + } catch (RemoteException e) { + Log.e(TAG, "getSupportedYuvAnalysisResolutions failed", e); + throw new IllegalStateException("getSupportedYuvAnalysisResolutions failed", e); + } + } + + /** + * Re-initialize IAdvancedExtenderImpl when binder died. + */ + private void ensureIAdvancedExtenderImplAlive() { + try { + if (!mIAdvancedExtender.asBinder().pingBinder()) { + Log.e(TAG, "IAdvancedExtenderImpl binder died, recreate"); + mIAdvancedExtender = ServiceManager.getInstance().createAdvancedExtenderImpl( + mExtensionType); + mIAdvancedExtender.init(mCameraId); + } + } catch (RemoteException e) { + Log.e(TAG, "can't create IAdvancedExtenderImpl", e); + throw new IllegalStateException("can't create IAdvancedExtenderImpl", e); + } + } + /** + * Re-initialize ISessionProcessImpl when binder died. + */ + ISessionProcessorImpl recreateISessionProcessor() { + Log.e(TAG, "Recreating ISessionProcessorImpl"); + try { + ensureIAdvancedExtenderImplAlive(); + return mIAdvancedExtender.getSessionProcessor(); + } catch (RemoteException e) { + Log.e(TAG, "can't get the SessionProcessor from IAdvancedExtenderImpl", e); + throw new IllegalStateException( + "can't get the SessionProcessor from IAdvancedExtenderImpl", e); + } + } + + @Override + @NonNull + public SessionProcessorImpl createSessionProcessor() { + try { + ISessionProcessorImpl sessionProcessor = mIAdvancedExtender.getSessionProcessor(); + mForwardSessionProcessor = + new ForwardSessionProcessor(this, sessionProcessor); + return mForwardSessionProcessor; + } catch (RemoteException e) { + Log.e(TAG, "can't get the SessionProcessor from IAdvancedExtenderImpl", e); + throw new IllegalStateException( + "can't get the SessionProcessor from IAdvancedExtenderImpl", e); } + } + + @Override + @Nullable + public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() { + try { + CameraMetadataWrapper cameraMetadataWrapper + = mIAdvancedExtender.getAvailableCaptureRequestKeys(mCameraId); + + CaptureRequest captureRequest = cameraMetadataWrapper.toCaptureRequest(); + + List<CaptureRequest.Key> result = new ArrayList<>(); + for (CaptureRequest.Key<?> key : captureRequest.getKeys()) { + result.add(key); + } + return result; + } catch (RemoteException e) { + Log.e(TAG, "getAvailableCaptureRequestKeys failed", e); + throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e); + } + } + + @Override + @Nullable + public List<CaptureResult.Key> getAvailableCaptureResultKeys() { + try { + CameraMetadataWrapper cameraMetadataWrapper + = mIAdvancedExtender.getAvailableCaptureResultKeys(mCameraId); + TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult(); + + List<CaptureResult.Key> result = new ArrayList<>(); + for (CaptureResult.Key<?> key : captureResult.getKeys()) { + result.add(key); + } + return result; + } catch (RemoteException e) { + Log.e(TAG, "getAvailableCaptureRequestKeys failed", e); + throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e); + } + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java new file mode 100644 index 00000000..bdb87be7 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java @@ -0,0 +1,345 @@ +/* + * 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 androidx.camera.extensions.impl.serviceforward; + +import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_IMAGEREADER; +import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER; +import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_SURFACE; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.os.Binder; +import android.os.DeadObjectException; +import android.os.RemoteException; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImplBuilder; +import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl; +import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImplBuilder; +import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl; +import androidx.camera.extensions.impl.advanced.RequestProcessorImpl; +import androidx.camera.extensions.impl.advanced.SessionProcessorImpl; +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.ICaptureCallback; +import androidx.camera.extensions.impl.service.ISessionProcessorImpl; +import androidx.camera.extensions.impl.service.OutputSurface; + +import java.util.HashMap; +import java.util.Map; + +public class ForwardSessionProcessor implements SessionProcessorImpl { + private static final String TAG = "ForwardSessionProcessor"; + private final ForwardAdvancedExtender mForwardAdvancedExtender; + + private ISessionProcessorImpl mISessionProcessor; + public ForwardSessionProcessor(@NonNull ForwardAdvancedExtender forwardAdvancedExtender, + @NonNull ISessionProcessorImpl sessionProcessor) { + mForwardAdvancedExtender = forwardAdvancedExtender; + mISessionProcessor = sessionProcessor; + } + + private OutputSurface getOutputSurface(OutputSurfaceImpl outputSurfaceImpl) { + OutputSurface outputSurface = new OutputSurface(); + + androidx.camera.extensions.impl.service.Size extSize = + new androidx.camera.extensions.impl.service.Size(); + extSize.width = outputSurfaceImpl.getSize().getWidth(); + extSize.height = outputSurfaceImpl.getSize().getHeight(); + outputSurface.size = extSize; + outputSurface.imageFormat = outputSurfaceImpl.getImageFormat(); + outputSurface.surface = outputSurfaceImpl.getSurface(); + return outputSurface; + } + + @Override + @NonNull + public Camera2SessionConfigImpl initSession(@NonNull String cameraId, + @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap, + @NonNull Context context, + @NonNull OutputSurfaceImpl previewSurfaceConfig, + @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig, + @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) { + return initSession(cameraId, cameraCharacteristicsMap, context, previewSurfaceConfig, + imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig, + /* isRecoveringFromBinderDeath */ false); + } + + @NonNull + private Camera2SessionConfigImpl initSession(@NonNull String cameraId, + @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap, + @NonNull Context context, + @NonNull OutputSurfaceImpl previewSurfaceConfig, + @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig, + @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig, + boolean isRecoveringFromBinderDeath) { + try { + OutputSurface outputSurfacePreview = getOutputSurface(previewSurfaceConfig); + OutputSurface outputSurfaceCapture = getOutputSurface(imageCaptureSurfaceConfig); + OutputSurface outputSurfaceAnalysis = null; + if (imageAnalysisSurfaceConfig != null) { + outputSurfaceAnalysis = getOutputSurface(imageAnalysisSurfaceConfig); + } + + CameraSessionConfig sessionConfig = mISessionProcessor.initSession( + cameraId, + outputSurfacePreview, + outputSurfaceCapture, + outputSurfaceAnalysis); + + Camera2SessionConfigImplBuilder sessionConfigBuilder = + new Camera2SessionConfigImplBuilder(); + CaptureRequest captureRequest = sessionConfig.sessionParameter.toCaptureRequest(); + for (CaptureRequest.Key<?> key : captureRequest.getKeys()) { + CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key; + sessionConfigBuilder.addSessionParameter(objKey, captureRequest.get(objKey)); + } + for (CameraOutputConfig outputConfig : sessionConfig.outputConfigs) { + Camera2OutputConfigImplBuilder builder = + getCamera2OutputConfigImplBuilder(outputConfig); + if (outputConfig.sharedSurfaceConfigs != null && + (!outputConfig.sharedSurfaceConfigs.isEmpty())) { + for (CameraOutputConfig sharedSurfaceConfig : + outputConfig.sharedSurfaceConfigs) { + builder.addSurfaceSharingOutputConfig( + getCamera2OutputConfigImplBuilder(sharedSurfaceConfig).build()); + } + } + sessionConfigBuilder.addOutputConfig(builder.build()); + } + + sessionConfigBuilder.setSessionTemplateId(sessionConfig.sessionTemplateId); + return sessionConfigBuilder.build(); + } catch (RemoteException e) { + if ((e instanceof DeadObjectException) && !isRecoveringFromBinderDeath) { + // service died, reinitialize. + mISessionProcessor = mForwardAdvancedExtender.recreateISessionProcessor(); + return initSession(cameraId, cameraCharacteristicsMap, context, previewSurfaceConfig + , imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig, + /* isRecoveringFromBinderDeath */ true ); + } + Log.e(TAG, "initSession failed", e); + throw new IllegalStateException("initSession failed", e); + } + } + + private static Camera2OutputConfigImplBuilder getCamera2OutputConfigImplBuilder( + CameraOutputConfig outputConfig) { + switch (outputConfig.type) { + case TYPE_SURFACE: + return Camera2OutputConfigImplBuilder + .newSurfaceConfig(outputConfig.surface) + .setPhysicalCameraId(outputConfig.physicalCameraId) + .setSurfaceGroupId(outputConfig.surfaceGroupId) + .setOutputConfigId(outputConfig.outputId); + case TYPE_IMAGEREADER: + android.util.Size size = new android.util.Size( + outputConfig.size.width, outputConfig.size.height); + return Camera2OutputConfigImplBuilder + .newImageReaderConfig(size, outputConfig.imageFormat, outputConfig.capacity) + .setPhysicalCameraId(outputConfig.physicalCameraId) + .setSurfaceGroupId(outputConfig.surfaceGroupId) + .setOutputConfigId(outputConfig.outputId); + case TYPE_MULTIRES_IMAGEREADER: + default: + throw new UnsupportedOperationException("Output config type not supported"); + } + } + + @Override + public void deInitSession() { + try { + mISessionProcessor.deInitSession(); + } catch (RemoteException e) { + Log.e(TAG, "deInitSession failed", e); + throw new IllegalStateException("deInitSession failed", e); + } + } + + @Override + public void setParameters(Map<CaptureRequest.Key<?>, Object> parameters) { + try { + mISessionProcessor.setParameters(PlatformApi.createCaptureRequest(parameters)); + } catch (RemoteException e) { + Log.e(TAG, "setParameters failed", e); + // still capture normally will invoke setParameters first and then startCapture. + // We want to fail the startCapture not the setParameters so that the capture failure + // can be propagated to the app. + } + } + + @Override + public int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback) { + try { + return mISessionProcessor.startTrigger(PlatformApi.createCaptureRequest(triggers), + new CaptureCallbackAdapter(callback)); + } catch (RemoteException e) { + Log.e(TAG, "startTrigger failed", e); + throw new IllegalStateException("startTrigger failed", e); + } + } + + @Override + public void onCaptureSessionStart(RequestProcessorImpl requestProcessor) { + try { + mISessionProcessor.onCaptureSessionStart( + new RequestProcessorAdapter(requestProcessor)); + } catch (RemoteException e) { + Log.e(TAG, "onCaptureSessionStart failed", e); + throw new IllegalStateException("onCaptureSessionStart failed", e); + } + } + + @Override + public void onCaptureSessionEnd() { + try { + mISessionProcessor.onCaptureSessionEnd(); + } catch (RemoteException e) { + Log.e(TAG, "onCaptureSessionEnd failed", e); + throw new IllegalStateException("onCaptureSessionEnd failed", e); + } + } + + @Override + public int startRepeating(CaptureCallback callback) { + try { + return mISessionProcessor.startRepeating(new CaptureCallbackAdapter(callback)); + } catch (RemoteException e) { + Log.e(TAG, "startRepeating failed", e); + // notify the onCaptureFailed callback so that app is notified of the error. + callback.onCaptureFailed(0); + return 0; + } + } + + @Override + public void stopRepeating() { + try { + mISessionProcessor.stopRepeating(); + } catch (RemoteException e) { + Log.e(TAG, "stopRepeating failed", e); + throw new IllegalStateException("startRepeating failed", e); + } + } + + @Override + public int startCapture(CaptureCallback callback) { + try { + return mISessionProcessor.startCapture(new CaptureCallbackAdapter(callback)); + } catch (RemoteException e) { + Log.e(TAG, "startCapture failed", e); + // notify the onCaptureFailed callback so that app is notified of the error. + callback.onCaptureFailed(0); + return 0; + } + } + + @Override + public void abortCapture(int captureSequenceId) { + try { + mISessionProcessor.abortCapture(captureSequenceId); + } catch (RemoteException e) { + Log.e(TAG, "abortCapture failed", e); + throw new IllegalStateException("abortCapture failed", e); + } + } + + private static class CaptureCallbackAdapter extends ICaptureCallback.Stub { + private final SessionProcessorImpl.CaptureCallback mImplCaptureCallback; + + CaptureCallbackAdapter(SessionProcessorImpl.CaptureCallback implCaptureCallback) { + mImplCaptureCallback = implCaptureCallback; + } + + @Override + public void onCaptureStarted(int captureSequenceId, long timeStamp) throws RemoteException { + final long token = Binder.clearCallingIdentity(); + try { + mImplCaptureCallback.onCaptureStarted(captureSequenceId, timeStamp); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onCaptureProcessStarted(int captureSequenceId) throws RemoteException { + final long token = Binder.clearCallingIdentity(); + try { + mImplCaptureCallback.onCaptureProcessStarted(captureSequenceId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onCaptureFailed(int captureSequenceId) throws RemoteException { + final long token = Binder.clearCallingIdentity(); + try { + mImplCaptureCallback.onCaptureFailed(captureSequenceId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onCaptureSequenceCompleted(int captureSequenceId) throws RemoteException { + final long token = Binder.clearCallingIdentity(); + try { + mImplCaptureCallback.onCaptureSequenceCompleted(captureSequenceId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onCaptureSequenceAborted(int captureSequenceId) throws RemoteException { + final long token = Binder.clearCallingIdentity(); + try { + mImplCaptureCallback.onCaptureSequenceAborted(captureSequenceId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onCaptureCompleted(long shutterTimestamp, int captureSequenceId, + CameraMetadataWrapper cameraMetadataWrapper) + throws RemoteException { + TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult(); + + Map<CaptureResult.Key, Object> resultmap = new HashMap<>(); + for (CaptureResult.Key key : captureResult.getKeys()) { + resultmap.put(key, captureResult.get(key)); + } + + final long token = Binder.clearCallingIdentity(); + try { + mImplCaptureCallback.onCaptureCompleted(shutterTimestamp, captureSequenceId, + resultmap); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java new file mode 100644 index 00000000..a40a16d0 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java @@ -0,0 +1,59 @@ +/* + * 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 androidx.camera.extensions.impl.serviceforward; + +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.impl.CameraMetadataNative; + +import java.util.Map; + +public class PlatformApi { + public static CaptureRequest createCaptureRequest( + Map<CaptureRequest.Key<?>, Object> parameters) { + CameraMetadataNative metadataNative = new CameraMetadataNative(); + CaptureRequest.Builder builder = + new CaptureRequest.Builder(metadataNative, false, -1, "0", null); + + for (CaptureRequest.Key<?> key : parameters.keySet()) { + CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key; + builder.set(objKey, parameters.get(objKey)); + } + return builder.build(); + } + + public static CaptureRequest createCaptureRequest(CameraMetadataNative cameraMetadataNative) { + CaptureRequest.Builder builder = + new CaptureRequest.Builder(cameraMetadataNative, false, -1, "0", null); + return builder.build(); + } + + public static TotalCaptureResult createTotalCaptureResult( + CameraMetadataNative cameraMetadataNative) { + return new TotalCaptureResult(cameraMetadataNative, 0); + } + + public static CameraMetadataNative createCameraMetadataNative( + Map<CaptureRequest.Key<?>, Object> parameters) { + CameraMetadataNative metadataNative = new CameraMetadataNative(); + for (CaptureRequest.Key<?> key : parameters.keySet()) { + CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key; + metadataNative.set(objKey, parameters.get(objKey)); + } + return metadataNative; + } +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java new file mode 100644 index 00000000..3cc1d24c --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java @@ -0,0 +1,229 @@ +/* + * 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 androidx.camera.extensions.impl.serviceforward; + +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.camera.extensions.impl.advanced.ImageProcessorImpl; +import androidx.camera.extensions.impl.advanced.ImageReferenceImpl; +import androidx.camera.extensions.impl.advanced.RequestProcessorImpl; +import androidx.camera.extensions.impl.service.CaptureFailureWrapper; +import androidx.camera.extensions.impl.service.CaptureResultWrapper; +import androidx.camera.extensions.impl.service.IImageProcessorImpl; +import androidx.camera.extensions.impl.service.IRequestCallback; +import androidx.camera.extensions.impl.service.IRequestProcessorImpl; +import androidx.camera.extensions.impl.service.ImageWrapper; +import androidx.camera.extensions.impl.service.Request; +import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class RequestProcessorAdapter extends IRequestProcessorImpl.Stub { + private static final String TAG = "RequestProcessorAdapter"; + + private RequestProcessorImpl mRequestProcessorImpl; + RequestProcessorAdapter(RequestProcessorImpl requestProcessorImpl) { + mRequestProcessorImpl = requestProcessorImpl; + } + @Override + public void setImageProcessor(int outputfigId, IImageProcessorImpl imageProcessor) + throws RemoteException { + mRequestProcessorImpl.setImageProcessor(outputfigId, new ImageProcessorImpl() { + @Override + public void onNextImageAvailable(int outputConfigId, long timestampNs, + ImageReferenceImpl imageReference, String physicalCameraId) { + try { + imageProcessor.onNextImageAvailable(outputConfigId, + new ImageWrapper(imageReference.get()), physicalCameraId); + imageReference.decrement(); + } catch (RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + }); + } + + @Override + public int submit(Request request, IRequestCallback requestCallback) + throws RemoteException { + return submitBurst(Arrays.asList(request), requestCallback); + } + + @Override + public int submitBurst(List<Request> requests, IRequestCallback requestCallback) + throws RemoteException { + List<RequestProcessorImpl.Request> implRequests = new ArrayList<>(); + Map<RequestProcessorImpl.Request, Request> requestsMap = new HashMap<>(); + for (Request request : requests) { + RequestProcessorImpl.Request implRequest = new ImplRequestAdapter(request); + implRequests.add(implRequest); + requestsMap.put(implRequest, request); + } + return mRequestProcessorImpl.submit(implRequests, + new ImplCaptureCallbackAdapter(requestsMap, requestCallback)); + } + + @Override + public int setRepeating(Request request, IRequestCallback requestCallback) + throws RemoteException { + Map<RequestProcessorImpl.Request, Request> requestsMap = new HashMap<>(); + RequestProcessorImpl.Request implRequest = new ImplRequestAdapter(request); + requestsMap.put(implRequest, request); + + return mRequestProcessorImpl.setRepeating(implRequest, + new ImplCaptureCallbackAdapter(requestsMap, requestCallback)); + } + + @Override + public void abortCaptures() throws RemoteException { + mRequestProcessorImpl.abortCaptures(); + } + + @Override + public void stopRepeating() throws RemoteException { + mRequestProcessorImpl.stopRepeating(); + } + + private static class ImplRequestAdapter implements RequestProcessorImpl.Request { + private Request mRequest; + ImplRequestAdapter(Request request) { + mRequest = request; + } + + @Override + public List<Integer> getTargetOutputConfigIds() { + List<Integer> result = new ArrayList<>(mRequest.targetOutputConfigIds.length); + for (int id : mRequest.targetOutputConfigIds) { + result.add(id); + } + return result; + } + + @Override + public Map<CaptureRequest.Key<?>, Object> getParameters() { + CaptureRequest captureRequest = mRequest.parameters.toCaptureRequest(); + Map<CaptureRequest.Key<?>, Object> parameters = new HashMap<>(); + for (CaptureRequest.Key<?> key : captureRequest.getKeys()) { + parameters.put(key, captureRequest.get(key)); + } + return parameters; + } + + @Override + public Integer getTemplateId() { + return mRequest.templateId; + } + } + + private static class ImplCaptureCallbackAdapter implements RequestProcessorImpl.Callback { + private Map<RequestProcessorImpl.Request, Request> mRequestsMap; + private IRequestCallback mRequestCallback; + ImplCaptureCallbackAdapter(Map<RequestProcessorImpl.Request, Request> requestsMap, + IRequestCallback requestCallback) { + mRequestCallback = requestCallback; + mRequestsMap = requestsMap; + } + + private Request getRequest(RequestProcessorImpl.Request implRequest) { + return mRequestsMap.get(implRequest); + } + + @Override + public void onCaptureStarted(RequestProcessorImpl.Request implRequest, long frameNumber, + long timestamp) { + try { + mRequestCallback.onCaptureStarted(getRequest(implRequest).requestId, + frameNumber, timestamp); + } catch (RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + + @Override + public void onCaptureProgressed(RequestProcessorImpl.Request implRequest, + CaptureResult partialResult) { + try { + mRequestCallback.onCaptureProgressed(getRequest(implRequest).requestId, + new CaptureResultWrapper(partialResult)); + } catch(RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + + @Override + public void onCaptureCompleted(RequestProcessorImpl.Request implRequest, + TotalCaptureResult totalCaptureResult) { + try { + mRequestCallback.onCaptureCompleted(getRequest(implRequest).requestId, + new TotalCaptureResultWrapper(totalCaptureResult)); + } catch(RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + + @Override + public void onCaptureFailed(RequestProcessorImpl.Request implRequest, + CaptureFailure captureFailure) { + try { + + mRequestCallback.onCaptureFailed(getRequest(implRequest).requestId, + new CaptureFailureWrapper(captureFailure)); + } catch(RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + + @Override + public void onCaptureBufferLost(RequestProcessorImpl.Request implRequest, long frameNumber, + int outputStreamId) { + try { + mRequestCallback.onCaptureBufferLost(getRequest(implRequest).requestId, + frameNumber, outputStreamId); + } catch(RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + + @Override + public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) { + try { + mRequestCallback.onCaptureSequenceCompleted(sequenceId, frameNumber); + } catch(RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + + @Override + public void onCaptureSequenceAborted(int sequenceId) { + try { + mRequestCallback.onCaptureSequenceAborted(sequenceId); + } catch(RemoteException e) { + Log.e(TAG, "Can't connect to the binder!", e); + } + } + } + +} diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java new file mode 100644 index 00000000..7e27a7b6 --- /dev/null +++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java @@ -0,0 +1,171 @@ +/* + * 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 androidx.camera.extensions.impl.serviceforward; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.AsyncTask; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.camera.extensions.impl.InitializerImpl; +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; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +public class ServiceManager { + private static final String TAG = "ServiceManager"; + private static final int SERVICE_DELAY_MS = 1000; + private static final String SERVICE_PACKAGE_NAME = "com.android.oemextensions"; + private static final String SERVICE_SERVICE_NAME = + "com.android.oemextensions.ExtensionsService"; + + private static ServiceManager sServiceManager; + private static final Object mLock = new Object(); + + public static void init(@Nullable Context context, @NonNull String version, + @NonNull InitializerImpl.OnExtensionsInitializedCallback callback, + @NonNull Executor executor) { + synchronized (mLock) { + if (sServiceManager == null) { + sServiceManager = new ServiceManager(context); + } + sServiceManager.bindServiceSync(context); + } + + try { + sServiceManager.mExtensionService.initialize(version, + new IOnExtensionsInitializedCallback.Stub() { + @Override + public void onSuccess() throws RemoteException { + executor.execute( () -> { + callback.onSuccess(); + Log.d(TAG, "success!"); + }); + } + + @Override + public void onFailure(int error) throws RemoteException { + executor.execute( () -> { + callback.onFailure(error); + }); + } + }); + } catch (RemoteException e){ + throw new IllegalStateException("Failed to connect to extensions service", e); + } + } + + @NonNull + public static ServiceManager getInstance() { + return sServiceManager; + } + + public ServiceManager(@NonNull Context context) { + mContext = context; + } + + Context mContext; + + ServiceConnection mServiceConnection; + IExtensionsService mExtensionService; + + void bindServiceSync(Context context) { + if (mServiceConnection == null) { + CountDownLatch countDownLatch = new CountDownLatch(1); + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder binder) { + mExtensionService = IExtensionsService.Stub.asInterface(binder); + Log.d(TAG, "service connected"); + countDownLatch.countDown(); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + Log.e(TAG, "service disconnected"); + mExtensionService = null; + mServiceConnection = null; + } + }; + + Intent intent = new Intent(); + intent.setClassName(SERVICE_PACKAGE_NAME, SERVICE_SERVICE_NAME); + Log.d(TAG, "bindService start. intent = " + intent); + context.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | + Context.BIND_ABOVE_CLIENT, AsyncTask.THREAD_POOL_EXECUTOR, + mServiceConnection); + + try { + boolean success = countDownLatch.await(SERVICE_DELAY_MS, TimeUnit.MILLISECONDS); + if (!success) { + Log.e(TAG, "Timed out while initializing proxy service!"); + } + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted while initializing proxy service!"); + } + } + } + + public void deinit(@NonNull InitializerImpl.OnExtensionsDeinitializedCallback callback, + @NonNull Executor executor) { + try { + mExtensionService.deInitialize(new IOnExtensionsDeinitializedCallback.Stub() { + @Override + public void onSuccess() throws RemoteException { + executor.execute( () -> { + callback.onSuccess(); + }); + } + + @Override + public void onFailure(int error) throws RemoteException { + executor.execute( () -> { + callback.onFailure(error); + }); + } + }); + } catch (RemoteException e) { + throw new IllegalStateException("Failed to connect to extensions service", e); + } + } + + @NonNull + public IAdvancedExtenderImpl createAdvancedExtenderImpl(int extensionType) { + try { + synchronized (mLock) { + if (mExtensionService == null) { + bindServiceSync(mContext); + } + } + return mExtensionService.initializeAdvancedExtension(extensionType); + } catch (RemoteException e) { + Log.e(TAG, "initializeAdvancedExtension failed", e); + throw new IllegalStateException("initializeAdvancedExtension failed", e); + } + } +} |