summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Emilian Peev <epeev@google.com> 2022-03-04 15:46:19 -0800
committer Emilian Peev <epeev@google.com> 2022-04-11 15:33:31 -0700
commitd6b3ab77a0ea18ef1fd019881011cc0341dff104 (patch)
treecb7d11cd42d21cf22d97bd8082ee52cd3f8b95f1
parentc31090f0e23467a25c7fe1f90758a29ba0be596b (diff)
Camera: Add support for client requests&results for advanced extensions
Allow camera clients to query for any orthogonal camera parameters that can be applied during advanced extension capture sessions. Enable capture result callbacks in the same scenario as well as single catpure requests to the preview client surface. Bug: 198447410 Test: Camera CTS Change-Id: Ia51cc0813a93963d628ea73beb54ed080f4696e7
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java51
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionSession.java15
-rw-r--r--core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl3
-rw-r--r--core/java/android/hardware/camera2/extension/ICaptureCallback.aidl2
-rw-r--r--core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl5
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java75
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java1
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java116
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java105
9 files changed, 279 insertions, 94 deletions
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index aa98f1fdf9bc..cf611fb3adcf 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -824,24 +824,34 @@ public final class CameraExtensionCharacteristics {
if (!isExtensionSupported(mCameraId, extension, mChars)) {
throw new IllegalArgumentException("Unsupported extension");
}
- Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
- initializeExtension(extension);
- extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
- extenders.second.init(mCameraId, mChars.getNativeMetadata());
- CameraMetadataNative captureRequestMeta =
- extenders.second.getAvailableCaptureRequestKeys();
+
+ CameraMetadataNative captureRequestMeta = null;
+ if (areAdvancedExtensionsSupported()) {
+ IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
+ extender.init(mCameraId);
+ captureRequestMeta = extender.getAvailableCaptureRequestKeys(mCameraId);
+ } else {
+ Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+ initializeExtension(extension);
+ extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
+ extenders.second.init(mCameraId, mChars.getNativeMetadata());
+ captureRequestMeta = extenders.second.getAvailableCaptureRequestKeys();
+ extenders.second.onDeInit();
+ }
if (captureRequestMeta != null) {
int[] requestKeys = captureRequestMeta.get(
CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS);
if (requestKeys == null) {
- throw new AssertionError("android.request.availableRequestKeys must be non-null"
- + " in the characteristics");
+ throw new AssertionError(
+ "android.request.availableRequestKeys must be non-null"
+ + " in the characteristics");
}
- CameraCharacteristics requestChars = new CameraCharacteristics(captureRequestMeta);
+ CameraCharacteristics requestChars = new CameraCharacteristics(
+ captureRequestMeta);
Object crKey = CaptureRequest.Key.class;
- Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
+ Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>) crKey;
ret.addAll(requestChars.getAvailableKeyList(CaptureRequest.class, crKeyTyped,
requestKeys, /*includeSynthetic*/ false));
@@ -854,7 +864,6 @@ public final class CameraExtensionCharacteristics {
if (!ret.contains(CaptureRequest.JPEG_ORIENTATION)) {
ret.add(CaptureRequest.JPEG_ORIENTATION);
}
- extenders.second.onDeInit();
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture request keys!");
} finally {
@@ -894,12 +903,19 @@ public final class CameraExtensionCharacteristics {
throw new IllegalArgumentException("Unsupported extension");
}
- Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
- initializeExtension(extension);
- extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
- extenders.second.init(mCameraId, mChars.getNativeMetadata());
- CameraMetadataNative captureResultMeta =
- extenders.second.getAvailableCaptureResultKeys();
+ CameraMetadataNative captureResultMeta = null;
+ if (areAdvancedExtensionsSupported()) {
+ IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
+ extender.init(mCameraId);
+ captureResultMeta = extender.getAvailableCaptureResultKeys(mCameraId);
+ } else {
+ Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+ initializeExtension(extension);
+ extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
+ extenders.second.init(mCameraId, mChars.getNativeMetadata());
+ captureResultMeta = extenders.second.getAvailableCaptureResultKeys();
+ extenders.second.onDeInit();
+ }
if (captureResultMeta != null) {
int[] resultKeys = captureResultMeta.get(
@@ -926,7 +942,6 @@ public final class CameraExtensionCharacteristics {
ret.add(CaptureResult.SENSOR_TIMESTAMP);
}
}
- extenders.second.onDeInit();
} catch (RemoteException e) {
throw new IllegalStateException("Failed to query the available capture result keys!");
} finally {
diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java
index ee3441fc16f1..6ddaddf8a809 100644
--- a/core/java/android/hardware/camera2/CameraExtensionSession.java
+++ b/core/java/android/hardware/camera2/CameraExtensionSession.java
@@ -265,8 +265,8 @@ public abstract class CameraExtensionSession implements AutoCloseable {
* from the camera device, to produce a single high-quality output result.
*
* <p>Note that single capture requests currently do not support
- * client parameters except for {@link CaptureRequest#JPEG_ORIENTATION orientation} and
- * {@link CaptureRequest#JPEG_QUALITY quality} in case of ImageFormat.JPEG output target.
+ * client parameters except for controls advertised in
+ * {@link CameraExtensionCharacteristics#getAvailableCaptureRequestKeys}.
* The rest of the settings included in the request will be entirely overridden by
* the device-specific extension. </p>
*
@@ -275,6 +275,11 @@ public abstract class CameraExtensionSession implements AutoCloseable {
* arguments that include further targets will cause
* IllegalArgumentException to be thrown. </p>
*
+ * <p>Starting with Android {@link android.os.Build.VERSION_CODES#TIRAMISU} single capture
+ * requests will also support the preview {@link android.graphics.ImageFormat#PRIVATE} target
+ * surface. These can typically be used for enabling AF/AE triggers. Do note, that single
+ * capture requests referencing both output surfaces remain unsupported.</p>
+ *
* <p>Each request will produce one new frame for one target Surface, set
* with the CaptureRequest builder's
* {@link CaptureRequest.Builder#addTarget} method.</p>
@@ -319,8 +324,10 @@ public abstract class CameraExtensionSession implements AutoCloseable {
* rate possible.</p>
*
* <p>Note that repeating capture requests currently do not support
- * client parameters. Settings included in the request will
- * be completely overridden by the device-specific extension.</p>
+ * client parameters except for controls advertised in
+ * {@link CameraExtensionCharacteristics#getAvailableCaptureRequestKeys}.
+ * The rest of the settings included in the request will be entirely overridden by
+ * the device-specific extension. </p>
*
* <p>The {@link CaptureRequest.Builder#addTarget} supports only one
* target surface. {@link CaptureRequest} arguments that include further
diff --git a/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl b/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
index f279c59b812c..935a542b72aa 100644
--- a/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
@@ -19,6 +19,7 @@ import android.hardware.camera2.extension.ISessionProcessorImpl;
import android.hardware.camera2.extension.LatencyRange;
import android.hardware.camera2.extension.Size;
import android.hardware.camera2.extension.SizeList;
+import android.hardware.camera2.impl.CameraMetadataNative;
/** @hide */
interface IAdvancedExtenderImpl
@@ -30,4 +31,6 @@ interface IAdvancedExtenderImpl
@nullable List<SizeList> getSupportedPreviewOutputResolutions(in String cameraId);
@nullable List<SizeList> getSupportedCaptureOutputResolutions(in String cameraId);
ISessionProcessorImpl getSessionProcessor();
+ CameraMetadataNative getAvailableCaptureRequestKeys(in String cameraId);
+ CameraMetadataNative getAvailableCaptureResultKeys(in String cameraId);
}
diff --git a/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl b/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl
index 6ab0ad2c7417..f3062ad980a9 100644
--- a/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl
+++ b/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl
@@ -16,6 +16,7 @@
package android.hardware.camera2.extension;
import android.hardware.camera2.extension.Request;
+import android.hardware.camera2.impl.CameraMetadataNative;
/** @hide */
interface ICaptureCallback
@@ -25,4 +26,5 @@ interface ICaptureCallback
void onCaptureFailed(int captureSequenceId);
void onCaptureSequenceCompleted(int captureSequenceId);
void onCaptureSequenceAborted(int captureSequenceId);
+ void onCaptureCompleted(long shutterTimestamp, int requestId, in CameraMetadataNative results);
}
diff --git a/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl
index 6fdf4df775bc..0eca5a7f4c40 100644
--- a/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.camera2.extension;
+import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.extension.CameraSessionConfig;
import android.hardware.camera2.extension.ICaptureCallback;
import android.hardware.camera2.extension.IRequestProcessorImpl;
@@ -30,5 +31,7 @@ interface ISessionProcessorImpl
void onCaptureSessionEnd();
int startRepeating(in ICaptureCallback callback);
void stopRepeating();
- int startCapture(in ICaptureCallback callback, int jpegRotation, int jpegQuality);
+ int startCapture(in ICaptureCallback callback);
+ void setParameters(in CaptureRequest captureRequest);
+ int startTrigger(in CaptureRequest captureRequest, in ICaptureCallback callback);
}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 3c52d65b2f00..5503e2834d98 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -86,6 +86,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
// maps camera extension output ids to camera registered image readers
private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
private final RequestProcessor mRequestProcessor = new RequestProcessor();
+ private final int mSessionId;
private Surface mClientRepeatingRequestSurface;
private Surface mClientCaptureSurface;
@@ -175,7 +176,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(clientId,
extender, cameraDevice, repeatingRequestSurface, burstCaptureSurface,
- config.getStateCallback(), config.getExecutor());
+ config.getStateCallback(), config.getExecutor(), sessionId);
ret.initialize();
return ret;
@@ -184,7 +185,8 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
private CameraAdvancedExtensionSessionImpl(long extensionClientId,
@NonNull IAdvancedExtenderImpl extender, @NonNull CameraDevice cameraDevice,
@Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface,
- @NonNull CameraExtensionSession.StateCallback callback, @NonNull Executor executor) {
+ @NonNull CameraExtensionSession.StateCallback callback, @NonNull Executor executor,
+ int sessionId) {
mExtensionClientId = extensionClientId;
mAdvancedExtender = extender;
mCameraDevice = cameraDevice;
@@ -197,6 +199,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
mHandler = new Handler(mHandlerThread.getLooper());
mInitialized = false;
mInitializeHandler = new InitializeSessionHandler();
+ mSessionId = sessionId;
}
/**
@@ -367,6 +370,8 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
}
try {
+ mSessionProcessor.setParameters(request);
+
seqId = mSessionProcessor.startRepeating(new RequestCallbackHandler(request,
executor, listener));
} catch (RemoteException e) {
@@ -388,34 +393,32 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
throw new IllegalStateException("Uninitialized component");
}
- if (mClientCaptureSurface == null) {
- throw new IllegalArgumentException("No output surface registered for single"
- + " requests!");
+ if (request.getTargets().size() != 1) {
+ throw new IllegalArgumentException("Single capture to both preview & still" +
+ " capture outputs target is not supported!");
}
- if (!request.containsTarget(mClientCaptureSurface) ||
- (request.getTargets().size() != 1)) {
- throw new IllegalArgumentException("Invalid single capture output target!");
- }
+ if ((mClientCaptureSurface != null) && request.containsTarget(mClientCaptureSurface)) {
+ try {
+ mSessionProcessor.setParameters(request);
- try {
- // This will override the extension capture stage jpeg parameters with the user set
- // jpeg quality and rotation. This will guarantee that client configured jpeg
- // parameters always have highest priority.
- Integer jpegRotation = request.get(CaptureRequest.JPEG_ORIENTATION);
- if (jpegRotation == null) {
- jpegRotation = CameraExtensionUtils.JPEG_DEFAULT_ROTATION;
+ seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
+ executor, listener));
+ } catch (RemoteException e) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
+ " to submit capture request, extension service failed to respond!");
}
- Byte jpegQuality = request.get(CaptureRequest.JPEG_QUALITY);
- if (jpegQuality == null) {
- jpegQuality = CameraExtensionUtils.JPEG_DEFAULT_QUALITY;
+ } else if ((mClientRepeatingRequestSurface != null) &&
+ request.containsTarget(mClientRepeatingRequestSurface)) {
+ try {
+ seqId = mSessionProcessor.startTrigger(request,
+ new RequestCallbackHandler(request, executor, listener));
+ } catch (RemoteException e) {
+ throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
+ " to submit trigger request, extension service failed to respond!");
}
-
- seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
- executor, listener), jpegRotation, jpegQuality);
- } catch (RemoteException e) {
- throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
- "Failed to submit capture request, extension service failed to respond!");
+ } else {
+ throw new IllegalArgumentException("Invalid single capture output target!");
}
}
@@ -661,6 +664,28 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
Binder.restoreCallingIdentity(ident);
}
}
+
+ @Override
+ public void onCaptureCompleted(long timestamp, int requestId, CameraMetadataNative result) {
+ if (result == null) {
+ Log.e(TAG,"Invalid capture result!");
+ return;
+ }
+
+ result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
+ TotalCaptureResult totalResult = new TotalCaptureResult(mCameraDevice.getId(), result,
+ mClientRequest, requestId, timestamp, new ArrayList<>(), mSessionId,
+ new PhysicalCaptureResultInfo[0]);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(
+ () -> mClientCallbacks.onCaptureResultAvailable(
+ CameraAdvancedExtensionSessionImpl.this, mClientRequest,
+ totalResult));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private final class CaptureCallbackHandler extends CameraCaptureSession.CaptureCallback {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index 1514a2be5de8..aee20db6783e 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -303,6 +303,7 @@ public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
jpegBuffer, jpegCapacity, jpegParams.mQuality,
0, 0, yuvImage.getWidth(), yuvImage.getHeight(),
jpegParams.mRotation);
+ jpegImage.setTimestamp(yuvImage.getTimestamp());
yuvImage.close();
try {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 916d16d92977..1263da6e4884 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -475,8 +475,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mInternalRepeatingRequestEnabled = false;
try {
return setRepeatingRequest(mPreviewExtender.getCaptureStage(),
- new RepeatingRequestHandler(request, executor, listener,
- mRepeatingRequestImageCallback));
+ new PreviewRequestHandler(request, executor, listener,
+ mRepeatingRequestImageCallback), request);
} catch (RemoteException e) {
Log.e(TAG, "Failed to set repeating request! Extension service does not "
+ "respond");
@@ -530,7 +530,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
CaptureRequest request = requestBuilder.build();
CameraMetadataNative.update(request.getNativeMetadata(), captureStage.parameters);
ret.add(request);
- captureMap.put(request, captureStage.id);
+ if (captureMap != null) {
+ captureMap.put(request, captureStage.id);
+ }
}
return ret;
@@ -583,33 +585,57 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
throw new IllegalStateException("Uninitialized component");
}
- if (mClientCaptureSurface == null) {
- throw new IllegalArgumentException("No output surface registered for single requests!");
+ if (request.getTargets().size() != 1) {
+ throw new IllegalArgumentException("Single capture to both preview & still capture " +
+ "outputs target is not supported!");
}
- if (!request.containsTarget(mClientCaptureSurface) || (request.getTargets().size() != 1)) {
- throw new IllegalArgumentException("Invalid single capture output target!");
- }
+ int seqId = -1;
+ if ((mClientCaptureSurface != null) && request.containsTarget(mClientCaptureSurface)) {
+ HashMap<CaptureRequest, Integer> requestMap = new HashMap<>();
+ List<CaptureRequest> burstRequest;
+ try {
+ burstRequest = createBurstRequest(mCameraDevice,
+ mImageExtender.getCaptureStages(), request, mCameraBurstSurface,
+ CameraDevice.TEMPLATE_STILL_CAPTURE, requestMap);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to initialize internal burst request! Extension service does"
+ + " not respond!");
+ throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
+ }
+ if (burstRequest == null) {
+ throw new UnsupportedOperationException(
+ "Failed to create still capture burst request");
+ }
- HashMap<CaptureRequest, Integer> requestMap = new HashMap<>();
- List<CaptureRequest> burstRequest;
- try {
- burstRequest = createBurstRequest(mCameraDevice,
- mImageExtender.getCaptureStages(), request, mCameraBurstSurface,
- CameraDevice.TEMPLATE_STILL_CAPTURE, requestMap);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to initialize internal burst request! Extension service does"
- + " not respond!");
- throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
- }
- if (burstRequest == null) {
- throw new UnsupportedOperationException("Failed to create still capture burst request");
+ seqId = mCaptureSession.captureBurstRequests(burstRequest,
+ new CameraExtensionUtils.HandlerExecutor(mHandler),
+ new BurstRequestHandler(request, executor, listener, requestMap,
+ mBurstCaptureImageCallback));
+ } else if ((mClientRepeatingRequestSurface != null) &&
+ request.containsTarget(mClientRepeatingRequestSurface)) {
+
+ CaptureRequest captureRequest = null;
+ try {
+ ArrayList<CaptureStageImpl> captureStageList = new ArrayList<>();
+ captureStageList.add(mPreviewExtender.getCaptureStage());
+
+ captureRequest = createRequest(mCameraDevice, captureStageList,
+ mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW, request);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to initialize capture request! Extension service does"
+ + " not respond!");
+ throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
+ }
+
+ seqId = mCaptureSession.capture(captureRequest, new PreviewRequestHandler(request,
+ executor, listener, mRepeatingRequestImageCallback, true /*singleCapture*/),
+ mHandler);
+ } else {
+ throw new IllegalArgumentException("Capture request to unknown output surface!");
}
- return mCaptureSession.captureBurstRequests(burstRequest,
- new CameraExtensionUtils.HandlerExecutor(mHandler),
- new BurstRequestHandler(request, executor, listener, requestMap,
- mBurstCaptureImageCallback));
+ return seqId;
}
@Override
@@ -847,7 +873,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} else {
try {
setRepeatingRequest(mPreviewExtender.getCaptureStage(),
- new RepeatingRequestHandler(null, null, null,
+ new PreviewRequestHandler(null, null, null,
mRepeatingRequestImageCallback));
} catch (CameraAccessException | RemoteException e) {
Log.e(TAG,
@@ -1010,7 +1036,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
if (timestamp != null) {
if (mCaptureResultsSupported && (mCaptureResultHandler == null)) {
mCaptureResultHandler = new CaptureResultHandler(mClientRequest, mExecutor,
- mCallbacks, result.getSessionId());
+ mCallbacks, result.getSequenceId());
}
if (mImageProcessor != null) {
if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
@@ -1179,7 +1205,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
*/
try {
setRepeatingRequest(mPreviewExtender.getCaptureStage(),
- new RepeatingRequestHandler(null, null, null,
+ new PreviewRequestHandler(null, null, null,
mImageCallback));
} catch (CameraAccessException | RemoteException e) {
Log.e(TAG, "Failed to start the internal repeating request!");
@@ -1320,17 +1346,20 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
}
- // This handler can operate in two modes:
+ // This handler can operate in three modes:
// 1) Using valid client callbacks, which means camera buffers will be propagated the
// registered output surfaces and clients will be notified accordingly.
// 2) Without any client callbacks where an internal repeating request is kept active
// to satisfy the extensions continuous preview/(repeating request) requirement.
- private class RepeatingRequestHandler extends CameraCaptureSession.CaptureCallback {
+ // 3) Single capture mode, where internal repeating requests are ignored and the preview
+ // logic is only triggered for the image processor case.
+ private class PreviewRequestHandler extends CameraCaptureSession.CaptureCallback {
private final Executor mExecutor;
private final ExtensionCaptureCallback mCallbacks;
private final CaptureRequest mClientRequest;
private final boolean mClientNotificationsEnabled;
private final CameraOutputImageCallback mRepeatingImageCallback;
+ private final boolean mSingleCapture;
private OnImageAvailableListener mImageCallback = null;
private LongSparseArray<Pair<Image, TotalCaptureResult>> mPendingResultMap =
new LongSparseArray<>();
@@ -1338,15 +1367,22 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private boolean mRequestUpdatedNeeded = false;
- public RepeatingRequestHandler(@Nullable CaptureRequest clientRequest,
+ public PreviewRequestHandler(@Nullable CaptureRequest clientRequest,
@Nullable Executor executor, @Nullable ExtensionCaptureCallback listener,
@NonNull CameraOutputImageCallback imageCallback) {
+ this(clientRequest, executor, listener, imageCallback, false /*singleCapture*/);
+ }
+
+ public PreviewRequestHandler(@Nullable CaptureRequest clientRequest,
+ @Nullable Executor executor, @Nullable ExtensionCaptureCallback listener,
+ @NonNull CameraOutputImageCallback imageCallback, boolean singleCapture) {
mClientRequest = clientRequest;
mExecutor = executor;
mCallbacks = listener;
mClientNotificationsEnabled =
(mClientRequest != null) && (mExecutor != null) && (mCallbacks != null);
mRepeatingImageCallback = imageCallback;
+ mSingleCapture = singleCapture;
}
@Override
@@ -1393,7 +1429,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session,
int sequenceId) {
synchronized (mInterfaceLock) {
- if (mInternalRepeatingRequestEnabled) {
+ if (mInternalRepeatingRequestEnabled && !mSingleCapture) {
resumeInternalRepeatingRequest(true);
}
}
@@ -1420,10 +1456,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
long frameNumber) {
synchronized (mInterfaceLock) {
- if (mRequestUpdatedNeeded) {
+ if (mRequestUpdatedNeeded && !mSingleCapture) {
mRequestUpdatedNeeded = false;
resumeInternalRepeatingRequest(false);
- } else if (mInternalRepeatingRequestEnabled) {
+ } else if (mInternalRepeatingRequestEnabled && !mSingleCapture) {
resumeInternalRepeatingRequest(true);
}
}
@@ -1471,10 +1507,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
if (mCaptureResultsSupported && mClientNotificationsEnabled &&
(mCaptureResultHandler == null)) {
mCaptureResultHandler = new CaptureResultHandler(mClientRequest, mExecutor,
- mCallbacks, result.getSessionId());
+ mCallbacks, result.getSequenceId());
}
- if (mPreviewProcessorType ==
- IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) {
+ if ((!mSingleCapture) && (mPreviewProcessorType ==
+ IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY)) {
CaptureStageImpl captureStage = null;
try {
captureStage = mPreviewRequestUpdateProcessor.process(
@@ -1582,10 +1618,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
try {
if (internal) {
setRepeatingRequest(mPreviewExtender.getCaptureStage(),
- new RepeatingRequestHandler(null, null, null,
+ new PreviewRequestHandler(null, null, null,
mRepeatingImageCallback));
} else {
- setRepeatingRequest(mPreviewExtender.getCaptureStage(), this);
+ setRepeatingRequest(mPreviewExtender.getCaptureStage(), this, mClientRequest);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to resume internal repeating request, extension service"
@@ -1733,7 +1769,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
private static Size findSmallestAspectMatchedSize(@NonNull List<Size> sizes,
- @NonNull Size arSize) {
+ @NonNull Size arSize) {
final float TOLL = .01f;
if (arSize.getHeight() == 0) {
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index c9903ea19868..e27b7a659ae6 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -19,6 +19,7 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.graphics.Camera;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
@@ -752,13 +753,65 @@ public class CameraExtensionsProxyService extends Service {
public ISessionProcessorImpl getSessionProcessor() {
return new SessionProcessorImplStub(mAdvancedExtender.createSessionProcessor());
}
+
+ @Override
+ public CameraMetadataNative getAvailableCaptureRequestKeys(String cameraId) {
+ if (RESULT_API_SUPPORTED) {
+ List<CaptureRequest.Key> supportedCaptureKeys =
+ mAdvancedExtender.getAvailableCaptureRequestKeys();
+
+ if ((supportedCaptureKeys != null) && !supportedCaptureKeys.isEmpty()) {
+ CameraMetadataNative ret = new CameraMetadataNative();
+ long vendorId = mMetadataVendorIdMap.containsKey(cameraId) ?
+ mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
+ ret.setVendorId(vendorId);
+ int requestKeyTags [] = new int[supportedCaptureKeys.size()];
+ int i = 0;
+ for (CaptureRequest.Key key : supportedCaptureKeys) {
+ requestKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
+ }
+ ret.set(CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS, requestKeyTags);
+
+ return ret;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public CameraMetadataNative getAvailableCaptureResultKeys(String cameraId) {
+ if (RESULT_API_SUPPORTED) {
+ List<CaptureResult.Key> supportedResultKeys =
+ mAdvancedExtender.getAvailableCaptureResultKeys();
+
+ if ((supportedResultKeys != null) && !supportedResultKeys.isEmpty()) {
+ CameraMetadataNative ret = new CameraMetadataNative();
+ long vendorId = mMetadataVendorIdMap.containsKey(cameraId) ?
+ mMetadataVendorIdMap.get(cameraId) : Long.MAX_VALUE;
+ ret.setVendorId(vendorId);
+ int resultKeyTags [] = new int[supportedResultKeys.size()];
+ int i = 0;
+ for (CaptureResult.Key key : supportedResultKeys) {
+ resultKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
+ }
+ ret.set(CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS, resultKeyTags);
+
+ return ret;
+ }
+ }
+
+ return null;
+ }
}
private class CaptureCallbackStub implements SessionProcessorImpl.CaptureCallback {
private final ICaptureCallback mCaptureCallback;
+ private final String mCameraId;
- private CaptureCallbackStub(ICaptureCallback captureCallback) {
+ private CaptureCallbackStub(ICaptureCallback captureCallback, String cameraId) {
mCaptureCallback = captureCallback;
+ mCameraId = cameraId;
}
@Override
@@ -820,6 +873,29 @@ public class CameraExtensionsProxyService extends Service {
}
}
}
+
+ @Override
+ public void onCaptureCompleted(long timestamp, int requestId,
+ Map<CaptureResult.Key, Object> result) {
+
+ if (result == null) {
+ Log.e(TAG, "Invalid capture result received!");
+ }
+
+ CameraMetadataNative captureResults = new CameraMetadataNative();
+ if (mMetadataVendorIdMap.containsKey(mCameraId)) {
+ captureResults.setVendorId(mMetadataVendorIdMap.get(mCameraId));
+ }
+ for (Map.Entry<CaptureResult.Key, Object> entry : result.entrySet()) {
+ captureResults.set(entry.getKey(), entry.getValue());
+ }
+
+ try {
+ mCaptureCallback.onCaptureCompleted(timestamp, requestId, captureResults);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to notify capture complete due to remote exception!");
+ }
+ }
}
private class RequestCallbackStub extends IRequestCallback.Stub {
@@ -1124,7 +1200,7 @@ public class CameraExtensionsProxyService extends Service {
@Override
public int startRepeating(ICaptureCallback callback) {
- return mSessionProcessor.startRepeating(new CaptureCallbackStub(callback));
+ return mSessionProcessor.startRepeating(new CaptureCallbackStub(callback, mCameraId));
}
@Override
@@ -1133,12 +1209,29 @@ public class CameraExtensionsProxyService extends Service {
}
@Override
- public int startCapture(ICaptureCallback callback, int jpegRotation, int jpegQuality) {
+ public void setParameters(CaptureRequest captureRequest) {
HashMap<CaptureRequest.Key<?>, Object> paramMap = new HashMap<>();
- paramMap.put(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
- paramMap.put(CaptureRequest.JPEG_QUALITY, jpegQuality);
+ for (CaptureRequest.Key captureRequestKey : captureRequest.getKeys()) {
+ paramMap.put(captureRequestKey, captureRequest.get(captureRequestKey));
+ }
+
mSessionProcessor.setParameters(paramMap);
- return mSessionProcessor.startCapture(new CaptureCallbackStub(callback));
+ }
+
+ @Override
+ public int startTrigger(CaptureRequest captureRequest, ICaptureCallback callback) {
+ HashMap<CaptureRequest.Key<?>, Object> triggerMap = new HashMap<>();
+ for (CaptureRequest.Key captureRequestKey : captureRequest.getKeys()) {
+ triggerMap.put(captureRequestKey, captureRequest.get(captureRequestKey));
+ }
+
+ return mSessionProcessor.startTrigger(triggerMap,
+ new CaptureCallbackStub(callback, mCameraId));
+ }
+
+ @Override
+ public int startCapture(ICaptureCallback callback) {
+ return mSessionProcessor.startCapture(new CaptureCallbackStub(callback, mCameraId));
}
}