• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.camera2.impl;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.content.Context;
23 import android.graphics.ColorSpace;
24 import android.graphics.ImageFormat;
25 import android.graphics.SurfaceTexture;
26 import android.hardware.SyncFence;
27 import android.hardware.camera2.CameraAccessException;
28 import android.hardware.camera2.CameraCaptureSession;
29 import android.hardware.camera2.CameraCharacteristics;
30 import android.hardware.camera2.CameraDevice;
31 import android.hardware.camera2.CameraExtensionCharacteristics;
32 import android.hardware.camera2.CameraExtensionSession;
33 import android.hardware.camera2.CaptureFailure;
34 import android.hardware.camera2.CaptureRequest;
35 import android.hardware.camera2.CaptureResult;
36 import android.hardware.camera2.TotalCaptureResult;
37 import android.hardware.camera2.extension.CameraOutputConfig;
38 import android.hardware.camera2.extension.CameraSessionConfig;
39 import android.hardware.camera2.extension.IAdvancedExtenderImpl;
40 import android.hardware.camera2.extension.ICaptureCallback;
41 import android.hardware.camera2.extension.IImageProcessorImpl;
42 import android.hardware.camera2.extension.IInitializeSessionCallback;
43 import android.hardware.camera2.extension.IRequestCallback;
44 import android.hardware.camera2.extension.IRequestProcessorImpl;
45 import android.hardware.camera2.extension.ISessionProcessorImpl;
46 import android.hardware.camera2.extension.LatencyPair;
47 import android.hardware.camera2.extension.OutputConfigId;
48 import android.hardware.camera2.extension.OutputSurface;
49 import android.hardware.camera2.extension.ParcelCaptureResult;
50 import android.hardware.camera2.extension.ParcelImage;
51 import android.hardware.camera2.extension.ParcelTotalCaptureResult;
52 import android.hardware.camera2.extension.Request;
53 import android.hardware.camera2.params.ColorSpaceProfiles;
54 import android.hardware.camera2.params.DynamicRangeProfiles;
55 import android.hardware.camera2.params.ExtensionSessionConfiguration;
56 import android.hardware.camera2.params.OutputConfiguration;
57 import android.hardware.camera2.params.SessionConfiguration;
58 import android.hardware.camera2.utils.ExtensionSessionStatsAggregator;
59 import android.hardware.camera2.utils.SurfaceUtils;
60 import android.media.Image;
61 import android.media.ImageReader;
62 import android.os.Binder;
63 import android.os.Handler;
64 import android.os.HandlerThread;
65 import android.os.IBinder;
66 import android.os.RemoteException;
67 import android.util.IntArray;
68 import android.util.Log;
69 import android.util.Size;
70 import android.view.Surface;
71 
72 import com.android.internal.camera.flags.Flags;
73 
74 import java.io.IOException;
75 import java.util.ArrayList;
76 import java.util.Arrays;
77 import java.util.HashMap;
78 import java.util.List;
79 import java.util.Map;
80 import java.util.concurrent.Executor;
81 
82 public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSession {
83     private static final String TAG = "CameraAdvancedExtensionSessionImpl";
84 
85     private final Executor mExecutor;
86     private CameraDevice mCameraDevice;
87     private final Map<String, CameraMetadataNative> mCharacteristicsMap;
88     private final Handler mHandler;
89     private final HandlerThread mHandlerThread;
90     private final CameraExtensionSession.StateCallback mCallbacks;
91     private IAdvancedExtenderImpl mAdvancedExtender;
92     // maps registered camera surfaces to extension output configs
93     private final HashMap<Surface, CameraOutputConfig> mCameraConfigMap = new HashMap<>();
94     // maps camera extension output ids to camera registered image readers
95     private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
96     private RequestProcessor mRequestProcessor = new RequestProcessor();
97     private final int mSessionId;
98     private IBinder mToken = null;
99 
100     private Surface mClientRepeatingRequestSurface;
101     private Surface mClientCaptureSurface;
102     private Surface mClientPostviewSurface;
103     private OutputConfiguration mClientRepeatingRequestOutputConfig;
104     private OutputConfiguration mClientCaptureOutputConfig;
105     private OutputConfiguration mClientPostviewOutputConfig;
106     private CameraCaptureSession mCaptureSession = null;
107     private ISessionProcessorImpl mSessionProcessor = null;
108     private final InitializeSessionHandler mInitializeHandler;
109     private final ExtensionSessionStatsAggregator mStatsAggregator;
110 
111     private boolean mInitialized;
112     private boolean mSessionClosed;
113     private int mExtensionType;
114 
115 
116     private final Context mContext;
117 
118     // Lock to synchronize cross-thread access to device public interface
119     final Object mInterfaceLock;
120 
121     /**
122      * @hide
123      */
124     @RequiresPermission(android.Manifest.permission.CAMERA)
createCameraAdvancedExtensionSession( @onNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice, @NonNull Map<String, CameraCharacteristics> characteristicsMap, @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId, @NonNull IBinder token)125     public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
126             @NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
127             @NonNull Map<String, CameraCharacteristics> characteristicsMap,
128             @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId,
129             @NonNull IBinder token)
130             throws CameraAccessException, RemoteException {
131         String cameraId = cameraDevice.getId();
132         CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
133                 cameraId, characteristicsMap);
134 
135         Map<String, CameraMetadataNative> characteristicsMapNative =
136                 CameraExtensionUtils.getCharacteristicsMapNative(characteristicsMap);
137         if (!CameraExtensionCharacteristics.isExtensionSupported(cameraDevice.getId(),
138                 config.getExtension(), characteristicsMapNative)) {
139             throw new UnsupportedOperationException("Unsupported extension type: " +
140                     config.getExtension());
141         }
142 
143         if (config.getOutputConfigurations().isEmpty() ||
144                 config.getOutputConfigurations().size() > 2) {
145             throw new IllegalArgumentException("Unexpected amount of output surfaces, received: " +
146                     config.getOutputConfigurations().size() + " expected <= 2");
147         }
148 
149         for (OutputConfiguration c : config.getOutputConfigurations()) {
150             if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) {
151                 if (Flags.cameraExtensionsCharacteristicsGet()) {
152                     DynamicRangeProfiles dynamicProfiles = extensionChars.get(
153                             config.getExtension(),
154                             CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES);
155                     if (dynamicProfiles == null || !dynamicProfiles.getSupportedProfiles()
156                             .contains(c.getDynamicRangeProfile())) {
157                         throw new IllegalArgumentException("Unsupported dynamic range profile: "
158                                 + c.getDynamicRangeProfile());
159                     }
160                 } else {
161                     throw new IllegalArgumentException("Unsupported dynamic range profile: "
162                             + c.getDynamicRangeProfile());
163                 }
164             }
165             if (c.getStreamUseCase() !=
166                     CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
167                 throw new IllegalArgumentException("Unsupported stream use case: " +
168                         c.getStreamUseCase());
169             }
170         }
171 
172         int suitableSurfaceCount = 0;
173         List<Size> supportedPreviewSizes = extensionChars.getExtensionSupportedSizes(
174                 config.getExtension(), SurfaceTexture.class);
175         Surface repeatingRequestSurface = CameraExtensionUtils.getRepeatingRequestSurface(
176                 config.getOutputConfigurations(), supportedPreviewSizes);
177         OutputConfiguration repeatingRequestOutputConfig = null;
178         if (repeatingRequestSurface != null) {
179             for (OutputConfiguration outputConfig : config.getOutputConfigurations()) {
180                 if (outputConfig.getSurface() == repeatingRequestSurface) {
181                     repeatingRequestOutputConfig = outputConfig;
182                 }
183             }
184             suitableSurfaceCount++;
185         }
186 
187         HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
188 
189         Integer[] supportedCaptureOutputFormats =
190                 new Integer[CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.size()];
191         supportedCaptureOutputFormats =
192                 CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.toArray(
193                         supportedCaptureOutputFormats);
194         for (int format : supportedCaptureOutputFormats) {
195             List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
196                     config.getExtension(), format);
197             if (supportedSizes != null) {
198                 supportedCaptureSizes.put(format, supportedSizes);
199             }
200         }
201 
202         int captureFormat = ImageFormat.UNKNOWN;
203         Surface burstCaptureSurface = CameraExtensionUtils.getBurstCaptureSurface(
204                 config.getOutputConfigurations(), supportedCaptureSizes);
205         OutputConfiguration burstCaptureOutputConfig = null;
206         if (burstCaptureSurface != null) {
207             for (OutputConfiguration outputConfig : config.getOutputConfigurations()) {
208                 if (outputConfig.getSurface() == burstCaptureSurface) {
209                     burstCaptureOutputConfig = outputConfig;
210                 }
211             }
212             suitableSurfaceCount++;
213 
214             if (Flags.analytics24q3()) {
215                 CameraExtensionUtils.SurfaceInfo burstCaptureSurfaceInfo =
216                         CameraExtensionUtils.querySurface(burstCaptureSurface);
217                 captureFormat = burstCaptureSurfaceInfo.mFormat;
218             }
219         }
220 
221         if (suitableSurfaceCount != config.getOutputConfigurations().size()) {
222             throw new IllegalArgumentException("One or more unsupported output surfaces found!");
223         }
224 
225         Surface postviewSurface = null;
226         OutputConfiguration postviewOutputConfig = config.getPostviewOutputConfiguration();
227         if (burstCaptureSurface != null && config.getPostviewOutputConfiguration() != null) {
228             CameraExtensionUtils.SurfaceInfo burstCaptureSurfaceInfo =
229                     CameraExtensionUtils.querySurface(burstCaptureSurface);
230             Size burstCaptureSurfaceSize =
231                     new Size(burstCaptureSurfaceInfo.mWidth, burstCaptureSurfaceInfo.mHeight);
232             HashMap<Integer, List<Size>> supportedPostviewSizes = new HashMap<>();
233             for (int format : supportedCaptureOutputFormats) {
234                 List<Size> supportedSizesPostview = extensionChars.getPostviewSupportedSizes(
235                         config.getExtension(), burstCaptureSurfaceSize, format);
236                 if (supportedSizesPostview != null) {
237                     supportedPostviewSizes.put(format, supportedSizesPostview);
238                 }
239             }
240 
241             postviewSurface = CameraExtensionUtils.getPostviewSurface(
242                         config.getPostviewOutputConfiguration(), supportedPostviewSizes,
243                         burstCaptureSurfaceInfo.mFormat);
244             if (postviewSurface == null) {
245                 throw new IllegalArgumentException("Unsupported output surface for postview!");
246             }
247         }
248 
249         IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
250                 config.getExtension());
251         extender.init(cameraId, characteristicsMapNative);
252 
253         CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(ctx,
254                 extender, cameraDevice, characteristicsMapNative, repeatingRequestOutputConfig,
255                 burstCaptureOutputConfig, postviewOutputConfig, config.getStateCallback(),
256                 config.getExecutor(), sessionId, token, config.getExtension());
257 
258         if (Flags.analytics24q3()) {
259             ret.mStatsAggregator.setCaptureFormat(captureFormat);
260         }
261         ret.mStatsAggregator.setClientName(ctx.getOpPackageName());
262         ret.mStatsAggregator.setExtensionType(config.getExtension());
263 
264         ret.initialize();
265 
266         return ret;
267     }
268 
CameraAdvancedExtensionSessionImpl(Context ctx, @NonNull IAdvancedExtenderImpl extender, @NonNull CameraDeviceImpl cameraDevice, Map<String, CameraMetadataNative> characteristicsMap, @Nullable OutputConfiguration repeatingRequestOutputConfig, @Nullable OutputConfiguration burstCaptureOutputConfig, @Nullable OutputConfiguration postviewOutputConfig, @NonNull StateCallback callback, @NonNull Executor executor, int sessionId, @NonNull IBinder token, int extension)269     private CameraAdvancedExtensionSessionImpl(Context ctx,
270             @NonNull IAdvancedExtenderImpl extender,
271             @NonNull CameraDeviceImpl cameraDevice,
272             Map<String, CameraMetadataNative> characteristicsMap,
273             @Nullable OutputConfiguration repeatingRequestOutputConfig,
274             @Nullable OutputConfiguration burstCaptureOutputConfig,
275             @Nullable OutputConfiguration postviewOutputConfig,
276             @NonNull StateCallback callback, @NonNull Executor executor,
277             int sessionId,
278             @NonNull IBinder token,
279             int extension) {
280         mContext = ctx;
281         mAdvancedExtender = extender;
282         mCameraDevice = cameraDevice;
283         mCharacteristicsMap = characteristicsMap;
284         mCallbacks = callback;
285         mExecutor = executor;
286         mClientRepeatingRequestOutputConfig = repeatingRequestOutputConfig;
287         mClientCaptureOutputConfig = burstCaptureOutputConfig;
288         mClientPostviewOutputConfig = postviewOutputConfig;
289         if (repeatingRequestOutputConfig != null) {
290             mClientRepeatingRequestSurface = repeatingRequestOutputConfig.getSurface();
291         }
292         if (burstCaptureOutputConfig != null) {
293             mClientCaptureSurface = burstCaptureOutputConfig.getSurface();
294         }
295         if (postviewOutputConfig != null) {
296             mClientPostviewSurface = postviewOutputConfig.getSurface();
297         }
298         mHandlerThread = new HandlerThread(TAG);
299         mHandlerThread.start();
300         mHandler = new Handler(mHandlerThread.getLooper());
301         mInitialized = false;
302         mSessionClosed = false;
303         mInitializeHandler = new InitializeSessionHandler();
304         mSessionId = sessionId;
305         mToken = token;
306         mInterfaceLock = cameraDevice.mInterfaceLock;
307         mExtensionType = extension;
308 
309         mStatsAggregator = new ExtensionSessionStatsAggregator(mCameraDevice.getId(),
310                 /*isAdvanced=*/true);
311     }
312 
313     /**
314      * @hide
315      */
initialize()316     public synchronized void initialize() throws CameraAccessException, RemoteException {
317         if (mInitialized) {
318             Log.d(TAG, "Session already initialized");
319             return;
320         }
321 
322         OutputSurface previewSurface = initializeParcelable(mClientRepeatingRequestOutputConfig);
323         OutputSurface captureSurface = initializeParcelable(mClientCaptureOutputConfig);
324         OutputSurface postviewSurface = initializeParcelable(mClientPostviewOutputConfig);
325 
326         mSessionProcessor = mAdvancedExtender.getSessionProcessor();
327         CameraSessionConfig sessionConfig = mSessionProcessor.initSession(mToken,
328                 mCameraDevice.getId(),
329                 mCharacteristicsMap, previewSurface, captureSurface, postviewSurface);
330         List<CameraOutputConfig> outputConfigs = sessionConfig.outputConfigs;
331         ArrayList<OutputConfiguration> outputList = new ArrayList<>();
332         for (CameraOutputConfig output : outputConfigs) {
333             Surface outputSurface = initializeSurface(output);
334             if (outputSurface == null) {
335                 continue;
336             }
337             OutputConfiguration cameraOutput = new OutputConfiguration(output.surfaceGroupId,
338                     outputSurface);
339 
340             if (output.isMultiResolutionOutput) {
341                 cameraOutput.setMultiResolutionOutput();
342             }
343             if ((output.sharedSurfaceConfigs != null) && !output.sharedSurfaceConfigs.isEmpty()) {
344                 cameraOutput.enableSurfaceSharing();
345                 for (CameraOutputConfig sharedOutputConfig : output.sharedSurfaceConfigs) {
346                     Surface sharedSurface = initializeSurface(sharedOutputConfig);
347                     if (sharedSurface == null) {
348                         continue;
349                     }
350                     cameraOutput.addSurface(sharedSurface);
351                     mCameraConfigMap.put(sharedSurface, sharedOutputConfig);
352                 }
353             }
354 
355             // The extension processing logic needs to be able to match images to capture results via
356             // image and result timestamps.
357             cameraOutput.setTimestampBase(OutputConfiguration.TIMESTAMP_BASE_SENSOR);
358             cameraOutput.setReadoutTimestampEnabled(false);
359             cameraOutput.setPhysicalCameraId(output.physicalCameraId);
360             boolean validDynamicRangeProfile = false;
361             for (long profile = DynamicRangeProfiles.STANDARD;
362                     profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
363                 if (output.dynamicRangeProfile == profile) {
364                     validDynamicRangeProfile = true;
365                     break;
366                 }
367             }
368             if (validDynamicRangeProfile) {
369                 cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
370             } else {
371                 Log.e(TAG, "Extension configured dynamic range profile "
372                         + output.dynamicRangeProfile
373                         + " is not valid, using default DynamicRangeProfile.STANDARD");
374             }
375             outputList.add(cameraOutput);
376             mCameraConfigMap.put(cameraOutput.getSurface(), output);
377         }
378 
379         int sessionType = SessionConfiguration.SESSION_REGULAR;
380         if (sessionConfig.sessionType != -1 &&
381                 (sessionConfig.sessionType != SessionConfiguration.SESSION_HIGH_SPEED)) {
382             sessionType = sessionConfig.sessionType;
383             Log.v(TAG, "Using session type: " + sessionType);
384         }
385 
386         SessionConfiguration sessionConfiguration = new SessionConfiguration(sessionType,
387                 outputList, new CameraExtensionUtils.HandlerExecutor(mHandler),
388                 new SessionStateHandler());
389         if (sessionConfig.colorSpace >= 0
390                 && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
391             sessionConfiguration.setColorSpace(
392                     ColorSpace.Named.values()[sessionConfig.colorSpace]);
393         } else {
394             Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
395                     + " is not valid, using default unspecified color space");
396         }
397         if ((sessionConfig.sessionParameter != null) &&
398                 (!sessionConfig.sessionParameter.isEmpty())) {
399             CaptureRequest.Builder requestBuilder = mCameraDevice.createCaptureRequest(
400                     sessionConfig.sessionTemplateId);
401             CaptureRequest sessionRequest = requestBuilder.build();
402             CameraMetadataNative.update(sessionRequest.getNativeMetadata(),
403                     sessionConfig.sessionParameter);
404             sessionConfiguration.setSessionParameters(sessionRequest);
405         }
406 
407         mCameraDevice.createCaptureSession(sessionConfiguration);
408     }
409 
initializeParcelable(CaptureResult result)410     private static ParcelCaptureResult initializeParcelable(CaptureResult result) {
411         ParcelCaptureResult ret = new ParcelCaptureResult();
412         ret.cameraId = result.getCameraId();
413         ret.results = result.getNativeMetadata();
414         ret.parent = result.getRequest();
415         ret.sequenceId = result.getSequenceId();
416         ret.frameNumber = result.getFrameNumber();
417 
418         return ret;
419     }
420 
initializeParcelable(TotalCaptureResult totalResult)421     private static ParcelTotalCaptureResult initializeParcelable(TotalCaptureResult totalResult) {
422         ParcelTotalCaptureResult ret = new ParcelTotalCaptureResult();
423         ret.logicalCameraId = totalResult.getCameraId();
424         ret.results = totalResult.getNativeMetadata();
425         ret.parent = totalResult.getRequest();
426         ret.sequenceId = totalResult.getSequenceId();
427         ret.frameNumber = totalResult.getFrameNumber();
428         ret.sessionId = totalResult.getSessionId();
429         ret.partials = new ArrayList<>(totalResult.getPartialResults().size());
430         for (CaptureResult partial : totalResult.getPartialResults()) {
431             ret.partials.add(initializeParcelable(partial));
432         }
433         Map<String, TotalCaptureResult> physicalResults =
434                 totalResult.getPhysicalCameraTotalResults();
435         ret.physicalResult = new ArrayList<>(physicalResults.size());
436         for (TotalCaptureResult physicalResult : physicalResults.values()) {
437             ret.physicalResult.add(new PhysicalCaptureResultInfo(physicalResult.getCameraId(),
438                     physicalResult.getNativeMetadata()));
439         }
440 
441         return ret;
442     }
443 
initializeParcelable(OutputConfiguration o)444     private static OutputSurface initializeParcelable(OutputConfiguration o) {
445         OutputSurface ret = new OutputSurface();
446 
447         if (o != null && o.getSurface() != null) {
448             Surface s = o.getSurface();
449             ret.surface = s;
450             ret.size = new android.hardware.camera2.extension.Size();
451             Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
452             ret.size.width = surfaceSize.getWidth();
453             ret.size.height = surfaceSize.getHeight();
454             ret.imageFormat = SurfaceUtils.getSurfaceFormat(s);
455 
456             ret.dynamicRangeProfile = o.getDynamicRangeProfile();
457             ColorSpace colorSpace = o.getColorSpace();
458             if (colorSpace != null) {
459                 ret.colorSpace = colorSpace.getId();
460             } else {
461                 ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
462             }
463         } else {
464             ret.surface = null;
465             ret.size = new android.hardware.camera2.extension.Size();
466             ret.size.width = -1;
467             ret.size.height = -1;
468             ret.imageFormat = ImageFormat.UNKNOWN;
469             ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
470             ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
471         }
472 
473         return ret;
474     }
475 
476     @Override
getDevice()477     public @NonNull CameraDevice getDevice() {
478         synchronized (mInterfaceLock) {
479             return mCameraDevice;
480         }
481     }
482 
483     @Override
getRealtimeStillCaptureLatency()484     public StillCaptureLatency getRealtimeStillCaptureLatency() throws CameraAccessException {
485         synchronized (mInterfaceLock) {
486             if (!mInitialized) {
487                 throw new IllegalStateException("Uninitialized component");
488             }
489 
490             try {
491                 LatencyPair latency = mSessionProcessor.getRealtimeCaptureLatency();
492                 if (latency != null) {
493                     return new StillCaptureLatency(latency.first, latency.second);
494                 }
495 
496                 return null;
497             } catch (RemoteException e) {
498                 Log.e(TAG, "Failed to query realtime latency! Extension service does not "
499                         + "respond");
500                 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
501             }
502         }
503     }
504 
505     @Override
setRepeatingRequest(@onNull CaptureRequest request, @NonNull Executor executor, @NonNull ExtensionCaptureCallback listener)506     public int setRepeatingRequest(@NonNull CaptureRequest request, @NonNull Executor executor,
507             @NonNull ExtensionCaptureCallback listener) throws CameraAccessException {
508         int seqId = -1;
509         synchronized (mInterfaceLock) {
510             if (!mInitialized) {
511                 throw new IllegalStateException("Uninitialized component");
512             }
513 
514             if (mClientRepeatingRequestSurface == null) {
515                 throw new IllegalArgumentException("No registered preview surface");
516             }
517 
518             if (!request.containsTarget(mClientRepeatingRequestSurface) ||
519                     (request.getTargets().size() != 1)) {
520                 throw new IllegalArgumentException("Invalid repeating request output target!");
521             }
522 
523             try {
524                 mSessionProcessor.setParameters(request);
525 
526                 seqId = mSessionProcessor.startRepeating(new RequestCallbackHandler(request,
527                         executor, listener, mCameraDevice.getId()));
528             } catch (RemoteException e) {
529                 throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
530                         "Failed to enable repeating request, extension service failed to respond!");
531             }
532         }
533 
534         return seqId;
535     }
536 
537     @Override
capture(@onNull CaptureRequest request, @NonNull Executor executor, @NonNull ExtensionCaptureCallback listener)538     public int capture(@NonNull CaptureRequest request,
539             @NonNull Executor executor,
540             @NonNull ExtensionCaptureCallback listener) throws CameraAccessException {
541         int seqId = -1;
542         synchronized (mInterfaceLock) {
543             if (!mInitialized) {
544                 throw new IllegalStateException("Uninitialized component");
545             }
546 
547             validateCaptureRequestTargets(request);
548 
549             if ((mClientCaptureSurface != null)  && request.containsTarget(mClientCaptureSurface)) {
550                 try {
551                     boolean isPostviewRequested = request.containsTarget(mClientPostviewSurface);
552                     mSessionProcessor.setParameters(request);
553 
554                     seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
555                             executor, listener, mCameraDevice.getId()), isPostviewRequested);
556                 } catch (RemoteException e) {
557                     throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
558                             " to submit capture request, extension service failed to respond!");
559                 }
560             } else if ((mClientRepeatingRequestSurface != null) &&
561                     request.containsTarget(mClientRepeatingRequestSurface)) {
562                 try {
563                     seqId = mSessionProcessor.startTrigger(request, new RequestCallbackHandler(
564                             request, executor, listener, mCameraDevice.getId()));
565                 } catch (RemoteException e) {
566                     throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Failed " +
567                             " to submit trigger request, extension service failed to respond!");
568                 }
569             } else {
570                 throw new IllegalArgumentException("Invalid single capture output target!");
571             }
572         }
573 
574         return seqId;
575     }
576 
validateCaptureRequestTargets(@onNull CaptureRequest request)577     private void validateCaptureRequestTargets(@NonNull CaptureRequest request) {
578         if (request.getTargets().size() == 1) {
579             boolean containsCaptureTarget =
580                     mClientCaptureSurface != null && request.containsTarget(mClientCaptureSurface);
581             boolean containsRepeatingTarget =
582                     mClientRepeatingRequestSurface != null &&
583                     request.containsTarget(mClientRepeatingRequestSurface);
584 
585             if (!containsCaptureTarget && !containsRepeatingTarget) {
586                 throw new IllegalArgumentException("Target output combination requested is " +
587                         "not supported!");
588             }
589         }
590 
591         if ((request.getTargets().size() == 2) &&
592                 (!request.getTargets().containsAll(Arrays.asList(mClientCaptureSurface,
593                 mClientPostviewSurface)))) {
594             throw new IllegalArgumentException("Target output combination requested is " +
595                     "not supported!");
596         }
597 
598         if (request.getTargets().size() > 2) {
599             throw new IllegalArgumentException("Target output combination requested is " +
600                     "not supported!");
601         }
602     }
603 
604     @Override
stopRepeating()605     public void stopRepeating() throws CameraAccessException {
606         synchronized (mInterfaceLock) {
607             if (!mInitialized) {
608                 throw new IllegalStateException("Uninitialized component");
609             }
610 
611             mCaptureSession.stopRepeating();
612 
613             try {
614                 mSessionProcessor.stopRepeating();
615             } catch (RemoteException e) {
616                throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
617                        "Failed to notify about the end of repeating request, extension service"
618                                + " failed to respond!");
619             }
620         }
621     }
622 
623     @Override
close()624     public void close() throws CameraAccessException {
625         synchronized (mInterfaceLock) {
626             if (mInitialized) {
627                 try {
628                     try {
629                         mCaptureSession.stopRepeating();
630                     } catch (IllegalStateException e) {
631                         // OK: already be closed, nothing else to do
632                     }
633                     mSessionProcessor.stopRepeating();
634                     mSessionProcessor.onCaptureSessionEnd();
635                     mSessionClosed = true;
636                 } catch (RemoteException e) {
637                     Log.e(TAG, "Failed to stop the repeating request or end the session,"
638                             + " , extension service does not respond!") ;
639                 }
640                 // Commit stats before closing the capture session
641                 mStatsAggregator.commit(/*isFinal*/true);
642                 mCaptureSession.close();
643             }
644         }
645     }
646 
647     /**
648      * Called by {@link CameraDeviceImpl} right before the capture session is closed, and before it
649      * calls {@link #release}
650      */
commitStats()651     public void commitStats() {
652         synchronized (mInterfaceLock) {
653             if (mInitialized) {
654                 // Only commit stats if a capture session was initialized
655                 mStatsAggregator.commit(/*isFinal*/true);
656             }
657         }
658     }
659 
release(boolean skipCloseNotification)660     public void release(boolean skipCloseNotification) {
661         boolean notifyClose = false;
662 
663         synchronized (mInterfaceLock) {
664             mHandlerThread.quitSafely();
665 
666             if (mSessionProcessor != null) {
667                 try {
668                     if (!mSessionClosed) {
669                         mSessionProcessor.onCaptureSessionEnd();
670                     }
671                     mSessionProcessor.deInitSession(mToken);
672                 } catch (RemoteException e) {
673                     Log.e(TAG, "Failed to de-initialize session processor, extension service"
674                             + " does not respond!") ;
675                 }
676                 mSessionProcessor = null;
677             }
678 
679 
680             if (mToken != null) {
681                 if (mInitialized || (mCaptureSession != null)) {
682                     notifyClose = true;
683                     CameraExtensionCharacteristics.releaseSession(mExtensionType);
684                 }
685                 CameraExtensionCharacteristics.unregisterClient(mContext, mToken, mExtensionType);
686             }
687             mInitialized = false;
688             mToken = null;
689 
690             for (ImageReader reader : mReaderMap.values()) {
691                 reader.close();
692             }
693             mReaderMap.clear();
694 
695             mClientRepeatingRequestSurface = null;
696             mClientCaptureSurface = null;
697             mCaptureSession = null;
698             mRequestProcessor = null;
699             mCameraDevice = null;
700             mAdvancedExtender = null;
701         }
702 
703         if (notifyClose && !skipCloseNotification) {
704             final long ident = Binder.clearCallingIdentity();
705             try {
706                 mExecutor.execute(() -> mCallbacks.onClosed(
707                         CameraAdvancedExtensionSessionImpl.this));
708             } finally {
709                 Binder.restoreCallingIdentity(ident);
710             }
711         }
712     }
713 
notifyConfigurationFailure()714     private void notifyConfigurationFailure() {
715         synchronized (mInterfaceLock) {
716             if (mInitialized) {
717                 return;
718             }
719         }
720 
721         release(true /*skipCloseNotification*/);
722 
723         final long ident = Binder.clearCallingIdentity();
724         try {
725             mExecutor.execute(
726                     () -> mCallbacks.onConfigureFailed(
727                             CameraAdvancedExtensionSessionImpl.this));
728         } finally {
729             Binder.restoreCallingIdentity(ident);
730         }
731     }
732 
733     private class SessionStateHandler extends
734             android.hardware.camera2.CameraCaptureSession.StateCallback {
735         @Override
onClosed(@onNull CameraCaptureSession session)736         public void onClosed(@NonNull CameraCaptureSession session) {
737             release(false /*skipCloseNotification*/);
738         }
739 
740         @Override
onConfigureFailed(@onNull CameraCaptureSession session)741         public void onConfigureFailed(@NonNull CameraCaptureSession session) {
742             notifyConfigurationFailure();
743         }
744 
745         @Override
onConfigured(@onNull CameraCaptureSession session)746         public void onConfigured(@NonNull CameraCaptureSession session) {
747             synchronized (mInterfaceLock) {
748                 mCaptureSession = session;
749                 // Commit basic stats as soon as the capture session is created
750                 mStatsAggregator.commit(/*isFinal*/false);
751             }
752 
753             try {
754                 CameraExtensionCharacteristics.initializeSession(
755                         mInitializeHandler, mExtensionType);
756             } catch (RemoteException e) {
757                 Log.e(TAG, "Failed to initialize session! Extension service does"
758                         + " not respond!");
759                 notifyConfigurationFailure();
760             }
761         }
762     }
763 
764     private class InitializeSessionHandler extends IInitializeSessionCallback.Stub {
765         @Override
onSuccess()766         public void onSuccess() {
767             mHandler.post(new Runnable() {
768                 @Override
769                 public void run() {
770                     boolean status = true;
771                     synchronized (mInterfaceLock) {
772                         try {
773                             if (mSessionProcessor != null) {
774                                 mInitialized = true;
775                                 mSessionProcessor.onCaptureSessionStart(mRequestProcessor,
776                                         mStatsAggregator.getStatsKey());
777                             } else {
778                                 Log.v(TAG, "Failed to start capture session, session " +
779                                                 " released before extension start!");
780                                 status = false;
781                             }
782                         } catch (RemoteException e) {
783                             Log.e(TAG, "Failed to start capture session,"
784                                     + " extension service does not respond!");
785                             status = false;
786                             mInitialized = false;
787                         }
788                     }
789 
790                     if (status) {
791                         final long ident = Binder.clearCallingIdentity();
792                         try {
793                             mExecutor.execute(() -> mCallbacks.onConfigured(
794                                     CameraAdvancedExtensionSessionImpl.this));
795                         } finally {
796                             Binder.restoreCallingIdentity(ident);
797                         }
798                     } else {
799                         onFailure();
800                     }
801                 }
802             });
803         }
804 
805         @Override
onFailure()806         public void onFailure() {
807             mHandler.post(new Runnable() {
808                 @Override
809                 public void run() {
810                     mCaptureSession.close();
811 
812                     Log.e(TAG, "Failed to initialize proxy service session!"
813                             + " This can happen when trying to configure multiple "
814                             + "concurrent extension sessions!");
815                     notifyConfigurationFailure();
816                 }
817             });
818         }
819     }
820 
821     private final class RequestCallbackHandler extends ICaptureCallback.Stub {
822         private final CaptureRequest mClientRequest;
823         private final Executor mClientExecutor;
824         private final ExtensionCaptureCallback mClientCallbacks;
825         private final String mCameraId;
826 
RequestCallbackHandler(@onNull CaptureRequest clientRequest, @NonNull Executor clientExecutor, @NonNull ExtensionCaptureCallback clientCallbacks, @NonNull String cameraId)827         private RequestCallbackHandler(@NonNull CaptureRequest clientRequest,
828                 @NonNull Executor clientExecutor,
829                 @NonNull ExtensionCaptureCallback clientCallbacks,
830                 @NonNull String cameraId) {
831             mClientRequest = clientRequest;
832             mClientExecutor = clientExecutor;
833             mClientCallbacks = clientCallbacks;
834             mCameraId = cameraId;
835         }
836 
837         @Override
onCaptureStarted(int captureSequenceId, long timestamp)838         public void onCaptureStarted(int captureSequenceId, long timestamp) {
839             final long ident = Binder.clearCallingIdentity();
840             try {
841                 mClientExecutor.execute(
842                         () -> mClientCallbacks.onCaptureStarted(
843                                 CameraAdvancedExtensionSessionImpl.this, mClientRequest,
844                                 timestamp));
845             } finally {
846                 Binder.restoreCallingIdentity(ident);
847             }
848         }
849 
850         @Override
onCaptureProcessStarted(int captureSequenceId)851         public void onCaptureProcessStarted(int captureSequenceId) {
852             final long ident = Binder.clearCallingIdentity();
853             try {
854                 mClientExecutor.execute(
855                         () -> mClientCallbacks.onCaptureProcessStarted(
856                                 CameraAdvancedExtensionSessionImpl.this, mClientRequest));
857             } finally {
858                 Binder.restoreCallingIdentity(ident);
859             }
860         }
861 
862         @Override
onCaptureFailed(int captureSequenceId)863         public void onCaptureFailed(int captureSequenceId) {
864             final long ident = Binder.clearCallingIdentity();
865             try {
866                 mClientExecutor.execute(
867                         () -> mClientCallbacks.onCaptureFailed(
868                                 CameraAdvancedExtensionSessionImpl.this, mClientRequest));
869             } finally {
870                 Binder.restoreCallingIdentity(ident);
871             }
872         }
873 
874         @Override
onCaptureProcessFailed(int captureSequenceId, int captureFailureReason)875         public void onCaptureProcessFailed(int captureSequenceId, int captureFailureReason) {
876             final long ident = Binder.clearCallingIdentity();
877             try {
878                 mClientExecutor.execute(
879                         () -> mClientCallbacks.onCaptureFailed(
880                                  CameraAdvancedExtensionSessionImpl.this, mClientRequest,
881                                 captureFailureReason
882                         ));
883             } finally {
884                 Binder.restoreCallingIdentity(ident);
885             }
886         }
887 
888         @Override
onCaptureSequenceCompleted(int captureSequenceId)889         public void onCaptureSequenceCompleted(int captureSequenceId) {
890             final long ident = Binder.clearCallingIdentity();
891             try {
892                 mClientExecutor.execute(
893                         () -> mClientCallbacks.onCaptureSequenceCompleted(
894                                 CameraAdvancedExtensionSessionImpl.this, captureSequenceId));
895             } finally {
896                 Binder.restoreCallingIdentity(ident);
897             }
898         }
899 
900         @Override
onCaptureSequenceAborted(int captureSequenceId)901         public void onCaptureSequenceAborted(int captureSequenceId) {
902             final long ident = Binder.clearCallingIdentity();
903             try {
904                 mClientExecutor.execute(
905                         () -> mClientCallbacks.onCaptureSequenceAborted(
906                                 CameraAdvancedExtensionSessionImpl.this, captureSequenceId));
907             } finally {
908                 Binder.restoreCallingIdentity(ident);
909             }
910         }
911 
912         @Override
onCaptureCompleted(long timestamp, int requestId, CameraMetadataNative result)913         public void onCaptureCompleted(long timestamp, int requestId, CameraMetadataNative result) {
914             if (result == null) {
915                 Log.e(TAG,"Invalid capture result!");
916                 return;
917             }
918 
919             result.set(CaptureResult.SENSOR_TIMESTAMP, timestamp);
920             TotalCaptureResult totalResult = new TotalCaptureResult(mCameraId, result,
921                     mClientRequest, requestId, timestamp, new ArrayList<>(), mSessionId,
922                     new PhysicalCaptureResultInfo[0]);
923             final long ident = Binder.clearCallingIdentity();
924             try {
925                 mExecutor.execute(
926                         () -> mClientCallbacks.onCaptureResultAvailable(
927                                 CameraAdvancedExtensionSessionImpl.this, mClientRequest,
928                                 totalResult));
929             } finally {
930                 Binder.restoreCallingIdentity(ident);
931             }
932         }
933 
934         @Override
onCaptureProcessProgressed(int progress)935         public void onCaptureProcessProgressed(int progress) {
936             final long ident = Binder.clearCallingIdentity();
937             try {
938                 mExecutor.execute(
939                         () -> mClientCallbacks.onCaptureProcessProgressed(
940                                 CameraAdvancedExtensionSessionImpl.this, mClientRequest,
941                                 progress));
942             } finally {
943                 Binder.restoreCallingIdentity(ident);
944             }
945         }
946     }
947 
948     private final class CaptureCallbackHandler extends CameraCaptureSession.CaptureCallback {
949         private final IRequestCallback mCallback;
950 
CaptureCallbackHandler(IRequestCallback callback)951         public CaptureCallbackHandler(IRequestCallback callback) {
952             mCallback = callback;
953         }
954 
955         @Override
onCaptureBufferLost(CameraCaptureSession session, CaptureRequest request, Surface target, long frameNumber)956         public void onCaptureBufferLost(CameraCaptureSession session, CaptureRequest request,
957                 Surface target, long frameNumber) {
958             try {
959                 if (request.getTag() instanceof Integer) {
960                     Integer requestId = (Integer) request.getTag();
961                     mCallback.onCaptureBufferLost(requestId, frameNumber,
962                             mCameraConfigMap.get(target).outputId.id);
963                 } else {
964                     Log.e(TAG, "Invalid capture request tag!");
965                 }
966             } catch (RemoteException e) {
967                 Log.e(TAG, "Failed to notify lost capture buffer, extension service doesn't"
968                         + " respond!");
969             }
970         }
971 
972         @Override
onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result)973         public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
974                 TotalCaptureResult result) {
975             try {
976                 if (request.getTag() instanceof Integer) {
977                     Integer requestId = (Integer) request.getTag();
978                     mCallback.onCaptureCompleted(requestId, initializeParcelable(result));
979                 } else {
980                     Log.e(TAG, "Invalid capture request tag!");
981                 }
982             } catch (RemoteException e) {
983                 Log.e(TAG, "Failed to notify capture result, extension service doesn't"
984                         + " respond!");
985             }
986         }
987 
988         @Override
onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure)989         public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
990                 CaptureFailure failure) {
991             try {
992                 if (request.getTag() instanceof Integer) {
993                     Integer requestId = (Integer) request.getTag();
994                     android.hardware.camera2.extension.CaptureFailure captureFailure =
995                             new android.hardware.camera2.extension.CaptureFailure();
996                     captureFailure.request = request;
997                     captureFailure.reason = failure.getReason();
998                     captureFailure.errorPhysicalCameraId = failure.getPhysicalCameraId();
999                     captureFailure.frameNumber = failure.getFrameNumber();
1000                     captureFailure.sequenceId = failure.getSequenceId();
1001                     captureFailure.dropped = !failure.wasImageCaptured();
1002                     mCallback.onCaptureFailed(requestId, captureFailure);
1003                 } else {
1004                     Log.e(TAG, "Invalid capture request tag!");
1005                 }
1006             } catch (RemoteException e) {
1007                 Log.e(TAG, "Failed to notify capture failure, extension service doesn't"
1008                         + " respond!");
1009             }
1010         }
1011 
1012         @Override
onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult)1013         public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
1014                 CaptureResult partialResult) {
1015             try {
1016                 if (request.getTag() instanceof Integer) {
1017                     Integer requestId = (Integer) request.getTag();
1018                     mCallback.onCaptureProgressed(requestId, initializeParcelable(partialResult));
1019                 } else {
1020                     Log.e(TAG, "Invalid capture request tag!");
1021                 }
1022             } catch (RemoteException e) {
1023                 Log.e(TAG, "Failed to notify capture partial result, extension service doesn't"
1024                         + " respond!");
1025             }
1026         }
1027 
1028         @Override
onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId)1029         public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) {
1030             try {
1031                 mCallback.onCaptureSequenceAborted(sequenceId);
1032             } catch (RemoteException e) {
1033                 Log.e(TAG, "Failed to notify aborted sequence, extension service doesn't"
1034                         + " respond!");
1035             }
1036         }
1037 
1038         @Override
onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber)1039         public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId,
1040                 long frameNumber) {
1041             try {
1042                 mCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
1043             } catch (RemoteException e) {
1044                 Log.e(TAG, "Failed to notify sequence complete, extension service doesn't"
1045                         + " respond!");
1046             }
1047         }
1048 
1049         @Override
onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber)1050         public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
1051                 long timestamp, long frameNumber) {
1052             try {
1053                 if (request.getTag() instanceof Integer) {
1054                     Integer requestId = (Integer) request.getTag();
1055                     mCallback.onCaptureStarted(requestId, frameNumber, timestamp);
1056                 } else {
1057                     Log.e(TAG, "Invalid capture request tag!");
1058                 }
1059             } catch (RemoteException e) {
1060                 Log.e(TAG, "Failed to notify capture started, extension service doesn't"
1061                         + " respond!");
1062             }
1063         }
1064     }
1065 
1066     private static final class ImageReaderHandler implements ImageReader.OnImageAvailableListener {
1067         private final OutputConfigId mOutputConfigId;
1068         private final IImageProcessorImpl mIImageProcessor;
1069         private final String mPhysicalCameraId;
1070 
ImageReaderHandler(int outputConfigId, IImageProcessorImpl iImageProcessor, String physicalCameraId)1071         private ImageReaderHandler(int outputConfigId,
1072                 IImageProcessorImpl iImageProcessor, String physicalCameraId) {
1073             mOutputConfigId = new OutputConfigId();
1074             mOutputConfigId.id = outputConfigId;
1075             mIImageProcessor = iImageProcessor;
1076             mPhysicalCameraId = physicalCameraId;
1077         }
1078 
1079         @Override
onImageAvailable(ImageReader reader)1080         public void onImageAvailable(ImageReader reader) {
1081             if (mIImageProcessor == null) {
1082                 return;
1083             }
1084 
1085             Image img;
1086             try {
1087                 img = reader.acquireNextImage();
1088             } catch (IllegalStateException e) {
1089                 Log.e(TAG, "Failed to acquire image, too many images pending!");
1090                 return;
1091             }
1092             if (img == null) {
1093                 Log.e(TAG, "Invalid image!");
1094                 return;
1095             }
1096 
1097             try {
1098                 reader.detachImage(img);
1099             } catch(Exception e) {
1100                 Log.e(TAG, "Failed to detach image");
1101                 img.close();
1102                 return;
1103             }
1104 
1105             ParcelImage parcelImage = new ParcelImage();
1106             parcelImage.buffer = img.getHardwareBuffer();
1107             try {
1108                 SyncFence fd = img.getFence();
1109                 if (fd.isValid()) {
1110                     parcelImage.fence = fd.getFdDup();
1111                 }
1112             } catch (IOException e) {
1113                 Log.e(TAG, "Failed to parcel buffer fence!");
1114             }
1115             parcelImage.width = img.getWidth();
1116             parcelImage.height = img.getHeight();
1117             parcelImage.format = img.getFormat();
1118             parcelImage.timestamp = img.getTimestamp();
1119             parcelImage.transform = img.getTransform();
1120             parcelImage.scalingMode = img.getScalingMode();
1121             parcelImage.planeCount = img.getPlaneCount();
1122             parcelImage.crop = img.getCropRect();
1123 
1124             try {
1125                 mIImageProcessor.onNextImageAvailable(mOutputConfigId, parcelImage,
1126                         mPhysicalCameraId);
1127             } catch (RemoteException e) {
1128                 Log.e(TAG, "Failed to propagate image buffer on output surface id: " +
1129                         mOutputConfigId + " extension service does not respond!");
1130             } finally {
1131                 parcelImage.buffer.close();
1132                 img.close();
1133             }
1134         }
1135     }
1136 
1137     private final class RequestProcessor extends IRequestProcessorImpl.Stub {
1138         @Override
setImageProcessor(OutputConfigId outputConfigId, IImageProcessorImpl imageProcessor)1139         public void setImageProcessor(OutputConfigId outputConfigId,
1140                 IImageProcessorImpl imageProcessor) {
1141             synchronized (mInterfaceLock) {
1142                 if (mReaderMap.containsKey(outputConfigId.id)) {
1143                     ImageReader reader = mReaderMap.get(outputConfigId.id);
1144                     String physicalCameraId = null;
1145                     if (mCameraConfigMap.containsKey(reader.getSurface())) {
1146                         physicalCameraId =
1147                                 mCameraConfigMap.get(reader.getSurface()).physicalCameraId;
1148                         reader.setOnImageAvailableListener(new ImageReaderHandler(outputConfigId.id,
1149                                     imageProcessor, physicalCameraId), mHandler);
1150                     } else {
1151                         Log.e(TAG, "Camera output configuration for ImageReader with " +
1152                                         " config Id " + outputConfigId.id + " not found!");
1153                     }
1154                 } else {
1155                     Log.e(TAG, "ImageReader with output config id: " + outputConfigId.id +
1156                             " not found!");
1157                 }
1158             }
1159         }
1160 
1161         @Override
submit(Request request, IRequestCallback callback)1162         public int submit(Request request, IRequestCallback callback) {
1163             ArrayList<Request> captureList = new ArrayList<>();
1164             captureList.add(request);
1165             return submitBurst(captureList, callback);
1166         }
1167 
1168         @Override
submitBurst(List<Request> requests, IRequestCallback callback)1169         public int submitBurst(List<Request> requests, IRequestCallback callback) {
1170             int seqId = -1;
1171             try {
1172                 synchronized (mInterfaceLock) {
1173                     if (!mInitialized) {
1174                         return seqId;
1175                     }
1176 
1177                     CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
1178                     ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
1179                     for (Request request : requests) {
1180                         captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
1181                                 mCameraConfigMap));
1182                     }
1183                     seqId = mCaptureSession.captureBurstRequests(captureRequests,
1184                             new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
1185                 }
1186             } catch (CameraAccessException e) {
1187                 Log.e(TAG, "Failed to submit capture requests!");
1188             } catch (IllegalStateException e) {
1189                 Log.e(TAG, "Capture session closed!");
1190             }
1191 
1192             return seqId;
1193         }
1194 
1195         @Override
setRepeating(Request request, IRequestCallback callback)1196         public int setRepeating(Request request, IRequestCallback callback) {
1197             int seqId = -1;
1198             try {
1199                 synchronized (mInterfaceLock) {
1200                     if (!mInitialized) {
1201                         return seqId;
1202                     }
1203 
1204                     CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
1205                             request, mCameraConfigMap);
1206                     CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
1207                     seqId = mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
1208                             new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
1209                 }
1210             } catch (CameraAccessException e) {
1211                 Log.e(TAG, "Failed to enable repeating request!");
1212             } catch (IllegalStateException e) {
1213                 Log.e(TAG, "Capture session closed!");
1214             }
1215 
1216             return seqId;
1217         }
1218 
1219         @Override
abortCaptures()1220         public void abortCaptures() {
1221             try {
1222                 synchronized (mInterfaceLock) {
1223                     if (!mInitialized) {
1224                         return;
1225                     }
1226 
1227                     mCaptureSession.abortCaptures();
1228                 }
1229             } catch (CameraAccessException e) {
1230                 Log.e(TAG, "Failed during capture abort!");
1231             } catch (IllegalStateException e) {
1232                 Log.e(TAG, "Capture session closed!");
1233             }
1234         }
1235 
1236         @Override
stopRepeating()1237         public void stopRepeating() {
1238             try {
1239                 synchronized (mInterfaceLock) {
1240                     if (!mInitialized) {
1241                         return;
1242                     }
1243 
1244                     mCaptureSession.stopRepeating();
1245                 }
1246             } catch (CameraAccessException e) {
1247                 Log.e(TAG, "Failed during repeating capture stop!");
1248             } catch (IllegalStateException e) {
1249                 Log.e(TAG, "Capture session closed!");
1250             }
1251         }
1252     }
1253 
initializeCaptureRequest(CameraDevice cameraDevice, Request request, HashMap<Surface, CameraOutputConfig> surfaceIdMap)1254     private static CaptureRequest initializeCaptureRequest(CameraDevice cameraDevice,
1255             Request request, HashMap<Surface, CameraOutputConfig> surfaceIdMap)
1256             throws CameraAccessException {
1257         CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(request.templateId);
1258         for (OutputConfigId configId : request.targetOutputConfigIds) {
1259             boolean found = false;
1260             for (Map.Entry<Surface, CameraOutputConfig> entry : surfaceIdMap.entrySet()) {
1261                 if (entry.getValue().outputId.id == configId.id) {
1262                     builder.addTarget(entry.getKey());
1263                     found = true;
1264                     break;
1265                 }
1266             }
1267 
1268             if (!found) {
1269                 Log.e(TAG, "Surface with output id: " + configId.id +
1270                         " not found among registered camera outputs!");
1271             }
1272         }
1273 
1274         builder.setTag(request.requestId);
1275         CaptureRequest ret = builder.build();
1276         CameraMetadataNative.update(ret.getNativeMetadata(), request.parameters);
1277         return ret;
1278     }
1279 
initializeSurface(CameraOutputConfig output)1280     private Surface initializeSurface(CameraOutputConfig output) {
1281         switch(output.type) {
1282             case CameraOutputConfig.TYPE_SURFACE:
1283                 if (output.surface == null) {
1284                     Log.w(TAG, "Unsupported client output id: " + output.outputId.id +
1285                             ", skipping!");
1286                     return null;
1287                 }
1288                 return output.surface;
1289             case CameraOutputConfig.TYPE_IMAGEREADER:
1290                 if ((output.imageFormat == ImageFormat.UNKNOWN) || (output.size.width <= 0) ||
1291                         (output.size.height <= 0)) {
1292                     Log.w(TAG, "Unsupported client output id: " + output.outputId.id +
1293                             ", skipping!");
1294                     return null;
1295                 }
1296                 ImageReader reader = ImageReader.newInstance(output.size.width,
1297                         output.size.height, output.imageFormat, output.capacity,
1298                         output.usage);
1299                 mReaderMap.put(output.outputId.id, reader);
1300                 return reader.getSurface();
1301             case CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER:
1302                 // Support for multi-resolution outputs to be added in future releases
1303             default:
1304                 throw new IllegalArgumentException("Unsupported output config type: " +
1305                         output.type);
1306         }
1307     }
1308 }
1309