Merge "Camera: Add support for client requests&results for advanced extensions" into tm-dev
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,35 +393,33 @@ 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)) {
|
||||
if ((mClientCaptureSurface != null) && request.containsTarget(mClientCaptureSurface)) {
|
||||
try {
|
||||
mSessionProcessor.setParameters(request);
|
||||
|
||||
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!");
|
||||
}
|
||||
} 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!");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid single capture output target!");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Byte jpegQuality = request.get(CaptureRequest.JPEG_QUALITY);
|
||||
if (jpegQuality == null) {
|
||||
jpegQuality = CameraExtensionUtils.JPEG_DEFAULT_QUALITY;
|
||||
}
|
||||
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
return seqId;
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user