diff options
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)); } } |