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 /camera2/extensions/service_based_sample/extensions_service/src/com | |
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>
Diffstat (limited to 'camera2/extensions/service_based_sample/extensions_service/src/com')
5 files changed, 889 insertions, 0 deletions
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java new file mode 100644 index 00000000..a10c1659 --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java @@ -0,0 +1,270 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.oemextensions; + +import android.content.Context; +import android.graphics.ImageFormat; +import android.graphics.Rect; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.params.MeteringRectangle; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.os.RemoteException; +import android.util.Log; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; +import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl; +import androidx.camera.extensions.impl.service.ISessionProcessorImpl; +import androidx.camera.extensions.impl.service.LatencyRange; +import androidx.camera.extensions.impl.service.SizeList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AdvancedExtenderImplStub extends IAdvancedExtenderImpl.Stub { + private static final String TAG = "AdvancedExtenderStub"; + private Context mContext; + private int mExtensionType; + private String mCurrentCameraId; + private Map<String, CameraCharacteristics> mCharacteristicsMap = new HashMap<>(); + + /** + * Construct the AdvancedExtenderImplStub instance. + * + * @param context a context. + * @param extensionType CameraExtensionCharacteristics#EXTENSION_AUTOMATIC for Auto, + * CameraExtensionCharacteristics#EXTENSION_NIGHT for Night, + * CameraExtensionCharacteristics#EXTENSION_HDR for HDR, + * CameraExtensionCharacteristics#EXTENSION_BOKEH for Bokeh, + * CameraExtensionCharacteristics#EXTENSION_FACE_RETOUCH for face retouch. + */ + public AdvancedExtenderImplStub(@NonNull Context context, int extensionType) { + mContext = context; + mExtensionType = extensionType; + } + + @Override + public boolean isExtensionAvailable(@NonNull String cameraId) throws RemoteException { + return true; + } + + @Override + public void init(@NonNull String cameraId) throws RemoteException { + mCurrentCameraId = cameraId; + } + + @Override + @NonNull + public LatencyRange getEstimatedCaptureLatencyRange(@NonNull String cameraId, + @NonNull androidx.camera.extensions.impl.service.Size outputSize, + int format) throws RemoteException { + Log.d(TAG, "getEstimatedCaptureLatencyRange format" + format); + + LatencyRange latencyRange = new LatencyRange(); + latencyRange.min = 100; + latencyRange.max = 1000; + return latencyRange; + } + + private CameraCharacteristics getCameraCharacteristics(String cameraId) { + CameraCharacteristics characteristics = mCharacteristicsMap.get(cameraId); + if (characteristics != null) { + return characteristics; + } + try { + CameraManager cameraManager = mContext.getSystemService(CameraManager.class); + characteristics = cameraManager.getCameraCharacteristics(cameraId); + mCharacteristicsMap.put(cameraId, characteristics); + return characteristics; + } catch (CameraAccessException e) { + Log.e(TAG, "Cannot get CameraCharacteristics", e); + return null; + } + } + + private static SizeList getSupportedSizeByFormat( + CameraCharacteristics cameraCharacteristics, int imageFormat) { + StreamConfigurationMap streamConfigMap = + cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + + Size[] sizes = streamConfigMap.getOutputSizes(imageFormat); + SizeList sizeList = new SizeList(); + sizeList.sizes = new ArrayList<>(); + for (Size size : sizes) { + androidx.camera.extensions.impl.service.Size sz = + new androidx.camera.extensions.impl.service.Size(); + sz.width = size.getWidth(); + sz.height = size.getHeight(); + sizeList.sizes.add(sz); + } + sizeList.format = imageFormat; + return sizeList; + } + + @Override + @NonNull + public List<SizeList> getSupportedPreviewOutputResolutions(@NonNull String cameraId) + throws RemoteException { + CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId); + if (cameraCharacteristics == null) { + return Collections.emptyList(); + } + + return Arrays.asList( + getSupportedSizeByFormat(cameraCharacteristics, ImageFormat.PRIVATE)); + } + + @Override + @NonNull + public List<SizeList> getSupportedCaptureOutputResolutions(@NonNull String cameraId) + throws RemoteException { + CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId); + if (cameraCharacteristics == null) { + return Collections.emptyList(); + } + return Arrays.asList( + getSupportedSizeByFormat(cameraCharacteristics, + ImageFormat.JPEG), + getSupportedSizeByFormat(cameraCharacteristics, + ImageFormat.YUV_420_888)); + } + + @Override + @NonNull + public List<SizeList> getSupportedYuvAnalysisResolutions(@NonNull String cameraId) + throws RemoteException { + CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(cameraId); + if (cameraCharacteristics == null) { + return Collections.emptyList(); + } + + return Arrays.asList( + getSupportedSizeByFormat(cameraCharacteristics, ImageFormat.YUV_420_888)); + } + + @Override + @NonNull + public ISessionProcessorImpl getSessionProcessor() throws RemoteException { + Log.d(TAG, "getSessionProcessor"); + return new SimpleSessionProcessorStub(getCameraCharacteristics(mCurrentCameraId), + getSupportedCaptureRequestKeys(mCurrentCameraId).keySet(), + getSupportedCaptureResultKeys(mCurrentCameraId).keySet()); + } + + private Map<CaptureRequest.Key, Object> getSupportedCaptureRequestKeys(String cameraId) { + Map<CaptureRequest.Key, Object> map = new HashMap<>(); + map.put(CaptureRequest.CONTROL_ZOOM_RATIO, + 1.0f /* don't care, must not be null */); + map.put(CaptureRequest.SCALER_CROP_REGION, + new Rect() /* don't care, must not be null */); + map.put(CaptureRequest.CONTROL_AE_REGIONS, + new MeteringRectangle[0] /* don't care, must not be null */); + map.put(CaptureRequest.CONTROL_AWB_REGIONS, + new MeteringRectangle[0] /* don't care, must not be null */); + map.put(CaptureRequest.JPEG_QUALITY, + (byte)0 /* don't care, must not be null */); + map.put(CaptureRequest.JPEG_ORIENTATION, + 0 /* don't care, must not be null */); + if (isAfAutoSupported(cameraId)) { + Log.e("AAAAA", "support AF: cameraid=" + cameraId); + map.put(CaptureRequest.CONTROL_AF_TRIGGER, + 0 /* don't care, must not be null */); + map.put(CaptureRequest.CONTROL_AF_MODE, + 0 /* don't care, must not be null */); + map.put(CaptureRequest.CONTROL_AF_REGIONS, + new MeteringRectangle[0] /* don't care, must not be null */); + } + return map; + } + + private Map<CaptureResult.Key, Object> getSupportedCaptureResultKeys(String cameraId) { + Map<CaptureResult.Key, Object> map = new HashMap<>(); + map.put(CaptureResult.CONTROL_ZOOM_RATIO, + 1.0f /* don't care, must not be null */); + map.put(CaptureResult.SCALER_CROP_REGION, + new Rect() /* don't care, must not be null */); + map.put(CaptureResult.CONTROL_AE_REGIONS, + new MeteringRectangle[0] /* don't care, must not be null */); + map.put(CaptureResult.CONTROL_AWB_REGIONS, + new MeteringRectangle[0] /* don't care, must not be null */); + map.put(CaptureResult.JPEG_QUALITY, + (byte)0 /* don't care, must not be null */); + map.put(CaptureResult.JPEG_ORIENTATION, + 0 /* don't care, must not be null */); + if (isAfAutoSupported(cameraId)) { + map.put(CaptureResult.CONTROL_AF_REGIONS, + new MeteringRectangle[0] /* don't care, must not be null */); + map.put(CaptureResult.CONTROL_AF_TRIGGER, + 0 /* don't care, must not be null */); + map.put(CaptureResult.CONTROL_AF_MODE, + 0 /* don't care, must not be null */); + map.put(CaptureResult.CONTROL_AF_STATE, + 0 /* don't care, must not be null */); + } + return map; + } + + private boolean isAfAutoSupported(String cameraId) { + int[] afModes = getCameraCharacteristics(cameraId) + .get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); + if (afModes == null) { + return false; + } + + for (int afMode : afModes) { + if (afMode == CameraCharacteristics.CONTROL_AF_MODE_AUTO) { + return true; + } + } + return false; + } + + @Override + public CameraMetadataWrapper getAvailableCaptureRequestKeys(String cameraId) + throws RemoteException { + CameraMetadataWrapper cameraMetadataWrapper = + new CameraMetadataWrapper(getCameraCharacteristics(cameraId)); + Map<CaptureRequest.Key, Object> keysmap = getSupportedCaptureRequestKeys(cameraId); + for (CaptureRequest.Key key : keysmap.keySet()) { + cameraMetadataWrapper.set(key, keysmap.get(key)); + } + + return cameraMetadataWrapper; + } + + @Override + public CameraMetadataWrapper getAvailableCaptureResultKeys(String cameraId) + throws RemoteException { + CameraMetadataWrapper cameraMetadataWrapper = + new CameraMetadataWrapper(getCameraCharacteristics(cameraId)); + Map<CaptureResult.Key, Object> keysmap = getSupportedCaptureResultKeys(cameraId); + for (CaptureResult.Key key : keysmap.keySet()) { + cameraMetadataWrapper.set(key, keysmap.get(key)); + } + + return cameraMetadataWrapper; + } +} diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java new file mode 100644 index 00000000..c339ed98 --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.oemextensions; + +import android.annotation.NonNull; +import android.hardware.camera2.params.OutputConfiguration; +import android.view.Surface; + +import androidx.camera.extensions.impl.service.CameraOutputConfig; +import androidx.camera.extensions.impl.service.Size; + +import java.util.ArrayList; + +public class CameraOutputConfigBuilder { + private final CameraOutputConfig mConfig; + + private CameraOutputConfigBuilder(CameraOutputConfig config) { + mConfig = config; + mConfig.surfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE; + } + + public static CameraOutputConfigBuilder createSurfaceOutput( + int outputId, @NonNull Surface surface) { + CameraOutputConfig config = new CameraOutputConfig(); + config.type = CameraOutputConfig.TYPE_SURFACE; + config.outputId = outputId; + config.surface = surface; + return new CameraOutputConfigBuilder(config); + } + + public static CameraOutputConfigBuilder createImageReaderOutput( + int outputId, int width, int height, int imageFormat, int maxImages) { + CameraOutputConfig config = new CameraOutputConfig(); + config.type = CameraOutputConfig.TYPE_IMAGEREADER; + config.outputId = outputId; + config.size = new Size(); + config.size.width = width; + config.size.height = height; + config.imageFormat = imageFormat; + config.capacity = maxImages; + return new CameraOutputConfigBuilder(config); + } + + public CameraOutputConfigBuilder setPhysicalCameraId(String physicalCameraId) { + mConfig.physicalCameraId = physicalCameraId; + return this; + } + + public CameraOutputConfigBuilder setSurfaceGroupId(int surfaceGroupId) { + mConfig.surfaceGroupId = surfaceGroupId; + return this; + } + + public CameraOutputConfigBuilder addSharedOutputConfig(CameraOutputConfig cameraOutputConfig) { + if (mConfig.sharedSurfaceConfigs == null) { + mConfig.sharedSurfaceConfigs = new ArrayList<>(); + } + mConfig.sharedSurfaceConfigs.add(cameraOutputConfig); + return this; + } + + public CameraOutputConfig build() { + CameraOutputConfig result = new CameraOutputConfig(); + result.outputId = mConfig.outputId; + result.type = mConfig.type; + result.surface = mConfig.surface; + result.physicalCameraId = mConfig.physicalCameraId; + result.surfaceGroupId = mConfig.surfaceGroupId; + result.capacity = mConfig.capacity; + result.imageFormat = mConfig.imageFormat; + if (mConfig.size != null) { + result.size = new Size(); + result.size.width = mConfig.size.width; + result.size.height = mConfig.size.height; + } + if (mConfig.sharedSurfaceConfigs != null) { + result.sharedSurfaceConfigs = new ArrayList<>(mConfig.sharedSurfaceConfigs); + } + return result; + } +} diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java new file mode 100644 index 00000000..c3d62351 --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.oemextensions; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl; +import androidx.camera.extensions.impl.service.IExtensionsService; +import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback; +import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback; + +public class ExtensionsService extends Service { + private static final String TAG = "ExtensionsService"; + + public ExtensionsService() { + } + + @Override + @NonNull + public IBinder onBind(Intent intent) { + return new ExtensionsServiceStub(); + } + + class ExtensionsServiceStub extends IExtensionsService.Stub { + @Override + public boolean isAdvancedExtenderImplemented() throws RemoteException { + return true; + } + + @Override + public void initialize(String version, IOnExtensionsInitializedCallback callback) + throws RemoteException { + Log.d(TAG, "initialize"); + callback.onSuccess(); + } + + @Override + public void deInitialize(IOnExtensionsDeinitializedCallback callback) + throws RemoteException { + Log.d(TAG, "deInitialize"); + callback.onSuccess(); + } + + @Override + public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType) + throws RemoteException { + Log.d(TAG, "initializeAdvancedExtension"); + return new AdvancedExtenderImplStub(ExtensionsService.this, extensionType); + } + } +}
\ No newline at end of file diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java new file mode 100644 index 00000000..52bb26b4 --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.oemextensions; + +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CaptureRequest; + +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; +import androidx.camera.extensions.impl.service.Request; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class RequestBuilder { + private static final AtomicInteger sNextRequestId = new AtomicInteger(0); + private final List<Integer> mTargetOutputConfigIds = new ArrayList<>(); + private final CameraMetadataWrapper mParameters; + private int mTemplateId = CameraDevice.TEMPLATE_PREVIEW; + private final int mRequestId = 0; + + public RequestBuilder(CameraCharacteristics cameraCharacteristics) { + mParameters = new CameraMetadataWrapper(cameraCharacteristics); + } + + public RequestBuilder addTargetOutputConfigId(int... outputConfigIds) { + for (int id : outputConfigIds) { + mTargetOutputConfigIds.add(id); + } + return this; + } + + public <T> RequestBuilder setParameter(CaptureRequest.Key<T> key, T value) { + mParameters.set(key, value); + return this; + } + + public RequestBuilder setTemplateId(int templateId) { + mTemplateId = templateId; + return this; + } + + public Request build() { + Request request = new Request(); + int[] idArray = new int[mTargetOutputConfigIds.size()]; + for (int i = 0; i < idArray.length; i++) { + idArray[i] = mTargetOutputConfigIds.get(i); + } + request.targetOutputConfigIds = idArray; + request.requestId = mRequestId; + request.parameters = mParameters; + request.templateId = mTemplateId; + request.requestId = sNextRequestId.getAndIncrement(); + return request; + } +} diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java new file mode 100644 index 00000000..ed749aec --- /dev/null +++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java @@ -0,0 +1,383 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.oemextensions; + +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.os.RemoteException; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.camera.extensions.impl.service.CameraMetadataWrapper; +import androidx.camera.extensions.impl.service.CameraOutputConfig; +import androidx.camera.extensions.impl.service.CameraSessionConfig; +import androidx.camera.extensions.impl.service.CaptureFailureWrapper; +import androidx.camera.extensions.impl.service.CaptureResultWrapper; +import androidx.camera.extensions.impl.service.ICaptureCallback; +import androidx.camera.extensions.impl.service.IRequestCallback; +import androidx.camera.extensions.impl.service.IRequestProcessorImpl; +import androidx.camera.extensions.impl.service.ISessionProcessorImpl; +import androidx.camera.extensions.impl.service.OutputSurface; +import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Demonstrates a very simple SessionProcessor which just pass all the output surface into the + * camera pipeline directly. No postprocessing is performed. + */ +public class SimpleSessionProcessorStub extends ISessionProcessorImpl.Stub { + private static final String TAG = "SimpleSessionProcessor"; + private final CameraCharacteristics mCameraCharacteristics; + private final Set<CaptureRequest.Key> mSupportedRequestKeys; + private final Set<CaptureResult.Key> mSupportedResultKeys; + + private IRequestProcessorImpl mIRequestProcessor; + private AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1); + private Map<CaptureRequest.Key, Object> mParameters = new HashMap<>(); + private boolean mHasAnalysisOutput = false; + + private static final int PREVIEW_OUTPUT_ID = 1; + private static final int CAPTURE_OUTPUT_ID = 2; + private static final int ANALYSIS_OUTPUT_ID = 3; + + public SimpleSessionProcessorStub(@NonNull CameraCharacteristics cameraCharacteristics, + @NonNull Set<CaptureRequest.Key> supportedRequestKeys, + @NonNull Set<CaptureResult.Key> supportedResultKeys) { + mCameraCharacteristics = cameraCharacteristics; + mSupportedRequestKeys = supportedRequestKeys; + mSupportedResultKeys = supportedResultKeys; + } + + @Override + public CameraSessionConfig initSession(@NonNull String cameraId, + @NonNull OutputSurface outputSurfacePreview, + @NonNull OutputSurface outputSurfaceStillCapture, + @Nullable OutputSurface outputSurfaceAnalysis) throws RemoteException { + Log.d(TAG, "initSession cameraId=" + cameraId); + CameraSessionConfig cameraSessionConfig = new CameraSessionConfig(); + cameraSessionConfig.sessionParameter = new CameraMetadataWrapper(mCameraCharacteristics); + // if needed, invoke cameraSessionConfig.sessionParameter.set(...) to set session parameters + cameraSessionConfig.sessionTemplateId = CameraDevice.TEMPLATE_PREVIEW; + List<CameraOutputConfig> outputConfigList = new ArrayList<>(); + + // Preview + CameraOutputConfig previewOutputConfig = + CameraOutputConfigBuilder + .createSurfaceOutput(PREVIEW_OUTPUT_ID, outputSurfacePreview.surface) + .build(); + outputConfigList.add(previewOutputConfig); + + // Still capture + CameraOutputConfig captureOutputConfig = + CameraOutputConfigBuilder + .createSurfaceOutput(CAPTURE_OUTPUT_ID, outputSurfaceStillCapture.surface) + .build(); + outputConfigList.add(captureOutputConfig); + + // ImageAnalysis + if (outputSurfaceAnalysis != null) { + mHasAnalysisOutput = true; + CameraOutputConfig analysisOutputConfig = + CameraOutputConfigBuilder + .createSurfaceOutput(ANALYSIS_OUTPUT_ID, outputSurfaceAnalysis.surface) + .build(); + outputConfigList.add(analysisOutputConfig); + } + + cameraSessionConfig.outputConfigs = outputConfigList; + return cameraSessionConfig; + } + + @Override + public void deInitSession() throws RemoteException { + Log.d(TAG, "deInitSession"); + } + + @Override + public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor) + throws RemoteException { + Log.d(TAG, "onCaptureSessionStart"); + mIRequestProcessor = requestProcessor; + } + + @Override + public void onCaptureSessionEnd() throws RemoteException { + Log.d(TAG, "onCaptureSessionEnd"); + + mIRequestProcessor = null; + } + + @Override + public void setParameters(CaptureRequest captureRequest) throws RemoteException { + Log.d(TAG, "setParameters"); + + for (CaptureRequest.Key<?> key : captureRequest.getKeys()) { + if (mSupportedRequestKeys.contains(key)) { + mParameters.put(key, captureRequest.get(key)); + } + } + } + + protected void notifyOnCaptureCompleted( + @NonNull int seqId, + @NonNull TotalCaptureResult result, + @NonNull ICaptureCallback captureCallback) { + Long shutterTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP); + if (shutterTimestamp != null) { + CameraMetadataWrapper cameraMetadataWrapper = + new CameraMetadataWrapper(mCameraCharacteristics); + + for (CaptureResult.Key key : mSupportedResultKeys) { + if (result.get(key) != null) { + cameraMetadataWrapper.set(key, result.get(key)); + } + } + + try { + captureCallback.onCaptureCompleted(shutterTimestamp, seqId, + cameraMetadataWrapper); + } catch (RemoteException e) { + Log.e(TAG, "cannot notify onCaptureCompleted", e); + } + } + } + + @Override + public int startTrigger(CaptureRequest captureRequest, ICaptureCallback captureCallback) + throws RemoteException { + Log.d(TAG, "startTrigger"); + + int captureSequenceId = mNextCaptureSequenceId.getAndIncrement(); + + RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics) + .addTargetOutputConfigId(PREVIEW_OUTPUT_ID) + .setTemplateId(CameraDevice.TEMPLATE_PREVIEW); + + if (mHasAnalysisOutput) { + requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID); + } + applyParameters(requestBuilder); + + for (CaptureRequest.Key key : captureRequest.getKeys()) { + if (mSupportedRequestKeys.contains(key)) { + requestBuilder.setParameter(key, captureRequest.get(key)); + } else { + Log.e(TAG, "startTrigger: key " + key + " not supported"); + } + } + + mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() { + @Override + public void onCaptureStarted(int requestId, long frameNumber, long timestamp) + throws RemoteException { + captureCallback.onCaptureStarted(captureSequenceId, timestamp); + } + + @Override + public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult) + throws RemoteException { + CaptureResult captureResult = partialResult.toCaptureResult(); + } + + @Override + public void onCaptureCompleted(int requestId, + TotalCaptureResultWrapper totalCaptureResult) throws RemoteException { + TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult(); + captureCallback.onCaptureProcessStarted(captureSequenceId); + notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback); + } + + @Override + public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper) + throws RemoteException { + CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure(); + captureCallback.onCaptureFailed(captureSequenceId); + } + + @Override + public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId) + throws RemoteException { + captureCallback.onCaptureFailed(captureSequenceId); + } + + @Override + public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) + throws RemoteException { + captureCallback.onCaptureSequenceCompleted(captureSequenceId); + } + + @Override + public void onCaptureSequenceAborted(int sequenceId) throws RemoteException { + captureCallback.onCaptureSequenceAborted(captureSequenceId); + } + }); + return captureSequenceId; + } + + private void applyParameters(RequestBuilder requestBuilder) { + for (CaptureRequest.Key key : mParameters.keySet()) { + requestBuilder.setParameter(key, mParameters.get(key)); + } + } + + @Override + public int startRepeating(ICaptureCallback captureCallback) throws RemoteException { + Log.d(TAG, "startRepeating"); + + int captureSequenceId = mNextCaptureSequenceId.getAndIncrement(); + + RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics) + .addTargetOutputConfigId(PREVIEW_OUTPUT_ID) + .setTemplateId(CameraDevice.TEMPLATE_PREVIEW); + if (mHasAnalysisOutput) { + requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID); + } + applyParameters(requestBuilder); + + mIRequestProcessor.setRepeating(requestBuilder.build(), new IRequestCallback.Stub() { + @Override + public void onCaptureStarted(int requestId, long frameNumber, long timestamp) + throws RemoteException { + captureCallback.onCaptureStarted(captureSequenceId, timestamp); + + } + + @Override + public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult) + throws RemoteException { + CaptureResult captureResult = partialResult.toCaptureResult(); + } + + @Override + public void onCaptureCompleted(int requestId, + TotalCaptureResultWrapper totalCaptureResult) throws RemoteException { + TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult(); + captureCallback.onCaptureProcessStarted(captureSequenceId); + notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback); + } + + @Override + public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper) + throws RemoteException { + CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure(); + captureCallback.onCaptureFailed(captureSequenceId); + } + + @Override + public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId) + throws RemoteException { + captureCallback.onCaptureFailed(captureSequenceId); + } + + @Override + public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) + throws RemoteException { + captureCallback.onCaptureSequenceCompleted(captureSequenceId); + } + + @Override + public void onCaptureSequenceAborted(int sequenceId) throws RemoteException { + captureCallback.onCaptureSequenceAborted(captureSequenceId); + } + }); + return captureSequenceId; + } + + @Override + public void stopRepeating() throws RemoteException { + Log.d(TAG, "stopRepeating"); + + mIRequestProcessor.stopRepeating(); + } + + @Override + public int startCapture(ICaptureCallback captureCallback) throws RemoteException { + Log.d(TAG, "startCapture"); + + int captureSequenceId = mNextCaptureSequenceId.getAndIncrement(); + + RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics) + .addTargetOutputConfigId(CAPTURE_OUTPUT_ID) + .setTemplateId(CameraDevice.TEMPLATE_STILL_CAPTURE); + + applyParameters(requestBuilder); + + mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() { + @Override + public void onCaptureStarted(int requestId, long frameNumber, long timestamp) + throws RemoteException { + captureCallback.onCaptureStarted(captureSequenceId, timestamp); + } + + @Override + public void onCaptureProgressed(int requestId, + CaptureResultWrapper captureResultWrapper) + throws RemoteException { + } + + @Override + public void onCaptureCompleted(int requestId, + TotalCaptureResultWrapper totalCaptureResultWrapper) throws RemoteException { + TotalCaptureResult captureResult = totalCaptureResultWrapper.toTotalCaptureResult(); + captureCallback.onCaptureProcessStarted(captureSequenceId); + notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback); + } + + @Override + public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper) + throws RemoteException { + captureCallback.onCaptureFailed(captureSequenceId); + } + + @Override + public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId) + throws RemoteException { + captureCallback.onCaptureFailed(captureSequenceId); + } + + @Override + public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) + throws RemoteException { + captureCallback.onCaptureSequenceCompleted(captureSequenceId); + } + + @Override + public void onCaptureSequenceAborted(int sequenceId) throws RemoteException { + captureCallback.onCaptureSequenceAborted(captureSequenceId); + + } + }); + return captureSequenceId; + } + + @Override + public void abortCapture(int i) throws RemoteException { + Log.d(TAG, "abortCapture"); + mIRequestProcessor.abortCaptures(); + } +} |