summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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));
}
}