summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 01:06:25 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 01:06:25 +0000
commit40fbee9a4da7f72c49385faac9364cd2ad45a9a6 (patch)
treeda0417ebd1cd17c2ec214fb4e75bfb8c80d5b089
parentc9231e3a3d5364344c2f711fedb19226518e954b (diff)
parentcb5a327830ee0325116392b3dc3d796afa1c4215 (diff)
downloadex-android14-mainline-resolv-release.tar.gz
Snap for 10447354 from cb5a327830ee0325116392b3dc3d796afa1c4215 to mainline-resolv-releaseaml_res_341510000aml_res_341410010aml_res_341311030aml_res_341110000aml_res_340912000android14-mainline-resolv-release
Change-Id: Ifc0569919577dd5c261f0dbd93c60ff666840d58
-rw-r--r--camera2/extensions/advancedSample/Android.bp37
-rw-r--r--camera2/extensions/advancedSample/advancedSample_camera_extensions.xml5
-rw-r--r--camera2/extensions/advancedSample/jarjar-rules.txt1
-rwxr-xr-xcamera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java140
-rwxr-xr-xcamera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java101
-rwxr-xr-xcamera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java140
-rwxr-xr-xcamera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java101
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java140
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java99
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java116
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java45
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java100
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java74
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java140
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java101
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java217
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/InitializerImpl.java129
-rwxr-xr-xcamera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java140
-rwxr-xr-xcamera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java101
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java111
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java64
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java60
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java55
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java36
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java219
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java91
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java699
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java91
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java115
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java51
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java227
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java57
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java139
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CameraCharacteristicAvailability.java136
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CaptureResultImageMatcher.java204
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java321
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java53
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java41
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java50
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/JpegEncoder.java136
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java32
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java281
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java35
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java42
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java110
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java123
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java390
-rw-r--r--camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java31
-rw-r--r--camera2/extensions/jni/Android.bp44
-rw-r--r--camera2/extensions/jni/JpegEncoder.cpp647
-rwxr-xr-xcamera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java51
-rwxr-xr-xcamera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java6
-rwxr-xr-xcamera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java51
-rwxr-xr-xcamera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java6
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java141
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java6
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java86
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java17
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java2
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java70
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java52
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java56
-rwxr-xr-xcamera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java51
-rwxr-xr-xcamera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java6
-rw-r--r--camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java18
-rw-r--r--camera2/extensions/service_based_sample/README.txt26
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/Android.bp31
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml25
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml6
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java268
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java95
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java83
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ImageCaptureExtenderImplStub.java228
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/PreviewExtenderImplStub.java230
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java71
-rw-r--r--camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java383
-rw-r--r--camera2/extensions/service_based_sample/oem_library/Android.bp45
-rw-r--r--camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml21
-rw-r--r--camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml5
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java44
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java42
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java44
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java42
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java44
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java41
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java66
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java41
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java91
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java84
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java44
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java42
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java171
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java115
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java44
-rwxr-xr-xcamera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java42
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java117
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java64
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java45
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java57
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java39
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java188
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java51
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java243
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java46
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java123
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java53
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java41
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java50
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java32
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java42
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java123
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java281
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java31
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl21
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java106
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl38
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureBundle.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java88
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java89
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureStageImplWrapper.aidl24
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl36
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl29
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureProcessorImpl.aidl30
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl34
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageCaptureExtenderImpl.aidl42
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl24
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl22
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl22
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewExtenderImpl.aidl41
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewImageProcessorImpl.aidl33
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IProcessResultImpl.aidl23
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl33
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl30
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestUpdateProcessorImpl.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl39
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java281
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl23
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl27
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl23
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl25
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl19
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java121
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/CaptureStageImplAdapter.java48
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java246
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardImageCaptureExtender.java365
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardPreviewExtender.java322
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java345
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java59
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java229
-rw-r--r--camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java213
-rwxr-xr-xcamera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java24
-rwxr-xr-xcamera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java5
-rwxr-xr-xcamera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java25
-rwxr-xr-xcamera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java5
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java24
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java5
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java50
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java25
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java5
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java55
-rwxr-xr-xcamera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java25
-rwxr-xr-xcamera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java5
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java17
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java31
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java12
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java3
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java16
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java35
-rw-r--r--camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java115
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java13
-rw-r--r--camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java16
-rw-r--r--common/BUILD2
-rw-r--r--framesequence/Android.bp3
-rw-r--r--framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java10
190 files changed, 15415 insertions, 79 deletions
diff --git a/camera2/extensions/advancedSample/Android.bp b/camera2/extensions/advancedSample/Android.bp
new file mode 100644
index 00000000..9f0df8e4
--- /dev/null
+++ b/camera2/extensions/advancedSample/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "androidx.camera.extensions.impl.advanced",
+ installable: true,
+ static_libs: [
+ "androidx.annotation_annotation"
+ ],
+ exclude_kotlinc_generated_files: true,
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ vendor: true,
+ jarjar_rules: "jarjar-rules.txt",
+}
+
+prebuilt_etc {
+ name: "advancedSample_camera_extensions.xml",
+ src: "advancedSample_camera_extensions.xml",
+ sub_dir: "permissions",
+ vendor: true,
+}
diff --git a/camera2/extensions/advancedSample/advancedSample_camera_extensions.xml b/camera2/extensions/advancedSample/advancedSample_camera_extensions.xml
new file mode 100644
index 00000000..4fcbb486
--- /dev/null
+++ b/camera2/extensions/advancedSample/advancedSample_camera_extensions.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <library name="androidx.camera.extensions.impl"
+ file="/vendor/framework/androidx.camera.extensions.impl.advanced.jar"/>
+</permissions>
diff --git a/camera2/extensions/advancedSample/jarjar-rules.txt b/camera2/extensions/advancedSample/jarjar-rules.txt
new file mode 100644
index 00000000..7442cef5
--- /dev/null
+++ b/camera2/extensions/advancedSample/jarjar-rules.txt
@@ -0,0 +1 @@
+rule kotlin.** androidx.camera.extensions.impl.advanced.@0 \ No newline at end of file
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..bd605708
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for auto image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public AutoImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
new file mode 100755
index 00000000..0c4577a4
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for auto preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl {
+ public AutoPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..50c80407
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for beauty image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public BeautyImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
new file mode 100755
index 00000000..1f501745
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for beauty preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl {
+ public BeautyPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..ee777cf9
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for bokeh image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public BokehImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
new file mode 100644
index 00000000..1dc5ed79
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for bokeh preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl {
+ public BokehPreviewExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
new file mode 100644
index 00000000..f4719b8b
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * The interface for processing a set of {@link Image}s that have captured.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface CaptureProcessorImpl extends ProcessorImpl {
+ /**
+ * Process a set images captured that were requested.
+ *
+ * <p> The result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata to
+ * process. The {@link Image} that are contained within the map will become
+ * invalid after this method completes, so no references to them should be kept.
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
+
+ /**
+ * Informs the CaptureProcessorImpl where it should write the postview output to.
+ * This will only be invoked once if a valid postview surface was set.
+ *
+ * @param surface A valid {@link ImageFormat#YUV_420_888} {@link Surface}
+ * that the CaptureProcessorImpl should write data into.
+ * @since 1.4
+ */
+ void onPostviewOutputSurface(Surface surface);
+
+ /**
+ * Invoked when the Camera Framework changes the configured output resolution for
+ * still capture and postview.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input for still capture and postview to be at the specified resolutions.
+ *
+ * @param size for the surface for still capture.
+ * @param postviewSize for the surface for postview.
+ * @since 1.4
+ */
+ void onResolutionUpdate(Size size, Size postviewSize);
+
+ /**
+ * Process a set images captured that were requested.
+ *
+ * <p> The result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata
+ * to process. The {@link Image} that are contained within the map will
+ * become invalid after this method completes, so no references to them
+ * should be kept.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback will
+ * run on any arbitrary executor.
+ * @since 1.3
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor);
+
+ /**
+ * Process a set images captured that were requested for both postview and
+ * still capture.
+ *
+ * <p> This processing method will be called if a postview was requested, therefore the
+ * processed postview should be written to the
+ * {@link Surface} received by {@link #onPostviewOutputSurface(Surface, int)}.
+ * The final result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}. Since postview should be available
+ * before the capture, it should be processed and written to the surface before
+ * the final capture is processed.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and
+ * metadata to process. The {@link Image} that are contained within
+ * the map will become invalid after this method completes, so no
+ * references to them should be kept.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback
+ * will run on any arbitrary executor.
+ * @throws RuntimeException if postview feature is not supported
+ * @since 1.4
+ */
+ void processWithPostview(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor);
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
new file mode 100644
index 00000000..268a49da
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.hardware.camera2.CaptureRequest;
+import android.util.Pair;
+
+import java.util.List;
+
+/**
+ * The set of parameters that defines a single capture that will be sent to the camera.
+ *
+ * @since 1.0
+ * @hide
+ */
+public interface CaptureStageImpl {
+ /** Returns the identifier for the {@link CaptureStageImpl}. */
+ /**
+ * @hide
+ */
+ int getId();
+
+ /**
+ * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be
+ * set for a single {@link CaptureRequest}.
+ */
+ /**
+ * @hide
+ */
+ List<Pair<CaptureRequest.Key, Object>> getParameters();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
new file mode 100644
index 00000000..3a88ab2e
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
+
+/**
+ * Provides interfaces that the OEM needs to implement to handle the state change.
+ *
+ * @since 1.0
+ */
+public interface ExtenderStateListener {
+
+ /**
+ * Notify to initialize the extension. This will be called after bindToLifeCycle. This is
+ * where the use case is started and would be able to allocate resources here. After onInit() is
+ * called, the camera ID, cameraCharacteristics and context will not change until onDeInit()
+ * has been called.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @param context The {@link Context} used for CameraX.
+ */
+ void onInit(String cameraId, CameraCharacteristics cameraCharacteristics, Context context);
+
+ /**
+ * Notify to de-initialize the extension. This callback will be invoked after unbind.
+ * After onDeInit() was called, it is expected that the camera ID, cameraCharacteristics will
+ * no longer hold, this should be where to clear all resources allocated for this use case.
+ */
+ void onDeInit();
+
+ /**
+ * This will be invoked before creating a
+ * {@link android.hardware.camera2.CameraCaptureSession}. The {@link CaptureRequest}
+ * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as
+ * part of the capture session initialization via
+ * {@link SessionConfiguration#setSessionParameters(CaptureRequest)} which only supported from
+ * API level 28. The valid parameter is a subset of the available capture request parameters.
+ *
+ * @return The request information to set the session wide camera parameters.
+ */
+ CaptureStageImpl onPresetSession();
+
+ /**
+ * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession}
+ * has been created. The {@link CaptureRequest} parameters returned via
+ * {@link CaptureStageImpl} will be used to generate a single request to the current
+ * configured {@link CameraDevice}. The generated request will be submitted to camera before
+ * processing other single requests.
+ *
+ * @return The request information to create a single capture request to camera device.
+ */
+ CaptureStageImpl onEnableSession();
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * closed. The {@link CaptureRequest} parameters returned via {@link CaptureStageImpl} will
+ * be used to generate a single request to the currently configured {@link CameraDevice}. The
+ * generated request will be submitted to camera before the CameraCaptureSession is closed.
+ *
+ * @return The request information to customize the session.
+ */
+ CaptureStageImpl onDisableSession();
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * initialized and must return a valid camera session type
+ * {@link android.hardware.camera2.params.SessionConfiguration#getSessionType}
+ * to be used to configure camera capture session. Both the preview and the image capture
+ * extender must return the same session type value for a specific extension type. If there
+ * is inconsistency between the session type values from preview and image extenders, then
+ * the session configuration will fail.
+ *
+ *
+ * @since 1.4
+ * @return Camera capture session type. Regular and vendor specific types are supported but
+ * not high speed values. The extension can return -1 in which case the camera capture session
+ * will be configured to use the default regular type.
+ */
+ int onSessionType();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
new file mode 100644
index 00000000..1f285720
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.util.Log;
+
+/**
+ * Implementation for extension version check.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices. 3P developers
+ * don't need to implement this, unless this is used for related testing usage.
+ *
+ * @since 1.0
+ * @hide
+ */
+public class ExtensionVersionImpl {
+ private static final String TAG = "ExtenderVersionImpl";
+ private static final String VERSION = "1.4.0";
+
+ /**
+ * @hide
+ */
+ public ExtensionVersionImpl() {
+ }
+
+ /**
+ * Provide the current CameraX extension library version to vendor library and vendor would
+ * need to return the supported version for this device. If the returned version is not
+ * supported by CameraX library, the Preview and ImageCapture would not be able to enable the
+ * specific effects provided by the vendor.
+ *
+ * <p>CameraX library provides the Semantic Versioning string in a form of
+ * MAJOR.MINOR.PATCH-description
+ * We will increment the
+ * MAJOR version when make incompatible API changes,
+ * MINOR version when add functionality in a backwards-compatible manner, and
+ * PATCH version when make backwards-compatible bug fixes. And the description can be ignored.
+ *
+ * <p>Vendor library should provide MAJOR.MINOR.PATCH to CameraX. The MAJOR and MINOR
+ * version is used to map to the version of CameraX that it supports, and CameraX extension
+ * would only available when MAJOR version is matched with CameraX current version. The PATCH
+ * version does not indicate compatibility. The patch version should be incremented whenever
+ * the vendor library makes bug fixes or updates to the algorithm.
+ *
+ * @param version the version of CameraX library formatted as MAJOR.MINOR.PATCH-description.
+ * @return the version that vendor supported in this device. The MAJOR.MINOR.PATCH format
+ * should be used.
+ */
+ /**
+ * @hide
+ */
+ public String checkApiVersion(String version) {
+ Log.d(TAG, "Extension device library version " + VERSION);
+ return VERSION;
+ }
+
+ public boolean isAdvancedExtenderImplemented() {
+ return true;
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..f3fd2f3b
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for HDR image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public HdrImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
new file mode 100644
index 00000000..af484646
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for HDR preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
+ public HdrPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..70c1804e
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions for image capture.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable(String, CameraCharacteristics)}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ */
+ void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The processing that will be done on a set of captures to create and image with the effect.
+ */
+ CaptureProcessorImpl getCaptureProcessor();
+
+ /** The set of captures that are needed to create an image with the effect. */
+ List<CaptureStageImpl> getCaptureStages();
+
+ /**
+ * Returns the maximum size of the list returned by {@link #getCaptureStages()}.
+ * @return the maximum count.
+ */
+ int getMaxCaptureStage();
+
+ /**
+ * Returns the customized supported resolutions.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the
+ * returned list is not null, it will be used to find the best resolutions combination for
+ * the bound use cases.
+ *
+ * @return the customized supported resolutions, or null to support all sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap}.
+ * @since 1.1
+ */
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+
+ /**
+ * Returns the customized supported postview resolutions for a still capture using
+ * its size.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device.
+ *
+ * @return the customized supported resolutions, or null to support all sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap}.
+ * @since 1.4
+ */
+ List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize);
+
+ /**
+ * Returns the estimated capture latency range in milliseconds for the target capture
+ * resolution.
+ *
+ * <p>This includes the time spent processing the multi-frame capture request along with any
+ * additional time for encoding of the processed buffer in the framework if necessary.</p>
+ *
+ * @param captureOutputSize size of the capture output surface. If it is null or not in the
+ * supported output sizes, maximum capture output size is used for
+ * the estimation.
+ * @return the range of estimated minimal and maximal capture latency in milliseconds, or
+ * null if no capture latency info can be provided.
+ * @since 1.2
+ */
+ Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize);
+
+ /**
+ * Return a list of orthogonal capture request keys.
+ *
+ * <p>Any keys included in the list will be configurable by clients of the extension and will
+ * affect the extension functionality.</p>
+ *
+ * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p>
+ *
+ * <p>Also note that the keys {@link CaptureRequest#JPEG_QUALITY} and
+ * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the
+ * list or not. To support common camera operations like zoom, tap-to-focus, flash and
+ * exposure compensation, we recommend supporting the following keys if possible.
+ * <pre>
+ * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO}
+ * {@link CaptureRequest#SCALER_CROP_REGION}
+ * tap-to-focus:
+ * {@link CaptureRequest#CONTROL_AF_MODE}
+ * {@link CaptureRequest#CONTROL_AF_TRIGGER}
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}
+ * {@link CaptureRequest#CONTROL_AE_REGIONS}
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS}
+ * flash:
+ * {@link CaptureRequest#CONTROL_AE_MODE}
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
+ * {@link CaptureRequest#FLASH_MODE}
+ * exposure compensation:
+ * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
+ * </pre>
+ * On basic extensions that implement 1.2 or prior version, the above keys are all supported
+ * explicitly. When migrating from 1.2 or prior to 1.3, please note that both CameraX and
+ * Camera2 will honor the returned list and support only the keys contained in it. For
+ * example, if OEM decides to return only {@link CaptureRequest#CONTROL_ZOOM_RATIO} and
+ * {@link CaptureRequest#SCALER_CROP_REGION} in the 1.3 implementation, it means only zoom is
+ * supported for the app while tap-to-focus , flash and exposure compensation are not allowed.
+ *
+ * @return List of supported orthogonal capture keys, or an empty list if no capture settings
+ * are not supported.
+ * @since 1.3
+ */
+ List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
+
+ /**
+ * Return a list of supported capture result keys.
+ *
+ * <p>Any keys included in this list must be available as part of the registered
+ * {@link ProcessResultImpl} callback. In case frame processing is not supported,
+ * then the Camera2/CameraX framework will use the list to filter and notify camera clients
+ * using the respective camera results.</p>
+ *
+ * <p>At the very minimum, it is expected that the result key list is a superset of the
+ * capture request keys.</p>
+ *
+ * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p>
+ *
+ * @return List of supported capture result keys, or an empty list if capture results are not
+ * supported.
+ * @since 1.3
+ */
+ List<CaptureResult.Key> getAvailableCaptureResultKeys();
+
+ /**
+ * Advertise support for {@link ProcessResultImpl#onCaptureProcessProgressed}.
+ *
+ * @return {@code true} in case the process progress callback is supported and is expected to
+ * be triggered, {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isCaptureProcessProgressAvailable();
+
+ /**
+ * Returns the dynamically calculated capture latency pair in milliseconds.
+ *
+ * <p>In contrast to {@link #getEstimatedCaptureLatencyRange} this method is guaranteed to be
+ * called after the camera capture session is initialized and camera preview is enabled.
+ * The measurement is expected to take in to account dynamic parameters such as the current
+ * scene, the state of 3A algorithms, the state of internal HW modules and return a more
+ * accurate assessment of the still capture latency.</p>
+ *
+ * @return pair that includes the estimated input frame/frames camera capture latency as the
+ * first field and the estimated post-processing latency {@link CaptureProcessorImpl#process}
+ * as the second pair field. Both first and second fields will be in milliseconds. The total
+ * still capture latency will be the sum of both the first and second values.
+ * The pair is expected to be null if the dynamic latency estimation is not supported.
+ * If clients have not configured a still capture output, then this method can also return a
+ * null pair.
+ * @since 1.4
+ */
+ Pair<Long, Long> getRealtimeCaptureLatency();
+
+ /**
+ * Indicates whether the extension supports the postview for still capture feature.
+ * If the extension is using HAL processing, false should be returned since the
+ * postview feature is not currently supported for this case.
+ *
+ * @return {@code true} in case postview for still capture is supported
+ * {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isPostviewAvailable();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/InitializerImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/InitializerImpl.java
new file mode 100644
index 00000000..fe2afd52
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/InitializerImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ * Used for initializing the extensions library.
+ *
+ * @since 1.1
+ * @hide
+ */
+public class InitializerImpl {
+ private InitializerImpl() {
+ }
+
+ private static final String TAG = "InitializerImpl";
+ /**
+ * An unknown error has occurred.
+ * @hide
+ */
+ public static final int ERROR_UNKNOWN = 0;
+ /**
+ * Error reported if the application version of extensions is incompatible with the on device
+ * library version.
+ * @hide
+ */
+ public static final int ERROR_INITIALIZE_VERSION_INCOMPATIBLE = 1;
+ private static Executor sExecutor = Executors.newSingleThreadExecutor();
+
+ /**
+ * Initializes the {@link Context}.
+ *
+ * <p>Before this call has been made no calls to the extensions library should be made except
+ * for {@link ExtensionVersionImpl#checkApiVersion(String)}.
+ *
+ * @param version The version of the extension used by the application.
+ * @param context The {@link Context} of the calling application.
+ * @param executor The executor to run the callback on. If null then the callback will run on
+ * any arbitrary executor.
+ * @hide
+ */
+ public static void init(String version, Context context,
+ OnExtensionsInitializedCallback callback, Executor executor) {
+ Log.d(TAG, "initializing extensions");
+ if (executor == null) {
+ sExecutor.execute(callback::onSuccess);
+ } else {
+ executor.execute(callback::onSuccess);
+ }
+ }
+
+ /**
+ * Deinitializes the extensions to release resources.
+ *
+ * <p>After this call has been made no calls to the extensions library should be made except
+ * for {@link ExtensionVersionImpl#checkApiVersion(String)}.
+ *
+ * @param executor The executor to run the callback on. If null then the callback will run on
+ * any arbitrary executor.
+ * @hide
+ */
+ public static void deinit(OnExtensionsDeinitializedCallback callback,
+ Executor executor) {
+ Log.d(TAG, "deinitializing extensions");
+ if (executor == null) {
+ sExecutor.execute(callback::onSuccess);
+ } else {
+ executor.execute(callback::onSuccess);
+ }
+ }
+
+ /**
+ * Callback that gets called when the library has finished initializing and is ready for used.
+ * @hide
+ */
+ public interface OnExtensionsInitializedCallback {
+ /** Called if the library successfully initializes. */
+ void onSuccess();
+
+ /**
+ * Called if the library is unable to successfully initialize.
+ *
+ * @param error The reason for failing to initialize.
+ */
+ void onFailure(int error);
+ }
+
+ /**
+ * Callback that gets called when the library has finished deinitialized.
+ *
+ * <p> Once this interface has been called then
+ * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} can be called
+ * again regardless of whether or not the deinitialization has succeeded or failed.
+ * @hide
+ */
+ public interface OnExtensionsDeinitializedCallback {
+ /** Called if the library successfully deinitializes. */
+ void onSuccess();
+
+ /**
+ * Called if the library encountered some error during the deinitialization.
+ *
+ * <p>Even if the library fails to deinitialize it is now valid for {@link
+ * #init(String, Context, OnExtensionsInitializedCallback, Executor)} to be called
+ * again.
+ *
+ * @param error The reason for failing to deinitialize.
+ */
+ void onFailure(int error);
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..6f0eaef9
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for night image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class NightImageCaptureExtenderImpl implements ImageCaptureExtenderImpl {
+ public NightImageCaptureExtenderImpl() {}
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Nullable
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
new file mode 100755
index 00000000..825994f5
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Stub implementation for night preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class NightPreviewExtenderImpl implements PreviewExtenderImpl {
+ public NightPreviewExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @Nullable CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public void onDeInit() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
new file mode 100644
index 00000000..43249873
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.TotalCaptureResult;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions in the preview.
+ *
+ * @since 1.0
+ */
+public interface PreviewExtenderImpl extends ExtenderStateListener {
+ /** The different types of the preview processing. */
+ enum ProcessorType {
+ /** Processor which only updates the {@link CaptureStageImpl}. */
+ PROCESSOR_TYPE_REQUEST_UPDATE_ONLY,
+ /** Processor which updates the received {@link android.media.Image}. */
+ PROCESSOR_TYPE_IMAGE_PROCESSOR,
+ /** No processor, only a {@link CaptureStageImpl} is defined. */
+ PROCESSOR_TYPE_NONE
+ }
+
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable(String, CameraCharacteristics)}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ */
+ void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The set of parameters required to produce the effect on the preview stream.
+ *
+ * <p> This will be the initial set of parameters used for the preview
+ * {@link android.hardware.camera2.CaptureRequest}. If the {@link ProcessorType} is defined as
+ * {@link ProcessorType#PROCESSOR_TYPE_REQUEST_UPDATE_ONLY} then this will be updated when
+ * the {@link RequestUpdateProcessorImpl#process(TotalCaptureResult)} from {@link
+ * #getProcessor()} has been called, this should be updated to reflect the new {@link
+ * CaptureStageImpl}. If the processing step returns a {@code null}, meaning the required
+ * parameters has not changed, then calling this will return the previous non-null value.
+ */
+ CaptureStageImpl getCaptureStage();
+
+ /** The type of preview processing to use. */
+ ProcessorType getProcessorType();
+
+ /**
+ * Returns a processor which only updates the {@link CaptureStageImpl}.
+ *
+ * <p>The type of processor is dependent on the return of {@link #getProcessorType()}. The
+ * type of ProcessorImpl returned will be according to the following table.
+ *
+ * <table>
+ * <tr><th> ProcessorType </th> <th> ProcessorImpl </th> </tr>
+ * <tr><td> PROCESSOR_TYPE_REQUEST_UPDATE_ONLY </td> <td> RequestUpdateProcessorImpl </td> </tr>
+ * <tr><td> PROCESSOR_TYPE_IMAGE_PROCESSOR </td> <td> PreviewImageProcessorImpl </td> </tr>
+ * <tr><td> PROCESSOR_TYPE_NONE </td> <td> null </td> </tr>
+ * </table>
+ */
+ ProcessorImpl getProcessor();
+
+ /**
+ * Returns the customized supported resolutions.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the
+ * returned list is not null, it will be used to find the best resolutions combination for
+ * the bound use cases.
+ *
+ * @return the customized supported resolutions.
+ * @since 1.1
+ */
+ @Nullable
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
new file mode 100644
index 00000000..f203ebad
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Processes a single {@link Image} and {@link TotalCaptureResult} to produce an output to a
+ * stream.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface PreviewImageProcessorImpl extends ProcessorImpl {
+ /**
+ * Processes the requested image capture.
+ *
+ * <p> The result of the processing step should be written to the {@link android.view.Surface}
+ * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}.
+ *
+ * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will be
+ * invalid after the method completes so no reference to it should be kept.
+ * @param result The metadata associated with the image to process.
+ */
+ void process(Image image, TotalCaptureResult result);
+
+ /**
+ * Processes the requested image capture.
+ *
+ * <p> The result of the processing step should be written to the {@link android.view.Surface}
+ * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}.
+ *
+ * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will
+ * be invalid after the method completes so no reference to it should be
+ * kept.
+ * @param result The metadata associated with the image to process.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback will
+ * run on any arbitrary executor.
+ * @since 1.3
+ */
+ void process(Image image, TotalCaptureResult result, ProcessResultImpl resultCallback,
+ Executor executor);
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
new file mode 100644
index 00000000..0e154450
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+
+import java.util.List;
+
+/**
+ * Allows clients to receive information about the capture result values of processed frames.
+ *
+ */
+@SuppressLint("UnknownNullness")
+public interface ProcessResultImpl {
+ /**
+ * Capture result callback that needs to be called when the process capture results are
+ * ready as part of frame post-processing.
+ *
+ * @param shutterTimestamp The shutter time stamp of the processed frame.
+ * @param result Key value pairs for all supported capture results. Do note that
+ * if results 'android.jpeg.quality' and 'android.jpeg.orientation'
+ * are present in the process capture input results, then the values
+ * must also be passed as part of this callback. Both Camera2 and
+ * CameraX guarantee that those two settings and results are always
+ * supported and applied by the corresponding framework.
+ * @since 1.3
+ */
+ void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result);
+
+ /**
+ * Capture progress callback that needs to be called when the process capture is
+ * ongoing and includes the estimated progress of the processing.
+ *
+ * <p>Extensions must ensure that they always call this callback with monotonically increasing
+ * values.</p>
+ *
+ * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the
+ * callback is expected to be called once when processing is done with value 100.</p>
+ *
+ * @param progress Value between 0 and 100.
+ * @since 1.4
+ */
+ void onCaptureProcessProgressed(int progress);
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
new file mode 100644
index 00000000..6be328be
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.util.Size;
+import android.view.Surface;
+
+/**
+ * Processes an input image stream and produces an output image stream.
+ *
+ * @since 1.0
+ */
+public interface ProcessorImpl {
+ /**
+ * Updates where the ProcessorImpl should write the output to.
+ *
+ * @param surface The {@link Surface} that the ProcessorImpl should write data into.
+ * @param imageFormat The format of that the surface expects.
+ */
+ void onOutputSurface(Surface surface, int imageFormat);
+
+ /**
+ * Invoked when CameraX changes the configured output resolution.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to be at the specified resolution.
+ *
+ * @param size for the surface.
+ */
+ void onResolutionUpdate(Size size);
+
+ /**
+ * Invoked when CameraX changes the configured input image format.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input to have the specified image format.
+ *
+ * @param imageFormat for the surface.
+ */
+ void onImageFormatUpdate(int imageFormat);
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
new file mode 100644
index 00000000..14637d7c
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.hardware.camera2.TotalCaptureResult;
+
+/**
+ * Processes a {@link TotalCaptureResult} to update a CaptureStage.
+ *
+ * @since 1.0
+ */
+public interface RequestUpdateProcessorImpl extends ProcessorImpl {
+ /**
+ * Process the {@link TotalCaptureResult} to update the {@link CaptureStageImpl}
+ *
+ * @param result The metadata associated with the image. Can be null if the image and meta have
+ * not been synced.
+ * @return The updated parameters used for the repeating requests. If this is {@code null} then
+ * the previous parameters will be used.
+ */
+ CaptureStageImpl process(TotalCaptureResult result);
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
new file mode 100644
index 00000000..abcbf5fd
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.camera.extensions.impl.ExtensionVersionImpl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Advanced OEM contract for implementing Extensions. ImageCapture/Preview Extensions are both
+ * implemented on this interface.
+ *
+ * <p>This advanced OEM contract empowers OEM to gain access to more Camera2 capability. This
+ * includes: (1) Add custom surfaces with specific formats like YUV, RAW, RAW_DEPTH. (2) Access to
+ * the capture request callbacks as well as all the images retrieved of various image formats. (3)
+ * Able to triggers single or repeating request with the capabilities to specify target surfaces,
+ * template id and parameters.
+ *
+ * <p>OEM needs to implement it with class name HdrAdvancedExtenderImpl for HDR,
+ * NightAdvancedExtenderImpl for night mode, BeautyAdvancedExtenderImpl for beauty mode,
+ * BokehAdvancedExtenderImpl for bokeh mode and AutoAdvancedExtenderImpl for auto mode.
+ *
+ * <p>OEMs are required to return true in
+ * {@link ExtensionVersionImpl#isAdvancedExtenderImplemented()} in order to request CameraX to
+ * use advanced extender over basic extender. OEM is okay to implement advanced
+ * extender only Or basic extender only. However the caveat of advanced-only implementation is,
+ * extensions will be unavailable on the apps using interfaces prior to 1.2.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public interface AdvancedExtenderImpl {
+
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param characteristicsMap A map consisting of the camera ids and the
+ * {@link CameraCharacteristics}s. For every camera, the map
+ * contains at least the CameraCharacteristics for the camera id.
+ * If the camera is logical camera, it will also contain associated
+ * physical camera ids and their CameraCharacteristics.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param characteristicsMap A map consisting of the camera ids and the
+ * {@link CameraCharacteristics}s. For every camera, the map
+ * contains at least the CameraCharacteristics for the camera id.
+ * If the camera is logical camera, it will also contain associated
+ * physical camera ids and their CameraCharacteristics.
+ */
+ void init(String cameraId, Map<String, CameraCharacteristics> characteristicsMap);
+
+ /**
+ * Returns the estimated capture latency range in milliseconds for the
+ * target capture resolution during the calls to
+ * {@link SessionProcessorImpl#startCapture}. This
+ * includes the time spent processing the multi-frame capture request along with any additional
+ * time for encoding of the processed buffer in the framework if necessary.
+ *
+ * @param cameraId the camera id
+ * @param captureOutputSize size of the capture output surface. If it is null or not in the
+ * supported output sizes, maximum capture output size is used for
+ * the estimation.
+ * @param imageFormat the image format of the capture output surface.
+ * @return the range of estimated minimal and maximal capture latency in milliseconds.
+ * Returns null if no capture latency info can be provided.
+ */
+ Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
+ Size captureOutputSize, int imageFormat);
+
+ /**
+ * Returns supported output format/size map for preview. The format could be PRIVATE or
+ * YUV_420_888. OEM must support PRIVATE format at least. CameraX will only use resolutions
+ * for preview from the list.
+ *
+ * <p>The preview surface format in the CameraCaptureSession may not be identical to the
+ * supported preview output format returned here. Like in the basic extender interface, the
+ * preview PRIVATE surface could be added to the CameraCaptureSession and OEM processes it in
+ * the HAL. Alternatively OEM can configure a intermediate YUV surface of the same size and
+ * writes the output to the preview output surface.
+ */
+ Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId);
+
+ /**
+ * Returns supported output format/size map for image capture. OEM is required to support
+ * both JPEG and YUV_420_888 format output.
+ *
+ * <p>Like in the basic extender interface, the surface created with this supported
+ * format/size could be either added in CameraCaptureSession with HAL processing OR it
+ * configures intermediate surfaces(YUV/RAW..) and writes the output to the output surface.
+ */
+ Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId);
+
+ /**
+ * Returns supported output format/size map for postview image. OEM is required to support
+ * both JPEG and YUV_420_888 format output.
+ *
+ * <p>The surface created with this supported format/size could configure
+ * intermediate surfaces(YUV/RAW..) and write the output to the output surface.</p>
+ *
+ * @since 1.4
+ */
+ Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize);
+
+ /**
+ * Returns supported output sizes for Image Analysis (YUV_420_888 format).
+ *
+ * <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture
+ * output surfaces. If imageAnalysis YUV surface is not supported, OEM should return null or
+ * empty list.
+ */
+ List<Size> getSupportedYuvAnalysisResolutions(String cameraId);
+
+ /**
+ * Returns a processor for activating extension sessions. It implements all the interactions
+ * required for starting a extension and cleanup.
+ */
+ SessionProcessorImpl createSessionProcessor();
+
+ /**
+ * Returns a list of orthogonal capture request keys.
+ *
+ * <p>Any keys included in the list will be configurable by clients of the extension and will
+ * affect the extension functionality.</p>
+ *
+ * <p>Please note that the keys {@link CaptureRequest#JPEG_QUALITY} and
+ * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the
+ * list or not. To support common camera operations like zoom, tap-to-focus, flash and
+ * exposure compensation, we recommend supporting the following keys if possible.
+ * <pre>
+ * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO}
+ * {@link CaptureRequest#SCALER_CROP_REGION}
+ * tap-to-focus:
+ * {@link CaptureRequest#CONTROL_AF_MODE}
+ * {@link CaptureRequest#CONTROL_AF_TRIGGER}
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}
+ * {@link CaptureRequest#CONTROL_AE_REGIONS}
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS}
+ * flash:
+ * {@link CaptureRequest#CONTROL_AE_MODE}
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
+ * {@link CaptureRequest#FLASH_MODE}
+ * exposure compensation:
+ * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
+ * </pre>
+ *
+ * @return List of supported orthogonal capture keys, or an empty list if no capture settings
+ * are not supported.
+ * @since 1.3
+ */
+ List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
+
+ /**
+ * Returns a list of supported capture result keys.
+ *
+ * <p>Any keys included in this list must be available as part of the registered
+ * {@link SessionProcessorImpl.CaptureCallback#onCaptureCompleted} callback.</p>
+ *
+ * <p>At the very minimum, it is expected that the result key list is a superset of the
+ * capture request keys.</p>
+ *
+ * @return List of supported capture result keys, or
+ * an empty list if capture results are not supported.
+ * @since 1.3
+ */
+ List<CaptureResult.Key> getAvailableCaptureResultKeys();
+
+ /**
+ * Advertise support for {@link SessionProcessorImpl#onCaptureProcessProgressed}.
+ *
+ * @return {@code true} in case the process progress callback is supported and is expected to
+ * be triggered, {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isCaptureProcessProgressAvailable();
+
+ /**
+ * Indicates whether the extension supports the postview for still capture feature.
+ * If the extension is using HAL processing, false should be returned since the
+ * postview feature is not currently supported for this case.
+ *
+ * @return {@code true} in case postview for still capture is supported
+ * {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isPostviewAvailable();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
new file mode 100644
index 00000000..06c8c44a
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import androidx.camera.extensions.impl.advanced.BaseAdvancedExtenderImpl.BaseAdvancedSessionProcessor;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.os.Build;
+import android.util.Log;
+
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressLint("UnknownNullness")
+public class AutoAdvancedExtenderImpl extends BaseAdvancedExtenderImpl {
+
+ protected static final int AWB_MODE_DAYLIGHT = CaptureRequest.CONTROL_AWB_MODE_DAYLIGHT;
+
+ public AutoAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ // Requires API 23 for ImageWriter
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ CameraCharacteristics cameraCharacteristics = characteristicsMap.get(cameraId);
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics,
+ AWB_MODE_DAYLIGHT);
+ }
+
+ public class AutoAdvancedSessionProcessor extends BaseAdvancedSessionProcessor {
+
+ public AutoAdvancedSessionProcessor() {
+ appendTag("::Auto");
+ }
+
+ @Override
+ protected void addSessionParameter(Camera2SessionConfigImplBuilder builder) {
+ builder.addSessionParameter(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_DAYLIGHT);
+ }
+
+ @Override
+ protected void addCaptureRequestParameters(List<RequestProcessorImpl.Request> requestList) {
+ RequestBuilder build = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, DEFAULT_CAPTURE_ID);
+ build.setParameters(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_DAYLIGHT);
+ applyParameters(build);
+
+ requestList.add(build.build());
+ }
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return new AutoAdvancedSessionProcessor();
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java
new file mode 100644
index 00000000..00b57058
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BaseAdvancedExtenderImpl.java
@@ -0,0 +1,699 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import androidx.camera.extensions.impl.advanced.JpegEncoder;
+
+import static androidx.camera.extensions.impl.advanced.JpegEncoder.JPEG_DEFAULT_QUALITY;
+import static androidx.camera.extensions.impl.advanced.JpegEncoder.JPEG_DEFAULT_ROTATION;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@SuppressLint("UnknownNullness")
+public abstract class BaseAdvancedExtenderImpl implements AdvancedExtenderImpl {
+
+ static {
+ try {
+ System.loadLibrary("encoderjpeg_jni");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e("BaseAdvancedExtenderImpl", "libencoderjpeg_jni not loaded");
+ }
+ }
+
+ protected CameraCharacteristics mCameraCharacteristics;
+
+ public BaseAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public abstract boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap);
+
+ @Override
+ public void init(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ mCameraCharacteristics = characteristicsMap.get(cameraId);
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(
+ String cameraId, Size size, int imageFormat) {
+ return null;
+ }
+
+ protected Map<Integer, List<Size>> filterOutputResolutions(List<Integer> formats) {
+ Map<Integer, List<Size>> formatResolutions = new HashMap<>();
+
+ StreamConfigurationMap map =
+ mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ if (map != null) {
+ for (Integer format : formats) {
+ if (map.getOutputSizes(format) != null) {
+ formatResolutions.put(format, Arrays.asList(map.getOutputSizes(format)));
+ }
+ }
+ }
+
+ return formatResolutions;
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId) {
+ return filterOutputResolutions(Arrays.asList(ImageFormat.PRIVATE, ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId) {
+ return filterOutputResolutions(Arrays.asList(ImageFormat.JPEG, ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize) {
+ return new HashMap<>();
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(
+ String cameraId) {
+ return null;
+ }
+
+ public class BaseAdvancedSessionProcessor implements SessionProcessorImpl {
+ protected String TAG = "BaseAdvancedSessionProcessor";
+
+ protected static final int DEFAULT_CAPTURE_ID = 0;
+ protected static final int BASIC_CAPTURE_PROCESS_MAX_IMAGES = 3;
+ protected static final int MAX_NUM_IMAGES = 1;
+
+ protected Camera2OutputConfigImpl mPreviewOutputConfig;
+ protected Camera2OutputConfigImpl mCaptureOutputConfig;
+
+ protected OutputSurfaceImpl mPreviewOutputSurfaceConfig;
+ protected OutputSurfaceImpl mCaptureOutputSurfaceConfig;
+
+ protected final Object mLock = new Object();
+ @GuardedBy("mLock")
+ protected Map<CaptureRequest.Key<?>, Object> mParameters = new LinkedHashMap<>();
+
+ protected final Object mLockCaptureSurfaceImageWriter = new Object();
+ @GuardedBy("mLockCaptureSurfaceImageWriter")
+ protected ImageWriter mCaptureSurfaceImageWriter;
+
+ protected CaptureResultImageMatcher mImageCaptureCaptureResultImageMatcher =
+ new CaptureResultImageMatcher();
+ protected HashMap<Integer, Pair<ImageReferenceImpl, TotalCaptureResult>> mCaptureResults =
+ new HashMap<>();
+ protected RequestProcessorImpl mRequestProcessor;
+
+ protected List<Integer> mCaptureIdList = List.of(DEFAULT_CAPTURE_ID);
+
+ protected AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
+
+ protected void appendTag(String tag) {
+ TAG += tag;
+ }
+
+ @Override
+ @NonNull
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceConfigurationImpl surfaceConfigs) {
+
+ Log.d(TAG, "initSession cameraId=" + cameraId);
+
+ mPreviewOutputSurfaceConfig = surfaceConfigs.getPreviewOutputSurface();
+ mCaptureOutputSurfaceConfig = surfaceConfigs.getImageCaptureOutputSurface();
+
+ Camera2SessionConfigImplBuilder builder =
+ new Camera2SessionConfigImplBuilder()
+ .setSessionTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+
+ // Preview
+ if (mPreviewOutputSurfaceConfig.getSurface() != null) {
+ Camera2OutputConfigImplBuilder previewOutputConfigBuilder;
+
+ previewOutputConfigBuilder =
+ Camera2OutputConfigImplBuilder.newSurfaceConfig(
+ mPreviewOutputSurfaceConfig.getSurface());
+
+ mPreviewOutputConfig = previewOutputConfigBuilder.build();
+
+ builder.addOutputConfig(mPreviewOutputConfig);
+ }
+
+ // Image Capture
+ if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+ Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
+
+ captureOutputConfigBuilder =
+ Camera2OutputConfigImplBuilder.newImageReaderConfig(
+ mCaptureOutputSurfaceConfig.getSize(),
+ ImageFormat.YUV_420_888,
+ BASIC_CAPTURE_PROCESS_MAX_IMAGES);
+
+ mCaptureOutputConfig = captureOutputConfigBuilder.build();
+
+ builder.addOutputConfig(mCaptureOutputConfig);
+ }
+
+ addSessionParameter(builder);
+
+ return builder.build();
+ }
+
+ @Override
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) {
+
+ // Since this sample impl uses version 1.4, the other initSession method will be
+ // called. This is just a sample for earlier versions if wanting to redirect this call.
+ OutputSurfaceConfigurationImplImpl surfaceConfigs =
+ new OutputSurfaceConfigurationImplImpl(previewSurfaceConfig,
+ imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig,
+ null /*postviewSurfaceConfig*/);
+
+ return initSession(cameraId, cameraCharacteristicsMap, context, surfaceConfigs);
+ }
+
+ protected void addSessionParameter(Camera2SessionConfigImplBuilder builder) {
+ // default empty implementation
+ }
+
+ @Override
+ public void deInitSession() {
+ synchronized (mLockCaptureSurfaceImageWriter) {
+ if (mCaptureSurfaceImageWriter != null) {
+ mCaptureSurfaceImageWriter.close();
+ mCaptureSurfaceImageWriter = null;
+ }
+ }
+ }
+
+ @Override
+ public void setParameters(@NonNull Map<CaptureRequest.Key<?>, Object> parameters) {
+ synchronized (mLock) {
+ for (CaptureRequest.Key<?> key : parameters.keySet()) {
+ Object value = parameters.get(key);
+ if (value != null) {
+ mParameters.put(key, value);
+ }
+ }
+ }
+ }
+
+ protected void applyParameters(RequestBuilder builder) {
+ synchronized (mLock) {
+ for (CaptureRequest.Key<?> key : mParameters.keySet()) {
+ Object value = mParameters.get(key);
+ builder.setParameters(key, value);
+ }
+ }
+ }
+
+ protected void addTriggerRequestKeys(RequestBuilder builder,
+ Map<CaptureRequest.Key<?>, Object> triggers) {
+ HashSet<CaptureRequest.Key> supportedCaptureRequestKeys =
+ new HashSet<>(getAvailableCaptureRequestKeys());
+
+ for (CaptureRequest.Key<?> key : triggers.keySet()) {
+ if (supportedCaptureRequestKeys.contains(key)) {
+ Object value = triggers.get(key);
+ builder.setParameters(key, value);
+ }
+ }
+ }
+
+ @Override
+ public int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers,
+ CaptureCallback captureCallback) {
+ RequestBuilder builder = new RequestBuilder(mPreviewOutputConfig.getId(),
+ CameraDevice.TEMPLATE_PREVIEW, 0);
+ addTriggerRequestKeys(builder, triggers);
+
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request request, long frameNumber,
+ long timestamp) {
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request request,
+ CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request request,
+ TotalCaptureResult totalCaptureResult) {
+ addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+
+ captureCallback.onCaptureProcessStarted(seqId);
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request request,
+ CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ mRequestProcessor.submit(builder.build(), callback);
+
+ return seqId;
+ }
+
+ @Override
+ public void onCaptureSessionStart(@NonNull RequestProcessorImpl requestProcessor) {
+ mRequestProcessor = requestProcessor;
+
+ if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+ synchronized (mLockCaptureSurfaceImageWriter) {
+ if (JpegEncoder.imageFormatToPublic(mCaptureOutputSurfaceConfig
+ .getImageFormat()) == ImageFormat.JPEG) {
+ mCaptureSurfaceImageWriter = new ImageWriter
+ .Builder(mCaptureOutputSurfaceConfig.getSurface())
+ .setImageFormat(ImageFormat.JPEG)
+ .setMaxImages(MAX_NUM_IMAGES)
+ // For JPEG format, width x height should be set to (w*h) x 1
+ // since the JPEG image is returned as a 1D byte array
+ .setWidthAndHeight(mCaptureOutputSurfaceConfig.getSize().getWidth()
+ * mCaptureOutputSurfaceConfig.getSize().getHeight(), 1)
+ .build();
+ } else {
+ mCaptureSurfaceImageWriter = new ImageWriter
+ .Builder(mCaptureOutputSurfaceConfig.getSurface())
+ .setImageFormat(mCaptureOutputSurfaceConfig.getImageFormat())
+ .setMaxImages(MAX_NUM_IMAGES)
+ .build();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onCaptureSessionEnd() {
+ synchronized (this) {
+ mImageCaptureCaptureResultImageMatcher.clear();
+ }
+
+ mRequestProcessor = null;
+ }
+
+ @Override
+ public int startRepeating(@NonNull CaptureCallback captureCallback) {
+ RequestBuilder builder = new RequestBuilder(mPreviewOutputConfig.getId(),
+ CameraDevice.TEMPLATE_PREVIEW, 0);
+ applyParameters(builder);
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request request, long frameNumber,
+ long timestamp) {
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request request,
+ CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request request,
+ TotalCaptureResult totalCaptureResult) {
+ addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+
+ captureCallback.onCaptureProcessStarted(seqId);
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request request,
+ CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ mRequestProcessor.setRepeating(builder.build(), callback);
+
+ return seqId;
+ }
+
+ protected void addCaptureResultKeys(
+ @NonNull int seqId,
+ @NonNull TotalCaptureResult result,
+ @NonNull CaptureCallback captureCallback) {
+ HashMap<CaptureResult.Key, Object> captureResults = new HashMap<>();
+
+ Long shutterTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+
+ if (shutterTimestamp != null) {
+
+ List<CaptureResult.Key> captureResultKeys = getAvailableCaptureResultKeys();
+ for (CaptureResult.Key key : captureResultKeys) {
+ if (result.get(key) != null) {
+ captureResults.put(key, result.get(key));
+ }
+ }
+
+ captureCallback.onCaptureCompleted(shutterTimestamp, seqId,
+ captureResults);
+ }
+ }
+
+ protected void addCaptureRequestParameters(List<RequestProcessorImpl.Request> requestList) {
+ RequestBuilder build = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, DEFAULT_CAPTURE_ID);
+ applyParameters(build);
+
+ requestList.add(build.build());
+ }
+
+ @Override
+ public int startCaptureWithPostview(@NonNull CaptureCallback captureCallback) {
+ return startCapture(captureCallback);
+ }
+
+ @Override
+ public int startCapture(@NonNull CaptureCallback captureCallback) {
+ List<RequestProcessorImpl.Request> requestList = new ArrayList<>();
+ addCaptureRequestParameters(requestList);
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request request,
+ long frameNumber, long timestamp) {
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request request,
+ CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request request,
+ TotalCaptureResult totalCaptureResult) {
+ RequestBuilder.RequestProcessorRequest requestProcessorRequest =
+ (RequestBuilder.RequestProcessorRequest) request;
+
+ addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+
+ mImageCaptureCaptureResultImageMatcher.setCameraCaptureCallback(
+ totalCaptureResult,
+ requestProcessorRequest.getCaptureStageId());
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request request,
+ CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ captureCallback.onCaptureProcessProgressed(100);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ Log.d(TAG, "startCapture");
+
+ mRequestProcessor.submit(requestList, callback);
+
+ if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+ mRequestProcessor.setImageProcessor(mCaptureOutputConfig.getId(),
+ new ImageProcessorImpl() {
+ @Override
+ public void onNextImageAvailable(int outputStreamId,
+ long timestampNs,
+ @NonNull ImageReferenceImpl imgReferenceImpl,
+ @Nullable String physicalCameraId) {
+ mImageCaptureCaptureResultImageMatcher
+ .setInputImage(imgReferenceImpl);
+ }
+ });
+
+ mImageCaptureCaptureResultImageMatcher.setImageReferenceListener(
+ new CaptureResultImageMatcher.ImageReferenceListener() {
+ @Override
+ public void onImageReferenceIncoming(
+ @NonNull ImageReferenceImpl imageReferenceImpl,
+ @NonNull TotalCaptureResult totalCaptureResult,
+ int captureId) {
+ captureCallback.onCaptureProcessStarted(seqId);
+ processImageCapture(imageReferenceImpl, totalCaptureResult,
+ captureId);
+ }
+ });
+ }
+
+ return seqId;
+ }
+
+ protected void processImageCapture(@NonNull ImageReferenceImpl imageReferenceImpl,
+ @NonNull TotalCaptureResult totalCaptureResult,
+ int captureId) {
+
+ mCaptureResults.put(captureId, new Pair<>(imageReferenceImpl, totalCaptureResult));
+
+ if (mCaptureResults.keySet().containsAll(mCaptureIdList)) {
+ List<Pair<ImageReferenceImpl, TotalCaptureResult>> imageDataPairs =
+ new ArrayList<>(mCaptureResults.values());
+
+ Image resultImage = null;
+ int captureSurfaceWriterImageFormat = ImageFormat.UNKNOWN;
+ synchronized (mLockCaptureSurfaceImageWriter) {
+ resultImage = mCaptureSurfaceImageWriter.dequeueInputImage();
+ captureSurfaceWriterImageFormat = mCaptureSurfaceImageWriter.getFormat();
+ }
+
+ if (captureSurfaceWriterImageFormat == ImageFormat.JPEG) {
+ // Simple processing sample that encodes image from YUV to JPEG
+ Image yuvImage = imageDataPairs.get(DEFAULT_CAPTURE_ID).first.get();
+
+ Integer jpegOrientation = JPEG_DEFAULT_ROTATION;
+
+ synchronized (mLock) {
+ if (mParameters.get(CaptureRequest.JPEG_ORIENTATION) != null) {
+ jpegOrientation =
+ (Integer) mParameters.get(CaptureRequest.JPEG_ORIENTATION);
+ }
+ }
+
+ JpegEncoder.encodeToJpeg(yuvImage, resultImage, jpegOrientation,
+ JPEG_DEFAULT_QUALITY);
+
+ resultImage.setTimestamp(yuvImage.getTimestamp());
+
+ } else {
+ // Simple processing sample that transfers bytes and returns image as is
+ ByteBuffer yByteBuffer = resultImage.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = resultImage.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = resultImage.getPlanes()[1].getBuffer();
+
+ yByteBuffer.put(imageDataPairs.get(
+ DEFAULT_CAPTURE_ID).first.get().getPlanes()[0].getBuffer());
+ uByteBuffer.put(imageDataPairs.get(
+ DEFAULT_CAPTURE_ID).first.get().getPlanes()[2].getBuffer());
+ vByteBuffer.put(imageDataPairs.get(
+ DEFAULT_CAPTURE_ID).first.get().getPlanes()[1].getBuffer());
+
+ resultImage.setTimestamp(imageDataPairs.get(
+ DEFAULT_CAPTURE_ID).first.get().getTimestamp());
+ }
+
+ synchronized (mLockCaptureSurfaceImageWriter) {
+ mCaptureSurfaceImageWriter.queueInputImage(resultImage);
+ }
+
+ for (Pair<ImageReferenceImpl, TotalCaptureResult> val : mCaptureResults.values()) {
+ val.first.decrement();
+ }
+ } else {
+ Log.w(TAG, "Unable to process, waiting for all images");
+ }
+ }
+
+ @Override
+ public void stopRepeating() {
+ mRequestProcessor.stopRepeating();
+ }
+
+ @Override
+ public void abortCapture(int captureSequenceId) {
+
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+ }
+
+ public static class OutputSurfaceConfigurationImplImpl implements OutputSurfaceConfigurationImpl {
+ private OutputSurfaceImpl mOutputPreviewSurfaceImpl;
+ private OutputSurfaceImpl mOutputImageCaptureSurfaceImpl;
+ private OutputSurfaceImpl mOutputImageAnalysisSurfaceImpl;
+ private OutputSurfaceImpl mOutputPostviewSurfaceImpl;
+
+ public OutputSurfaceConfigurationImplImpl(OutputSurfaceImpl previewSurfaceConfig,
+ OutputSurfaceImpl imageCaptureSurfaceConfig,
+ OutputSurfaceImpl imageAnalysisSurfaceConfig,
+ OutputSurfaceImpl postviewSurfaceConfig) {
+ mOutputPreviewSurfaceImpl = previewSurfaceConfig;
+ mOutputImageCaptureSurfaceImpl = imageCaptureSurfaceConfig;
+ mOutputImageAnalysisSurfaceImpl = imageAnalysisSurfaceConfig;
+ mOutputPostviewSurfaceImpl = postviewSurfaceConfig;
+ }
+
+ @Override
+ public OutputSurfaceImpl getPreviewOutputSurface() {
+ return mOutputPreviewSurfaceImpl;
+ }
+
+ @Override
+ public OutputSurfaceImpl getImageCaptureOutputSurface() {
+ return mOutputImageCaptureSurfaceImpl;
+ }
+
+ @Override
+ public OutputSurfaceImpl getImageAnalysisOutputSurface() {
+ return mOutputImageAnalysisSurfaceImpl;
+ }
+
+ @Override
+ public OutputSurfaceImpl getPostviewOutputSurface() {
+ return mOutputPostviewSurfaceImpl;
+ }
+ }
+
+ @Override
+ public abstract SessionProcessorImpl createSessionProcessor();
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ final CaptureRequest.Key [] CAPTURE_REQUEST_SET = {CaptureRequest.JPEG_QUALITY,
+ CaptureRequest.JPEG_ORIENTATION};
+ return Arrays.asList(CAPTURE_REQUEST_SET);
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ final CaptureResult.Key [] CAPTURE_RESULT_SET = {CaptureResult.JPEG_QUALITY,
+ CaptureResult.JPEG_ORIENTATION};
+ return Arrays.asList(CAPTURE_RESULT_SET);
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return true;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
new file mode 100644
index 00000000..d8ff59f9
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import androidx.camera.extensions.impl.advanced.BaseAdvancedExtenderImpl.BaseAdvancedSessionProcessor;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.os.Build;
+import android.util.Log;
+
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressLint("UnknownNullness")
+public class BeautyAdvancedExtenderImpl extends BaseAdvancedExtenderImpl {
+
+ protected static final int AWB_MODE_TWILIGHT = CaptureRequest.CONTROL_AWB_MODE_TWILIGHT;
+
+ public BeautyAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ // Requires API 23 for ImageWriter
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ CameraCharacteristics cameraCharacteristics = characteristicsMap.get(cameraId);
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics,
+ AWB_MODE_TWILIGHT);
+ }
+
+ public class BeautyAdvancedSessionProcessor extends BaseAdvancedSessionProcessor {
+
+ public BeautyAdvancedSessionProcessor() {
+ appendTag("::Beauty");
+ }
+
+ @Override
+ protected void addSessionParameter(Camera2SessionConfigImplBuilder builder) {
+ builder.addSessionParameter(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_TWILIGHT);
+ }
+
+ @Override
+ protected void addCaptureRequestParameters(List<RequestProcessorImpl.Request> requestList) {
+ RequestBuilder build = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, DEFAULT_CAPTURE_ID);
+ build.setParameters(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_TWILIGHT);
+ applyParameters(build);
+
+ requestList.add(build.build());
+ }
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return new BeautyAdvancedSessionProcessor();
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
new file mode 100644
index 00000000..01569911
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import androidx.camera.extensions.impl.advanced.BaseAdvancedExtenderImpl.BaseAdvancedSessionProcessor;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.Build;
+import android.util.Log;
+
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@SuppressLint("UnknownNullness")
+public class BokehAdvancedExtenderImpl extends BaseAdvancedExtenderImpl {
+
+ protected static final int AWB_MODE_SHADE = CaptureRequest.CONTROL_AWB_MODE_SHADE;
+
+ public BokehAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ // Requires API 23 for ImageWriter
+ if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ CameraCharacteristics cameraCharacteristics = characteristicsMap.get(cameraId);
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics,
+ AWB_MODE_SHADE) &&
+ CameraCharacteristicAvailability.hasFlashUnit(cameraCharacteristics);
+ }
+
+ public class BokehAdvancedSessionProcessor extends BaseAdvancedSessionProcessor {
+
+ public BokehAdvancedSessionProcessor() {
+ appendTag("::Bokeh");
+ }
+
+ @Override
+ protected void addSessionParameter(Camera2SessionConfigImplBuilder builder) {
+ builder.addSessionParameter(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_SHADE);
+ }
+
+ @Override
+ protected void addCaptureRequestParameters(List<RequestProcessorImpl.Request> requestList) {
+ RequestBuilder build = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, DEFAULT_CAPTURE_ID);
+ build.setParameters(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_SHADE);
+ applyParameters(build);
+
+ requestList.add(build.build());
+ }
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return new BokehAdvancedSessionProcessor();
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ final CaptureRequest.Key [] CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_LOCK,
+ CaptureRequest.FLASH_MODE, CaptureRequest.JPEG_QUALITY,
+ CaptureRequest.JPEG_ORIENTATION};
+ return Arrays.asList(CAPTURE_REQUEST_SET);
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ final CaptureResult.Key [] CAPTURE_RESULT_SET = {CaptureResult.CONTROL_AE_MODE,
+ CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureResult.CONTROL_AE_LOCK,
+ CaptureResult.CONTROL_AE_STATE, CaptureResult.FLASH_MODE,
+ CaptureResult.FLASH_STATE, CaptureResult.JPEG_QUALITY, CaptureResult.JPEG_ORIENTATION};
+ return Arrays.asList(CAPTURE_RESULT_SET);
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
new file mode 100644
index 00000000..68de01b6
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+import java.util.List;
+
+/**
+ * A config representing a {@link android.hardware.camera2.params.OutputConfiguration} where
+ * Surface will be created by the information in this config.
+ */
+@SuppressLint("UnknownNullness")
+public interface Camera2OutputConfigImpl {
+ /**
+ * Gets thd id of this output config. The id can be used to identify the stream in vendor
+ * implementations.
+ */
+ int getId();
+
+ /**
+ * Gets the surface group id. Vendor can use the surface group id to share memory between
+ * Surfaces.
+ */
+ int getSurfaceGroupId();
+
+ /**
+ * Gets the physical camera id. Returns null if not specified.
+ */
+ String getPhysicalCameraId();
+
+ /**
+ * If non-null, enable surface sharing and add the surface constructed by the return
+ * Camera2OutputConfig.
+ */
+ List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
new file mode 100644
index 00000000..868be834
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A builder implementation to help OEM build the {@link Camera2OutputConfigImpl} instance.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2OutputConfigImplBuilder {
+ static AtomicInteger sLastId = new AtomicInteger(0);
+ private OutputConfigImplImpl mOutputConfig;
+ private int mSurfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE;
+ private String mPhysicalCameraId;
+ private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs;
+
+ private Camera2OutputConfigImplBuilder(OutputConfigImplImpl outputConfig) {
+ mOutputConfig = outputConfig;
+ }
+
+ private int getNextId() {
+ return sLastId.getAndIncrement();
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that represents a {@link android.media.ImageReader}
+ * with the given parameters.
+ */
+ public static Camera2OutputConfigImplBuilder newImageReaderConfig(
+ Size size, int imageFormat, int maxImages) {
+ return new Camera2OutputConfigImplBuilder(
+ new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages));
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that represents a MultiResolutionImageReader with
+ * the given parameters.
+ */
+ public static Camera2OutputConfigImplBuilder newMultiResolutionImageReaderConfig(
+ int imageFormat, int maxImages) {
+ return new Camera2OutputConfigImplBuilder(
+ new MultiResolutionImageReaderOutputConfigImplImpl(imageFormat, maxImages));
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that contains the Surface directly.
+ */
+ public static Camera2OutputConfigImplBuilder newSurfaceConfig(Surface surface) {
+ return new Camera2OutputConfigImplBuilder(new SurfaceOutputConfigImplImpl(surface));
+ }
+
+ /**
+ * Adds a {@link Camera2SessionConfigImpl} to be shared with current config.
+ */
+ public Camera2OutputConfigImplBuilder addSurfaceSharingOutputConfig(
+ Camera2OutputConfigImpl camera2OutputConfig) {
+ if (mSurfaceSharingConfigs == null) {
+ mSurfaceSharingConfigs = new ArrayList<>();
+ }
+
+ mSurfaceSharingConfigs.add(camera2OutputConfig);
+ return this;
+ }
+
+ /**
+ * Sets a physical camera id.
+ */
+ public Camera2OutputConfigImplBuilder setPhysicalCameraId(String physicalCameraId) {
+ mPhysicalCameraId = physicalCameraId;
+ return this;
+ }
+
+ /**
+ * Sets surface group id.
+ */
+ public Camera2OutputConfigImplBuilder setSurfaceGroupId(int surfaceGroupId) {
+ mSurfaceGroupId = surfaceGroupId;
+ return this;
+ }
+
+ /**
+ * Build a {@link Camera2OutputConfigImpl} instance.
+ */
+ public Camera2OutputConfigImpl build() {
+ mOutputConfig.setId(getNextId());
+ mOutputConfig.setPhysicalCameraId(mPhysicalCameraId);
+ mOutputConfig.setSurfaceGroup(mSurfaceGroupId);
+ mOutputConfig.setSurfaceSharingConfigs(mSurfaceSharingConfigs);
+ return mOutputConfig;
+ }
+
+ private static class OutputConfigImplImpl implements Camera2OutputConfigImpl {
+ private int mId;
+ private int mSurfaceGroup;
+ private String mPhysicalCameraId;
+ private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs;
+
+ OutputConfigImplImpl() {
+ mId = -1;
+ mSurfaceGroup = 0;
+ mPhysicalCameraId = null;
+ mSurfaceSharingConfigs = null;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public int getSurfaceGroupId() {
+ return mSurfaceGroup;
+ }
+
+ @Override
+ public String getPhysicalCameraId() {
+ return mPhysicalCameraId;
+ }
+
+ @Override
+ public List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs() {
+ return mSurfaceSharingConfigs;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
+
+ public void setSurfaceGroup(int surfaceGroup) {
+ mSurfaceGroup = surfaceGroup;
+ }
+
+ public void setPhysicalCameraId(String physicalCameraId) {
+ mPhysicalCameraId = physicalCameraId;
+ }
+
+ public void setSurfaceSharingConfigs(
+ List<Camera2OutputConfigImpl> surfaceSharingConfigs) {
+ mSurfaceSharingConfigs = surfaceSharingConfigs;
+ }
+ }
+
+ private static class SurfaceOutputConfigImplImpl extends OutputConfigImplImpl
+ implements SurfaceOutputConfigImpl {
+ private Surface mSurface;
+
+ SurfaceOutputConfigImplImpl(Surface surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ public Surface getSurface() {
+ return mSurface;
+ }
+ }
+
+ private static class ImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
+ implements ImageReaderOutputConfigImpl {
+ private Size mSize;
+ private int mImageFormat;
+ private int mMaxImages;
+
+ ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages) {
+ mSize = size;
+ mImageFormat = imageFormat;
+ mMaxImages = maxImages;
+ }
+
+ @Override
+ public Size getSize() {
+ return mSize;
+ }
+
+ @Override
+ public int getImageFormat() {
+ return mImageFormat;
+ }
+
+ @Override
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+ }
+
+ private static class MultiResolutionImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
+ implements MultiResolutionImageReaderOutputConfigImpl {
+ private int mImageFormat;
+ private int mMaxImages;
+
+ MultiResolutionImageReaderOutputConfigImplImpl(int imageFormat, int maxImages) {
+ mImageFormat = imageFormat;
+ mMaxImages = maxImages;
+ }
+
+ @Override
+ public int getImageFormat() {
+ return mImageFormat;
+ }
+
+ @Override
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
new file mode 100644
index 00000000..6fb45bca
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureRequest;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A config representing a {@link android.hardware.camera2.params.SessionConfiguration}
+ */
+@SuppressLint("UnknownNullness")
+public interface Camera2SessionConfigImpl {
+ /**
+ * Returns all the {@link Camera2OutputConfigImpl}s that will be used to create
+ * {@link android.hardware.camera2.params.OutputConfiguration}.
+ */
+ List<Camera2OutputConfigImpl> getOutputConfigs();
+
+ /**
+ * Gets all the parameters to create the session parameters with.
+ */
+ Map<CaptureRequest.Key<?>, Object> getSessionParameters();
+
+ /**
+ * Gets the template id used for creating {@link CaptureRequest}s to be passed in
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}.
+ */
+ int getSessionTemplateId();
+
+ /**
+ * Retrieves the session type to be used when initializing the
+ * {@link android.hardware.camera2.CameraCaptureSession}.
+ *
+ * @since 1.4
+ * @return Camera capture session type. Regular and vendor specific types are supported but
+ * not high speed values. The extension can return -1 in which case the camera capture session
+ * will be configured to use the default regular type.
+ */
+ int getSessionType();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
new file mode 100644
index 00000000..dc1feccd
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A builder implementation to help OEM build the {@link Camera2SessionConfigImpl} instance.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2SessionConfigImplBuilder {
+ private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ private int mSessionType = SessionConfiguration.SESSION_REGULAR;
+ Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>();
+ List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>();
+
+ public Camera2SessionConfigImplBuilder() {
+ }
+
+ /**
+ * Adds a output config.
+ */
+ public Camera2SessionConfigImplBuilder addOutputConfig(
+ Camera2OutputConfigImpl outputConfig) {
+ mCamera2OutputConfigs.add(outputConfig);
+ return this;
+ }
+
+ /**
+ * Sets session parameters.
+ */
+ public <T> Camera2SessionConfigImplBuilder addSessionParameter(
+ CaptureRequest.Key<T> key, T value) {
+ mSessionParameters.put(key, value);
+ return this;
+ }
+
+ /**
+ * Sets the template id for session parameters request.
+ */
+ public Camera2SessionConfigImplBuilder setSessionTemplateId(int templateId) {
+ mSessionTemplateId = templateId;
+ return this;
+ }
+
+ /**
+ * Gets the session template id.
+ */
+ public int getSessionTemplateId() {
+ return mSessionTemplateId;
+ }
+
+ /**
+ * Gets the session parameters.
+ */
+ public Map<CaptureRequest.Key<?>, Object> getSessionParameters() {
+ return mSessionParameters;
+ }
+
+ /**
+ * Gets all the output configs.
+ */
+ public List<Camera2OutputConfigImpl> getCamera2OutputConfigs() {
+ return mCamera2OutputConfigs;
+ }
+
+ /**
+ * Gets the camera capture session type.
+ */
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
+ * Builds a {@link Camera2SessionConfigImpl} instance.
+ */
+ public Camera2SessionConfigImpl build() {
+ return new Camera2SessionConfigImplImpl(this);
+ }
+
+ private static class Camera2SessionConfigImplImpl implements
+ Camera2SessionConfigImpl {
+ int mSessionTemplateId;
+ int mSessionType;
+ Map<CaptureRequest.Key<?>, Object> mSessionParameters;
+ List<Camera2OutputConfigImpl> mCamera2OutputConfigs;
+
+ Camera2SessionConfigImplImpl(Camera2SessionConfigImplBuilder builder) {
+ mSessionTemplateId = builder.getSessionTemplateId();
+ mSessionParameters = builder.getSessionParameters();
+ mCamera2OutputConfigs = builder.getCamera2OutputConfigs();
+ mSessionType = builder.getSessionType();
+ }
+
+ @Override
+ public List<Camera2OutputConfigImpl> getOutputConfigs() {
+ return mCamera2OutputConfigs;
+ }
+
+ @Override
+ public Map<CaptureRequest.Key<?>, Object> getSessionParameters() {
+ return mSessionParameters;
+ }
+
+ @Override
+ public int getSessionTemplateId() {
+ return mSessionTemplateId;
+ }
+
+ @Override
+ public int getSessionType() {
+ return mSessionType;
+ }
+ }
+}
+
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CameraCharacteristicAvailability.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CameraCharacteristicAvailability.java
new file mode 100644
index 00000000..6a77e6c9
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CameraCharacteristicAvailability.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.util.Log;
+import android.util.Range;
+
+import java.util.Arrays;
+
+/**
+ * A utility class to check the availabilities of camera characteristics.
+ */
+final class CameraCharacteristicAvailability {
+ private static final String TAG = "CharacteristicAbility";
+
+ private CameraCharacteristicAvailability() {
+ }
+
+ /**
+ * Check if the given device supports flash.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @return {@code true} if the device supports flash
+ * {@code false} otherwise.
+ */
+ static boolean hasFlashUnit(CameraCharacteristics cameraCharacteristics) {
+ Boolean flashInfo = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+
+ return (flashInfo != null) ? flashInfo : false;
+ }
+
+ /**
+ * Check if the given device supports zoom ratio.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @return {@code true} if the device supports zoom ratio
+ * {@code false} otherwise.
+ */
+ static boolean supportsZoomRatio(CameraCharacteristics cameraCharacteristics) {
+ Range<Float> zoomRatioRange = cameraCharacteristics.get(
+ CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE);
+
+ return (zoomRatioRange != null) && (zoomRatioRange.getUpper() > 1.f);
+ }
+
+ /**
+ * Check if the given device is fixed focus or not.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @return {@code true} if the device is not fixed focus
+ * {@code false} otherwise.
+ */
+ static boolean hasFocuser(CameraCharacteristics cameraCharacteristics) {
+ Float minFocusDistance = cameraCharacteristics.get(
+ CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ if (minFocusDistance == null) {
+ Log.d(TAG, "No LENS_INFO_MINIMUM_FOCUS_DISTANCE info");
+ return false;
+ }
+
+ if (minFocusDistance > 0.f) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if the given white balance mode id is available in the camera characteristics.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @param mode white balance mode id.
+ * @return {@code true} if the given white balance mode id is available in the camera
+ * characteristics.
+ * {@code false} otherwise.
+ */
+ static boolean isWBModeAvailable(CameraCharacteristics cameraCharacteristics,
+ int mode) {
+ int[] availableModes = cameraCharacteristics.get(
+ CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES);
+ if (availableModes == null) {
+ Log.d(TAG, "No CONTROL_AWB_AVAILABLE_MODES info");
+ return false;
+ }
+
+ for (int availableMode : availableModes) {
+ if (availableMode == mode) {
+ return true;
+ }
+ }
+ Log.d(TAG, "wb mode: " + mode + " is not in available list "
+ + Arrays.toString(availableModes));
+ return false;
+ }
+
+ /**
+ * Check if the given effect id is available in the camera characteristics.
+ *
+ * @param cameraCharacteristics the camera characteristics.
+ * @param effect the effect id.
+ * @return {@code true} if the given effect id is available in the camera characteristics.
+ * {@code false} otherwise.
+ */
+ static boolean isEffectAvailable(CameraCharacteristics cameraCharacteristics,
+ int effect) {
+ int[] availableEffects = cameraCharacteristics.get(
+ CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS);
+ if (availableEffects == null) {
+ Log.d(TAG, "No CONTROL_AVAILABLE_EFFECTS info");
+ return false;
+ }
+
+ for (int availableEffect : availableEffects) {
+ if (availableEffect == effect) {
+ return true;
+ }
+ }
+ Log.d(TAG, "effect: " + effect + " is not in available list "
+ + Arrays.toString(availableEffects));
+ return false;
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CaptureResultImageMatcher.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CaptureResultImageMatcher.java
new file mode 100644
index 00000000..f93271b6
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/CaptureResultImageMatcher.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.util.LongSparseArray;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CaptureResultImageMatcher {
+ private static final String TAG = "CaptureResultImageReader";
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mClosed = false;
+
+ /** ImageInfos haven't been matched with Image. */
+ @GuardedBy("mLock")
+ private final LongSparseArray<TotalCaptureResult> mPendingImageInfos = new LongSparseArray<>();
+
+ Map<TotalCaptureResult, Integer> mCaptureStageIdMap = new HashMap<>();
+
+
+ /** Images haven't been matched with ImageInfo. */
+ @GuardedBy("mLock")
+ private final LongSparseArray<ImageReferenceImpl> mPendingImages = new LongSparseArray<>();
+
+ ImageReferenceListener mImageReferenceListener;
+
+ public CaptureResultImageMatcher() {
+
+ }
+
+ public void clear() {
+ synchronized (mLock) {
+ mPendingImageInfos.clear();
+ for (int i = 0; i < mPendingImages.size(); i++) {
+ long key = mPendingImages.keyAt(i);
+ mPendingImages.get(key).decrement();
+ }
+ mPendingImages.clear();
+ mCaptureStageIdMap.clear();
+ mClosed = false;
+ }
+ }
+
+ public void setImageReferenceListener(
+ @NonNull ImageReferenceListener imageReferenceImplListener) {
+ synchronized (mLock) {
+ mImageReferenceListener = imageReferenceImplListener;
+ }
+ }
+
+ public void setInputImage(@NonNull ImageReferenceImpl imageReferenceImpl) {
+ synchronized (mLock) {
+ if (mClosed) {
+ return;
+ }
+
+ Image image = imageReferenceImpl.get();
+ // Add the incoming Image to pending list and do the matching logic.
+ mPendingImages.put(image.getTimestamp(), imageReferenceImpl);
+ matchImages();
+ }
+ }
+
+ public void setCameraCaptureCallback(@NonNull TotalCaptureResult captureResult) {
+ setCameraCaptureCallback(captureResult, 0);
+ }
+
+ public void setCameraCaptureCallback(@NonNull TotalCaptureResult captureResult,
+ int captureStageId) {
+ synchronized (mLock) {
+ if (mClosed) {
+ return;
+ }
+
+ long timestamp = getTimeStampFromCaptureResult(captureResult);
+
+ // Add the incoming CameraCaptureResult to pending list and do the matching logic.
+ mPendingImageInfos.put(timestamp, captureResult);
+ mCaptureStageIdMap.put(captureResult, captureStageId);
+ matchImages();
+ }
+ }
+
+
+ private long getTimeStampFromCaptureResult(TotalCaptureResult captureResult) {
+ Long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
+ long timestampValue = -1;
+ if (timestamp != null) {
+ timestampValue = timestamp;
+ }
+
+ return timestampValue;
+ }
+
+
+ private void notifyImage(ImageReferenceImpl imageReferenceImpl,
+ TotalCaptureResult totalCaptureResult) {
+ synchronized (mLock) {
+ if (mImageReferenceListener != null) {
+ mImageReferenceListener.onImageReferenceIncoming(imageReferenceImpl,
+ totalCaptureResult, mCaptureStageIdMap.get(totalCaptureResult));
+ } else {
+ imageReferenceImpl.decrement();
+ }
+ }
+ }
+
+ // Remove the stale {@link ImageProxy} and {@link ImageInfo} from the pending queue if there are
+ // any missing which can happen if the camera is momentarily shut off.
+ // The ImageProxy and ImageInfo timestamps are assumed to be monotonically increasing. This
+ // means any ImageProxy or ImageInfo which has a timestamp older (smaller in value) than the
+ // oldest timestamp in the other queue will never get matched, so they should be removed.
+ //
+ // This should only be called at the end of matchImages(). The assumption is that there are no
+ // matching timestamps.
+ private void removeStaleData() {
+ synchronized (mLock) {
+ // No stale data to remove
+ if (mPendingImages.size() == 0 || mPendingImageInfos.size() == 0) {
+ return;
+ }
+
+ Long minImageProxyTimestamp = mPendingImages.keyAt(0);
+ Long minImageInfoTimestamp = mPendingImageInfos.keyAt(0);
+
+ // If timestamps are equal then matchImages did not correctly match up the ImageInfo
+ // and ImageProxy
+ if (minImageInfoTimestamp.equals(minImageProxyTimestamp)) {
+ throw new IllegalArgumentException();
+ }
+
+ if (minImageInfoTimestamp > minImageProxyTimestamp) {
+ for (int i = mPendingImages.size() - 1; i >= 0; i--) {
+ if (mPendingImages.keyAt(i) < minImageInfoTimestamp) {
+ ImageReferenceImpl imageReferenceImpl = mPendingImages.valueAt(i);
+ imageReferenceImpl.decrement();
+ mPendingImages.removeAt(i);
+ }
+ }
+ } else {
+ for (int i = mPendingImageInfos.size() - 1; i >= 0; i--) {
+ if (mPendingImageInfos.keyAt(i) < minImageProxyTimestamp) {
+ mPendingImageInfos.removeAt(i);
+ }
+ }
+ }
+
+ }
+ }
+
+ // Match incoming Image from the ImageReader with the corresponding ImageInfo.
+ private void matchImages() {
+ synchronized (mLock) {
+ // Iterate in reverse order so that ImageInfo can be removed in place
+ for (int i = mPendingImageInfos.size() - 1; i >= 0; i--) {
+ TotalCaptureResult captureResult = mPendingImageInfos.valueAt(i);
+ long timestamp = getTimeStampFromCaptureResult(captureResult);
+
+ ImageReferenceImpl imageReferenceImpl = mPendingImages.get(timestamp);
+
+ if (imageReferenceImpl != null) {
+ mPendingImages.remove(timestamp);
+ mPendingImageInfos.removeAt(i);
+ // Got a match. Add the ImageProxy to matched list and invoke
+ // onImageAvailableListener.
+ notifyImage(imageReferenceImpl, captureResult);
+ }
+ }
+
+ removeStaleData();
+ }
+ }
+
+ public interface ImageReferenceListener {
+ void onImageReferenceIncoming(@NonNull ImageReferenceImpl imageReferenceImpl,
+ @NonNull TotalCaptureResult totalCaptureResult, int captureStageId);
+ }
+
+} \ No newline at end of file
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
new file mode 100644
index 00000000..d8b99289
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import androidx.camera.extensions.impl.advanced.JpegEncoder;
+import androidx.camera.extensions.impl.advanced.BaseAdvancedExtenderImpl.BaseAdvancedSessionProcessor;
+
+import static androidx.camera.extensions.impl.advanced.JpegEncoder.JPEG_DEFAULT_QUALITY;
+import static androidx.camera.extensions.impl.advanced.JpegEncoder.JPEG_DEFAULT_ROTATION;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageWriter;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.io.Closeable;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@SuppressLint("UnknownNullness")
+public class HdrAdvancedExtenderImpl extends BaseAdvancedExtenderImpl {
+
+ public HdrAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ CameraCharacteristics cameraCharacteristics = characteristicsMap.get(cameraId);
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ boolean zoomRatioSupported =
+ CameraCharacteristicAvailability.supportsZoomRatio(cameraCharacteristics);
+ boolean hasFocuser =
+ CameraCharacteristicAvailability.hasFocuser(cameraCharacteristics);
+
+ // Requires API 23 for ImageWriter
+ return (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) &&
+ zoomRatioSupported && hasFocuser;
+ }
+
+ public class HDRAdvancedSessionProcessor extends BaseAdvancedSessionProcessor {
+ protected static final int UNDER_EXPOSED_CAPTURE_ID = 0;
+ protected static final int NORMAL_EXPOSED_CAPTURE_ID = 1;
+ protected static final int OVER_EXPOSED_CAPTURE_ID = 2;
+
+ List<Integer> mCaptureIdsList = List.of(UNDER_EXPOSED_CAPTURE_ID,
+ NORMAL_EXPOSED_CAPTURE_ID, OVER_EXPOSED_CAPTURE_ID);
+
+ public HDRAdvancedSessionProcessor() {
+ appendTag("::HDR");
+ }
+
+ @Override
+ protected void addCaptureRequestParameters(List<RequestProcessorImpl.Request> requestList) {
+ // Under exposed capture
+ RequestBuilder builderUnder = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, UNDER_EXPOSED_CAPTURE_ID);
+ // Turn off AE so that ISO sensitivity can be controlled
+ builderUnder.setParameters(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_OFF);
+ builderUnder.setParameters(CaptureRequest.SENSOR_EXPOSURE_TIME,
+ TimeUnit.MILLISECONDS.toNanos(8));
+ applyParameters(builderUnder);
+
+ // Normal exposed capture
+ RequestBuilder builderNormal = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, NORMAL_EXPOSED_CAPTURE_ID);
+ builderNormal.setParameters(CaptureRequest.SENSOR_EXPOSURE_TIME,
+ TimeUnit.MILLISECONDS.toNanos(16));
+ applyParameters(builderNormal);
+
+ // Over exposed capture
+ RequestBuilder builderOver = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, OVER_EXPOSED_CAPTURE_ID);
+ builderOver.setParameters(CaptureRequest.SENSOR_EXPOSURE_TIME,
+ TimeUnit.MILLISECONDS.toNanos(32));
+ applyParameters(builderOver);
+
+ requestList.add(builderUnder.build());
+ requestList.add(builderNormal.build());
+ requestList.add(builderOver.build());
+ }
+
+ @Override
+ public int startCapture(@NonNull CaptureCallback captureCallback) {
+ List<RequestProcessorImpl.Request> requestList = new ArrayList<>();
+ addCaptureRequestParameters(requestList);
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ boolean mCaptureStarted = false;
+
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request request,
+ long frameNumber, long timestamp) {
+ if (!mCaptureStarted) {
+ mCaptureStarted = true;
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request request,
+ CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request request,
+ TotalCaptureResult totalCaptureResult) {
+ RequestBuilder.RequestProcessorRequest requestProcessorRequest =
+ (RequestBuilder.RequestProcessorRequest) request;
+
+ mImageCaptureCaptureResultImageMatcher.setCameraCaptureCallback(
+ totalCaptureResult,
+ requestProcessorRequest.getCaptureStageId());
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request request,
+ CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ captureCallback.onCaptureProcessProgressed(100);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ Log.d(TAG, "startCapture");
+
+ mRequestProcessor.submit(requestList, callback);
+
+ if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+ mRequestProcessor.setImageProcessor(mCaptureOutputConfig.getId(),
+ new ImageProcessorImpl() {
+ boolean mCaptureStarted = false;
+ @Override
+ public void onNextImageAvailable(int outputStreamId,
+ long timestampNs,
+ @NonNull ImageReferenceImpl imgReferenceImpl,
+ @Nullable String physicalCameraId) {
+ mImageCaptureCaptureResultImageMatcher
+ .setInputImage(imgReferenceImpl);
+
+ if (!mCaptureStarted) {
+ mCaptureStarted = true;
+ captureCallback.onCaptureProcessStarted(seqId);
+ }
+ }
+ });
+
+ mImageCaptureCaptureResultImageMatcher.setImageReferenceListener(
+ new CaptureResultImageMatcher.ImageReferenceListener() {
+ @Override
+ public void onImageReferenceIncoming(
+ @NonNull ImageReferenceImpl imageReferenceImpl,
+ @NonNull TotalCaptureResult totalCaptureResult,
+ int captureId) {
+ processImageCapture(imageReferenceImpl, totalCaptureResult,
+ captureId, seqId, captureCallback);
+ }
+ });
+ }
+
+ return seqId;
+ }
+
+ private void processImageCapture(@NonNull ImageReferenceImpl imageReferenceImpl,
+ @NonNull TotalCaptureResult totalCaptureResult,
+ int captureId,
+ int seqId,
+ @NonNull CaptureCallback captureCallback) {
+
+ mCaptureResults.put(captureId, new Pair<>(imageReferenceImpl, totalCaptureResult));
+
+ if (mCaptureResults.keySet().containsAll(mCaptureIdsList)) {
+ List<Pair<ImageReferenceImpl, TotalCaptureResult>> imageDataPairs =
+ new ArrayList<>(mCaptureResults.values());
+
+ Image resultImage = null;
+ int captureSurfaceWriterImageFormat = ImageFormat.UNKNOWN;
+ synchronized (mLockCaptureSurfaceImageWriter) {
+ resultImage = mCaptureSurfaceImageWriter.dequeueInputImage();
+ captureSurfaceWriterImageFormat = mCaptureSurfaceImageWriter.getFormat();
+ }
+
+ if (captureSurfaceWriterImageFormat == ImageFormat.JPEG) {
+ Image yuvImage = imageDataPairs.get(NORMAL_EXPOSED_CAPTURE_ID).first.get();
+
+ Integer jpegOrientation = JPEG_DEFAULT_ROTATION;
+
+ synchronized (mLock) {
+ if (mParameters.get(CaptureRequest.JPEG_ORIENTATION) != null) {
+ jpegOrientation =
+ (Integer) mParameters.get(CaptureRequest.JPEG_ORIENTATION);
+ }
+ }
+
+ JpegEncoder.encodeToJpeg(yuvImage, resultImage, jpegOrientation,
+ JPEG_DEFAULT_QUALITY);
+
+ addCaptureResultKeys(seqId, imageDataPairs.get(UNDER_EXPOSED_CAPTURE_ID)
+ .second, captureCallback);
+ resultImage.setTimestamp(imageDataPairs.get(UNDER_EXPOSED_CAPTURE_ID)
+ .first.get().getTimestamp());
+
+ } else {
+ ByteBuffer yByteBuffer = resultImage.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = resultImage.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = resultImage.getPlanes()[1].getBuffer();
+
+ yByteBuffer.put(imageDataPairs.get(
+ NORMAL_EXPOSED_CAPTURE_ID).first.get().getPlanes()[0].getBuffer());
+ uByteBuffer.put(imageDataPairs.get(
+ NORMAL_EXPOSED_CAPTURE_ID).first.get().getPlanes()[2].getBuffer());
+ vByteBuffer.put(imageDataPairs.get(
+ NORMAL_EXPOSED_CAPTURE_ID).first.get().getPlanes()[1].getBuffer());
+
+ addCaptureResultKeys(seqId, imageDataPairs.get(UNDER_EXPOSED_CAPTURE_ID)
+ .second, captureCallback);
+ resultImage.setTimestamp(imageDataPairs.get(
+ UNDER_EXPOSED_CAPTURE_ID).first.get().getTimestamp());
+ }
+
+ synchronized (mLockCaptureSurfaceImageWriter) {
+ mCaptureSurfaceImageWriter.queueInputImage(resultImage);
+ }
+
+ for (Pair<ImageReferenceImpl, TotalCaptureResult> val : mCaptureResults.values()) {
+ val.first.decrement();
+ }
+
+ mCaptureResults.clear();
+ } else {
+ Log.w(TAG, "Unable to process, waiting for all images");
+ }
+ }
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return new HDRAdvancedSessionProcessor();
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ final CaptureRequest.Key [] CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_ZOOM_RATIO,
+ CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_REGIONS,
+ CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.JPEG_QUALITY,
+ CaptureRequest.JPEG_ORIENTATION};
+ return Arrays.asList(CAPTURE_REQUEST_SET);
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ final CaptureResult.Key [] CAPTURE_RESULT_SET = {CaptureResult.CONTROL_ZOOM_RATIO,
+ CaptureResult.CONTROL_AF_MODE, CaptureResult.CONTROL_AF_REGIONS,
+ CaptureResult.CONTROL_AF_TRIGGER, CaptureResult.CONTROL_AF_STATE,
+ CaptureResult.JPEG_QUALITY, CaptureResult.JPEG_ORIENTATION};
+ return Arrays.asList(CAPTURE_RESULT_SET);
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
new file mode 100644
index 00000000..037e9479
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+/**
+ * A interface to receive and process the upcoming next available Image.
+ *
+ * <p>Implemented by OEM.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageProcessorImpl {
+ /**
+ * The reference count will not be decremented when this method returns. Extensions must
+ * decrement it when the image is no longer needed.
+ *
+ * <p>If OEM is not closing(decrement) the image fast enough, the imageReference passed
+ * in this method might contain null image meaning that the Image was closed to prevent
+ * preview from stalling.
+ *
+ * @param outputConfigId the id of {@link Camera2OutputConfigImpl} which identifies
+ * corresponding Surface
+ * @param timestampNs the timestamp in nanoseconds associated with this image
+ * @param imageReference A reference to the {@link android.media.Image} which might contain
+ * null if OEM close(decrement) the image too slowly
+ * @param physicalCameraId used to distinguish which physical camera id the image comes from
+ * when the output configuration is
+ * MultiResolutionImageReaderOutputConfigImpl. It is also set if
+ * physicalCameraId is set in other Camera2OutputConfigImpl types.
+ *
+ */
+ void onNextImageAvailable(
+ int outputConfigId,
+ long timestampNs,
+ ImageReferenceImpl imageReference,
+ String physicalCameraId
+ );
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
new file mode 100644
index 00000000..ca4dcafa
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.util.Size;
+
+/**
+ * Surface will be created by constructing a ImageReader.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageReaderOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Returns the size of the surface.
+ */
+ Size getSize();
+
+ /**
+ * Gets the image format of the surface.
+ */
+ int getImageFormat();
+
+ /**
+ * Gets the capacity for TYPE_IMAGEREADER.
+ */
+ int getMaxImages();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
new file mode 100644
index 00000000..95f2c3b9
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.media.Image;
+
+/**
+ * A Image reference container that enables the Image sharing between Camera2/CameraX and OEM
+ * using reference counting. The wrapped Image will be closed once the reference count
+ * reaches 0.
+ *
+ * <p>Implemented by Camera2/CameraX.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageReferenceImpl {
+
+ /**
+ * Increment the reference count. Returns true if the value was incremented.
+ * (returns false if the reference count has already reached zero.)
+ */
+ boolean increment();
+
+ /**
+ * Decrement the reference count. Image will be closed if reference count reaches 0.
+ * Returns true if the value was decremented (returns false if the reference count has
+ * already reached zero)
+ */
+ boolean decrement();
+
+ /**
+ * Return the Android image. This object MUST not be closed directly.
+ * Returns null when the reference count is zero.
+ */
+ Image get();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/JpegEncoder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/JpegEncoder.java
new file mode 100644
index 00000000..f3eb7eab
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/JpegEncoder.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageWriter;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+
+// Jpeg compress input YUV and queue back in the client target surface.
+public class JpegEncoder {
+
+ public final static int JPEG_DEFAULT_QUALITY = 100;
+ public final static int JPEG_DEFAULT_ROTATION = 0;
+ public static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
+
+ /**
+ * Compresses a YCbCr image to jpeg, applying a crop and rotation.
+ * <p>
+ * The input is defined as a set of 3 planes of 8-bit samples, one plane for
+ * each channel of Y, Cb, Cr.<br>
+ * The Y plane is assumed to have the same width and height of the entire
+ * image.<br>
+ * The Cb and Cr planes are assumed to be downsampled by a factor of 2, to
+ * have dimensions (floor(width / 2), floor(height / 2)).<br>
+ * Each plane is specified by a direct java.nio.ByteBuffer, a pixel-stride,
+ * and a row-stride. So, the sample at coordinate (x, y) can be retrieved
+ * from byteBuffer[x * pixel_stride + y * row_stride].
+ * <p>
+ * The pre-compression transformation is applied as follows:
+ * <ol>
+ * <li>The image is cropped to the rectangle from (cropLeft, cropTop) to
+ * (cropRight - 1, cropBottom - 1). So, a cropping-rectangle of (0, 0) -
+ * (width, height) is a no-op.</li>
+ * <li>The rotation is applied counter-clockwise relative to the coordinate
+ * space of the image, so a CCW rotation will appear CW when the image is
+ * rendered in scanline order. Only rotations which are multiples of
+ * 90-degrees are suppored, so the parameter 'rot90' specifies which
+ * multiple of 90 to rotate the image.</li>
+ * </ol>
+ *
+ * @param width the width of the image to compress
+ * @param height the height of the image to compress
+ * @param yBuf the buffer containing the Y component of the image
+ * @param yPStride the stride between adjacent pixels in the same row in
+ * yBuf
+ * @param yRStride the stride between adjacent rows in yBuf
+ * @param cbBuf the buffer containing the Cb component of the image
+ * @param cbPStride the stride between adjacent pixels in the same row in
+ * cbBuf
+ * @param cbRStride the stride between adjacent rows in cbBuf
+ * @param crBuf the buffer containing the Cr component of the image
+ * @param crPStride the stride between adjacent pixels in the same row in
+ * crBuf
+ * @param crRStride the stride between adjacent rows in crBuf
+ * @param outBuf a direct java.nio.ByteBuffer to hold the compressed jpeg.
+ * This must have enough capacity to store the result, or an
+ * error code will be returned.
+ * @param outBufCapacity the capacity of outBuf
+ * @param quality the jpeg-quality (1-100) to use
+ * @param cropLeft left-edge of the bounds of the image to crop to before
+ * rotation
+ * @param cropTop top-edge of the bounds of the image to crop to before
+ * rotation
+ * @param cropRight right-edge of the bounds of the image to crop to before
+ * rotation
+ * @param cropBottom bottom-edge of the bounds of the image to crop to
+ * before rotation
+ * @param rot90 the multiple of 90 to rotate the image CCW (after cropping)
+ */
+ public static native int compressJpegFromYUV420pNative(
+ int width, int height,
+ ByteBuffer yBuf, int yPStride, int yRStride,
+ ByteBuffer cbBuf, int cbPStride, int cbRStride,
+ ByteBuffer crBuf, int crPStride, int crRStride,
+ ByteBuffer outBuf, int outBufCapacity,
+ int quality,
+ int cropLeft, int cropTop, int cropRight, int cropBottom,
+ int rot90);
+
+ public static void encodeToJpeg(Image yuvImage, Image jpegImage,
+ int jpegOrientation, int jpegQuality) {
+
+ jpegOrientation = (360 - (jpegOrientation % 360)) / 90;
+ ByteBuffer jpegBuffer = jpegImage.getPlanes()[0].getBuffer();
+
+ jpegBuffer.clear();
+
+ int jpegCapacity = jpegImage.getWidth();
+
+ Plane lumaPlane = yuvImage.getPlanes()[0];
+
+ Plane crPlane = yuvImage.getPlanes()[1];
+ Plane cbPlane = yuvImage.getPlanes()[2];
+
+ JpegEncoder.compressJpegFromYUV420pNative(
+ yuvImage.getWidth(), yuvImage.getHeight(),
+ lumaPlane.getBuffer(), lumaPlane.getPixelStride(), lumaPlane.getRowStride(),
+ crPlane.getBuffer(), crPlane.getPixelStride(), crPlane.getRowStride(),
+ cbPlane.getBuffer(), cbPlane.getPixelStride(), cbPlane.getRowStride(),
+ jpegBuffer, jpegCapacity, jpegQuality,
+ 0, 0, yuvImage.getWidth(), yuvImage.getHeight(),
+ jpegOrientation);
+ }
+
+ public static int imageFormatToPublic(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BLOB:
+ return ImageFormat.JPEG;
+ case ImageFormat.JPEG:
+ throw new IllegalArgumentException(
+ "ImageFormat.JPEG is an unknown internal format");
+ default:
+ return format;
+ }
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
new file mode 100644
index 00000000..c3ad61bc
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+/**
+ * Surface will be created by constructing a MultiResolutionImageReader.
+ */
+public interface MultiResolutionImageReaderOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Gets the image format of the surface.
+ */
+ int getImageFormat();
+
+ /**
+ * Gets the max images of the ImageReader.
+ */
+ int getMaxImages();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
new file mode 100644
index 00000000..82940635
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import androidx.camera.extensions.impl.advanced.BaseAdvancedExtenderImpl.BaseAdvancedSessionProcessor;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageWriter;
+import android.os.Build;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressLint("UnknownNullness")
+public class NightAdvancedExtenderImpl extends BaseAdvancedExtenderImpl {
+
+ protected static final int AWB_MODE_INCANDESCENT = CaptureRequest.CONTROL_AWB_MODE_INCANDESCENT;
+
+ public NightAdvancedExtenderImpl() {
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap) {
+ // Requires API 23 for ImageWriter
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return false;
+ }
+
+ CameraCharacteristics cameraCharacteristics = characteristicsMap.get(cameraId);
+
+ if (cameraCharacteristics == null) {
+ return false;
+ }
+
+ return CameraCharacteristicAvailability.isWBModeAvailable(cameraCharacteristics,
+ AWB_MODE_INCANDESCENT);
+ }
+
+ public class NightAdvancedSessionProcessor extends BaseAdvancedSessionProcessor {
+
+ public NightAdvancedSessionProcessor() {
+ appendTag("::Night");
+ }
+
+ protected final Object mLockPreviewSurfaceImageWriter = new Object();
+ @GuardedBy("mLockPreviewSurfaceImageWriter")
+ private ImageWriter mPreviewSurfaceImageWriter;
+
+ CaptureResultImageMatcher mCaptureResultImageMatcher =
+ new CaptureResultImageMatcher();
+
+ @Override
+ @NonNull
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceConfigurationImpl surfaceConfigs) {
+
+ Log.d(TAG, "initSession cameraId=" + cameraId);
+
+ mPreviewOutputSurfaceConfig = surfaceConfigs.getPreviewOutputSurface();
+ mCaptureOutputSurfaceConfig = surfaceConfigs.getImageCaptureOutputSurface();
+
+ Camera2SessionConfigImplBuilder builder =
+ new Camera2SessionConfigImplBuilder()
+ .setSessionTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+
+ // Preview
+ if (mPreviewOutputSurfaceConfig.getSurface() != null) {
+ Camera2OutputConfigImplBuilder previewOutputConfigBuilder;
+
+ previewOutputConfigBuilder =
+ Camera2OutputConfigImplBuilder.newImageReaderConfig(
+ mPreviewOutputSurfaceConfig.getSize(),
+ ImageFormat.YUV_420_888,
+ BASIC_CAPTURE_PROCESS_MAX_IMAGES);
+
+ mPreviewOutputConfig = previewOutputConfigBuilder.build();
+
+ builder.addOutputConfig(mPreviewOutputConfig);
+ }
+
+ // Image Capture
+ if (mCaptureOutputSurfaceConfig.getSurface() != null) {
+ Camera2OutputConfigImplBuilder captureOutputConfigBuilder;
+
+ captureOutputConfigBuilder =
+ Camera2OutputConfigImplBuilder.newImageReaderConfig(
+ mCaptureOutputSurfaceConfig.getSize(),
+ ImageFormat.YUV_420_888,
+ BASIC_CAPTURE_PROCESS_MAX_IMAGES);
+
+ mCaptureOutputConfig = captureOutputConfigBuilder.build();
+
+ builder.addOutputConfig(mCaptureOutputConfig);
+ }
+
+ addSessionParameter(builder);
+
+ return builder.build();
+ }
+
+ @Override
+ protected void addSessionParameter(Camera2SessionConfigImplBuilder builder) {
+ builder.addSessionParameter(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_INCANDESCENT);
+ }
+
+ @Override
+ public void deInitSession() {
+ super.deInitSession();
+
+ synchronized (mLockPreviewSurfaceImageWriter) {
+ if (mPreviewSurfaceImageWriter != null) {
+ mPreviewSurfaceImageWriter.close();
+ mPreviewSurfaceImageWriter = null;
+ }
+ }
+ }
+
+ @Override
+ public void onCaptureSessionStart(@NonNull RequestProcessorImpl requestProcessor) {
+ super.onCaptureSessionStart(requestProcessor);
+
+ if (mPreviewOutputSurfaceConfig.getSurface() != null) {
+ synchronized (mLockPreviewSurfaceImageWriter) {
+ mPreviewSurfaceImageWriter = new ImageWriter
+ .Builder(mPreviewOutputSurfaceConfig.getSurface())
+ .setMaxImages(MAX_NUM_IMAGES)
+ .build();
+ }
+ }
+
+ if (mPreviewOutputSurfaceConfig.getSurface() != null) {
+ requestProcessor.setImageProcessor(mPreviewOutputConfig.getId(),
+ new ImageProcessorImpl() {
+ @Override
+ public void onNextImageAvailable(int outputStreamId, long timestampNs,
+ @NonNull ImageReferenceImpl imageReferenceImpl,
+ @Nullable String physicalCameraId) {
+ mCaptureResultImageMatcher.setInputImage(imageReferenceImpl);
+ }
+ });
+
+ mCaptureResultImageMatcher.setImageReferenceListener(
+ new CaptureResultImageMatcher.ImageReferenceListener() {
+ @Override
+ public void onImageReferenceIncoming(
+ @NonNull ImageReferenceImpl imageReferenceImpl,
+ @NonNull TotalCaptureResult totalCaptureResult,
+ int captureId) {
+ processCapture(imageReferenceImpl);
+ }
+ });
+ }
+ }
+
+ private void processCapture(@NonNull ImageReferenceImpl imageReferenceImpl) {
+ synchronized (mLockPreviewSurfaceImageWriter) {
+ mPreviewSurfaceImageWriter.queueInputImage(imageReferenceImpl.get());
+ }
+
+ imageReferenceImpl.decrement();
+ }
+
+ @Override
+ public void onCaptureSessionEnd() {
+ super.onCaptureSessionEnd();
+
+ synchronized (this) {
+ mCaptureResultImageMatcher.clear();
+ }
+ }
+
+ @Override
+ public int startRepeating(@NonNull CaptureCallback captureCallback) {
+ RequestBuilder builder = new RequestBuilder(mPreviewOutputConfig.getId(),
+ CameraDevice.TEMPLATE_PREVIEW, 0);
+ applyParameters(builder);
+ final int seqId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestProcessorImpl.Callback callback = new RequestProcessorImpl.Callback() {
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request request, long frameNumber,
+ long timestamp) {
+ captureCallback.onCaptureStarted(seqId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request request,
+ CaptureResult partialResult) {
+
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request request,
+ TotalCaptureResult totalCaptureResult) {
+
+ addCaptureResultKeys(seqId, totalCaptureResult, captureCallback);
+
+ mCaptureResultImageMatcher.setCameraCaptureCallback(
+ totalCaptureResult);
+
+ captureCallback.onCaptureProcessStarted(seqId);
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request request,
+ CaptureFailure captureFailure) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request request,
+ long frameNumber, int outputStreamId) {
+ captureCallback.onCaptureFailed(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ captureCallback.onCaptureSequenceCompleted(seqId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ captureCallback.onCaptureSequenceAborted(seqId);
+ }
+ };
+
+ mRequestProcessor.setRepeating(builder.build(), callback);
+
+ return seqId;
+ }
+
+ @Override
+ protected void addCaptureRequestParameters(List<RequestProcessorImpl.Request> requestList) {
+ RequestBuilder build = new RequestBuilder(mCaptureOutputConfig.getId(),
+ CameraDevice.TEMPLATE_STILL_CAPTURE, DEFAULT_CAPTURE_ID);
+ build.setParameters(CaptureRequest.CONTROL_AWB_MODE, AWB_MODE_INCANDESCENT);
+ applyParameters(build);
+
+ requestList.add(build.build());
+ }
+ }
+
+ @Override
+ public SessionProcessorImpl createSessionProcessor() {
+ return new NightAdvancedSessionProcessor();
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java
new file mode 100644
index 00000000..ca3832e3
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+/**
+ * For specifying the output surface configurations for the extension.
+ *
+ * since 1.4
+ */
+@SuppressLint("UnknownNullness")
+public interface OutputSurfaceConfigurationImpl {
+ public OutputSurfaceImpl getPreviewOutputSurface();
+
+ public OutputSurfaceImpl getImageCaptureOutputSurface();
+
+ public OutputSurfaceImpl getImageAnalysisOutputSurface();
+
+ public OutputSurfaceImpl getPostviewOutputSurface();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
new file mode 100644
index 00000000..f6920296
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.util.Size;
+import android.view.Surface;
+
+/**
+ * For specifying output surface of the extension.
+ */
+@SuppressLint("UnknownNullness")
+public interface OutputSurfaceImpl {
+ /**
+ * Gets the surface.
+ */
+ Surface getSurface();
+
+ /**
+ * Gets the size.
+ */
+ Size getSize();
+
+ /**
+ * Gets the image format.
+ */
+ int getImageFormat();
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java
new file mode 100644
index 00000000..ccb4ec84
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestBuilder.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RequestBuilder {
+ List<Integer> mTargetOutputConfigIds = new ArrayList<>();
+ Map<CaptureRequest.Key<?>, Object> mParameters = new HashMap<>();
+ int mTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ int mCaptureStageId;
+
+ public RequestBuilder() {
+ }
+
+ public RequestBuilder(int targetOutputConfigId, int templateId, int captureStageId) {
+ addTargetOutputConfigIds(targetOutputConfigId);
+ setTemplateId(templateId);
+ setCaptureStageId(captureStageId);
+ }
+
+ @NonNull
+ public RequestBuilder addTargetOutputConfigIds(int targetOutputConfigId) {
+ mTargetOutputConfigIds.add(targetOutputConfigId);
+ return this;
+ }
+
+ @NonNull
+ public RequestBuilder setParameters(@NonNull CaptureRequest.Key<?> key,
+ @NonNull Object value) {
+ mParameters.put(key, value);
+ return this;
+ }
+
+ @NonNull
+ public RequestBuilder setTemplateId(int templateId) {
+ mTemplateId = templateId;
+ return this;
+ }
+
+ @NonNull
+ public RequestBuilder setCaptureStageId(int captureStageId) {
+ mCaptureStageId = captureStageId;
+ return this;
+ }
+
+ @NonNull
+ public RequestProcessorImpl.Request build() {
+ return new RequestProcessorRequest(
+ mTargetOutputConfigIds, mParameters, mTemplateId, mCaptureStageId);
+ }
+
+ static class RequestProcessorRequest implements RequestProcessorImpl.Request {
+ final List<Integer> mTargetOutputConfigIds;
+ final Map<CaptureRequest.Key<?>, Object> mParameters;
+ final int mTemplateId;
+ final int mCaptureStageId;
+
+ RequestProcessorRequest(List<Integer> targetOutputConfigIds,
+ Map<CaptureRequest.Key<?>, Object> parameters,
+ int templateId,
+ int captureStageId) {
+ mTargetOutputConfigIds = targetOutputConfigIds;
+ mParameters = parameters;
+ mTemplateId = templateId;
+ mCaptureStageId = captureStageId;
+ }
+
+ @Override
+ public List<Integer> getTargetOutputConfigIds() {
+ return mTargetOutputConfigIds;
+ }
+
+ @Override
+ public Map<CaptureRequest.Key<?>, Object> getParameters() {
+ return mParameters;
+ }
+
+ @Override
+ public Integer getTemplateId() {
+ return mTemplateId;
+ }
+
+ public int getCaptureStageId() {
+ return mCaptureStageId;
+ }
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
new file mode 100644
index 00000000..51853334
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An Interface to execute Camera2 capture requests.
+ */
+@SuppressLint("UnknownNullness")
+public interface RequestProcessorImpl {
+ /**
+ * Sets a {@link ImageProcessorImpl} to receive {@link ImageReferenceImpl} to process.
+ */
+ void setImageProcessor(int outputconfigId, ImageProcessorImpl imageProcessor);
+
+ /**
+ * Submits a request.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int submit(Request request, Callback callback);
+
+ /**
+ * Submits a list of requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int submit(List<Request> requests, Callback callback);
+
+ /**
+ * Set repeating requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int setRepeating(Request request, Callback callback);
+
+
+ /**
+ * Abort captures.
+ */
+ void abortCaptures();
+
+ /**
+ * Stop Repeating.
+ */
+ void stopRepeating();
+
+ /**
+ * A interface representing a capture request configuration used for submitting requests in
+ * {@link RequestProcessorImpl}.
+ */
+ interface Request {
+ /**
+ * Gets the target ids of {@link Camera2OutputConfigImpl} which identifies corresponding
+ * Surface to be the targeted for the request.
+ */
+ List<Integer> getTargetOutputConfigIds();
+
+ /**
+ * Gets all the parameters.
+ */
+ Map<CaptureRequest.Key<?>, Object> getParameters();
+
+ /**
+ * Gets the template id.
+ */
+ Integer getTemplateId();
+ }
+
+ /**
+ * Callback to be invoked during the capture.
+ */
+ interface Callback {
+ void onCaptureStarted(
+ Request request,
+ long frameNumber,
+ long timestamp);
+
+ void onCaptureProgressed(
+ Request request,
+ CaptureResult partialResult);
+
+ void onCaptureCompleted(
+ Request request,
+ TotalCaptureResult totalCaptureResult);
+
+ void onCaptureFailed(
+ Request request,
+ CaptureFailure captureFailure);
+
+ void onCaptureBufferLost(
+ Request request,
+ long frameNumber,
+ int outputStreamId);
+
+ void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+
+ void onCaptureSequenceAborted(int sequenceId);
+
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
new file mode 100644
index 00000000..8dbfadc2
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.view.Surface;
+
+import java.util.Map;
+
+/**
+ * Interface for creating Camera2 CameraCaptureSessions with extension enabled based on
+ * advanced vendor implementation.
+ *
+ * <p><pre>
+ * The flow of a extension session is shown below:
+ * (1) {@link #initSession}: CameraX prepares streams configuration for creating
+ * CameraCaptureSession. Output surfaces for Preview, ImageCapture and ImageAnalysis are passed
+ * in and vendor is responsible for outputting the results to these surfaces.
+ *
+ * (2) {@link #onCaptureSessionStart}: It is called after CameraCaptureSession is configured.
+ * A {@link RequestProcessorImpl} is passed for vendor to send repeating requests and
+ * single requests.
+ *
+ * (3) {@link #startRepeating}: CameraX will call this method to start the repeating request
+ * after CameraCaptureSession is called. Vendor should start the repeating request by
+ * {@link RequestProcessorImpl}. Vendor can also update the repeating request if needed later.
+ *
+ * (4) {@link #setParameters(Map)}: The passed parameters will be attached to the repeating request
+ * and single requests but vendor can choose to apply some of them only.
+ *
+ * (5) {@link #startCapture(CaptureCallback)}: It is called when apps want to
+ * start a multi-frame image capture. {@link CaptureCallback} will be called
+ * to report the status and the output image will be written to the capture output surface
+ * specified in {@link #initSession}.
+ *
+ * (5) {@link #onCaptureSessionEnd}: It is called right BEFORE CameraCaptureSession.close() is
+ * called.
+ *
+ * (6) {@link #deInitSession}: called when CameraCaptureSession is closed.
+ * </pre>
+ */
+@SuppressLint("UnknownNullness")
+public interface SessionProcessorImpl {
+ /**
+ * Initializes the session for the extension. This is where the OEMs allocate resources for
+ * preparing a CameraCaptureSession. After initSession() is called, the camera ID,
+ * cameraCharacteristics and context will not change until deInitSession() has been called.
+ *
+ * <p>CameraX / Camera2 specifies the output surface configurations for preview using
+ * {@link OutputSurfaceConfigurationImpl#getPreviewOutputSurface}, image capture using
+ * {@link OutputSurfaceConfigurationImpl#getImageCaptureOutputSurface}, and image analysis
+ * [optional] using {@link OutputSurfaceConfigurationImpl#getImageAnalysisOutputSurface}.
+ * And OEM returns a {@link Camera2SessionConfigImpl} which consists of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters. The {@link Camera2SessionConfigImpl}
+ * will be used to configure the CameraCaptureSession.
+ *
+ * <p>OEM is responsible for outputting correct camera images output to these output surfaces.
+ * OEM can have the following options to enable the output:
+ * <pre>
+ * (1) Add these output surfaces in CameraCaptureSession directly using
+ * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in
+ * HAL.
+ *
+ * (2) Use surface sharing with other surface by calling
+ * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)}
+ * to add the output surface to the other {@link Camera2OutputConfigImpl}.
+ *
+ * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output
+ * surface. The output surface won't be contained in the returned
+ * {@link Camera2SessionConfigImpl}.
+ * </pre>
+ *
+ * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder}
+ * implementations are provided in the stub for OEM to construct the
+ * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances.
+ *
+ * @param surfaceConfigs contains output surfaces for preview, image capture, and an
+ * optional output config for image analysis (YUV_420_888).
+ * @return a {@link Camera2SessionConfigImpl} consisting of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters which will decide the
+ * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the
+ * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any
+ * supported or mandatory stream combination BUT OEM must ensure this list will always
+ * produce a valid camera capture session.
+ *
+ * @since 1.4
+ */
+ Camera2SessionConfigImpl initSession(
+ String cameraId,
+ Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ Context context,
+ OutputSurfaceConfigurationImpl surfaceConfigs);
+
+ /**
+ * Initializes the session for the extension. This is where the OEMs allocate resources for
+ * preparing a CameraCaptureSession. After initSession() is called, the camera ID,
+ * cameraCharacteristics and context will not change until deInitSession() has been called.
+ *
+ * <p>CameraX / Camera2 specifies the output surface configurations for preview, image capture
+ * and image analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which
+ * consists of a list of {@link Camera2OutputConfigImpl} and session parameters. The
+ * {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession.
+ *
+ * <p>OEM is responsible for outputting correct camera images output to these output surfaces.
+ * OEM can have the following options to enable the output:
+ * <pre>
+ * (1) Add these output surfaces in CameraCaptureSession directly using
+ * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in
+ * HAL.
+ *
+ * (2) Use surface sharing with other surface by calling
+ * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)}
+ * to add the output surface to the other {@link Camera2OutputConfigImpl}.
+ *
+ * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output
+ * surface. The output surface won't be contained in the returned
+ * {@link Camera2SessionConfigImpl}.
+ * </pre>
+ *
+ * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder}
+ * implementations are provided in the stub for OEM to construct the
+ * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances.
+ *
+ * @param previewSurfaceConfig output surface for preview
+ * @param imageCaptureSurfaceConfig output surface for image capture.
+ * @param imageAnalysisSurfaceConfig an optional output config for image analysis
+ * (YUV_420_888).
+ * @return a {@link Camera2SessionConfigImpl} consisting of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters which will decide the
+ * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the
+ * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any
+ * supported or mandatory stream combination BUT OEM must ensure this list will always
+ * produce a valid camera capture session.
+ */
+ Camera2SessionConfigImpl initSession(
+ String cameraId,
+ Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ Context context,
+ OutputSurfaceImpl previewSurfaceConfig,
+ OutputSurfaceImpl imageCaptureSurfaceConfig,
+ OutputSurfaceImpl imageAnalysisSurfaceConfig);
+
+ /**
+ * Notify to de-initialize the extension. This callback will be invoked after
+ * CameraCaptureSession is closed. After onDeInit() was called, it is expected that the
+ * camera ID, cameraCharacteristics will no longer hold and tear down any resources allocated
+ * for this extension. Aborts all pending captures.
+ */
+ void deInitSession();
+
+ /**
+ * CameraX / Camera2 would call these API’s to pass parameters from the app to the OEM. It’s
+ * expected that the OEM would (eventually) update the repeating request if the keys are
+ * supported. Setting a value to null explicitly un-sets the value.
+ */
+ void setParameters(Map<CaptureRequest.Key<?>, Object> parameters);
+
+ /**
+ * CameraX / Camera2 will call this interface in response to client requests involving
+ * the output preview surface. Typical examples include requests that include AF/AE triggers.
+ * Extensions can disregard any capture request keys that were not advertised in
+ * {@link AdvancedExtenderImpl#getAvailableCaptureRequestKeys}.
+ *
+ * @param triggers Capture request key value map.
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ *
+ * @throws IllegalArgumentException If there are no valid settings that can be applied
+ *
+ * @since 1.3
+ */
+ int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback);
+
+ /**
+ * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession}
+ * has been created. {@link RequestProcessorImpl} is passed for OEM to submit single
+ * requests or set repeating requests. This ExtensionRequestProcessor will be valid to use
+ * until onCaptureSessionEnd is called.
+ */
+ void onCaptureSessionStart(RequestProcessorImpl requestProcessor);
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * closed. {@link RequestProcessorImpl} passed in onCaptureSessionStart will no longer
+ * accept any requests after onCaptureSessionEnd() returns.
+ */
+ void onCaptureSessionEnd();
+
+ /**
+ * Starts the repeating request after CameraCaptureSession is called. Vendor should start the
+ * repeating request by {@link RequestProcessorImpl}. Vendor can also update the
+ * repeating request when needed later.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ */
+ int startRepeating(CaptureCallback callback);
+
+ /**
+ * Stop the repeating request. To prevent OEM from not calling stopRepeating, CameraX will
+ * first stop the repeating request of current CameraCaptureSession and call this API to signal
+ * OEM that the repeating request was stopped and going forward calling
+ * {@link RequestProcessorImpl#setRepeating} will simply do nothing.
+ */
+ void stopRepeating();
+
+ /**
+ * Start a multi-frame capture with a postview. {@link #startCapture(CaptureCallback)}
+ * will be used for captures without a postview request.
+ *
+ * Postview will be available before the capture. Upon postview completion,
+ * {@code OnImageAvailableListener#onImageAvailable} will be called on the ImageReader
+ * that creates the postview output surface. When the capture is completed,
+ * {@link CaptureCallback#onCaptureSequenceCompleted} is called and
+ * {@code OnImageAvailableListener#onImageAvailable} will also be called on the ImageReader
+ * that creates the image capture output surface.
+ *
+ * <p>Only one capture can perform at a time. Starting a capture when another capture is
+ * running will cause onCaptureFailed to be called immediately.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ * @since 1.4
+ */
+ int startCaptureWithPostview(CaptureCallback callback);
+
+ /**
+ * Start a multi-frame capture.
+ *
+ * When the capture is completed, {@link CaptureCallback#onCaptureSequenceCompleted}
+ * is called and {@code OnImageAvailableListener#onImageAvailable}
+ * will also be called on the ImageReader that creates the image capture output surface.
+ *
+ * <p>Only one capture can perform at a time. Starting a capture when another capture is running
+ * will cause onCaptureFailed to be called immediately.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ */
+ int startCapture(CaptureCallback callback);
+
+ /**
+ * Abort all capture tasks.
+ */
+ void abortCapture(int captureSequenceId);
+
+ /**
+ * Returns the dynamically calculated capture latency pair in milliseconds.
+ *
+ * <p>In contrast to {@link AdvancedExtenderImpl#getEstimatedCaptureLatencyRange} this method is
+ * guaranteed to be called after {@link #onCaptureSessionStart}.
+ * The measurement is expected to take in to account dynamic parameters such as the current
+ * scene, the state of 3A algorithms, the state of internal HW modules and return a more
+ * accurate assessment of the still capture latency.</p>
+ *
+ * @return pair that includes the estimated input frame/frames camera capture latency as the
+ * first field. This is the time between {@link #onCaptureStarted} and
+ * {@link #onCaptureProcessStarted}. The second field value includes the estimated
+ * post-processing latency. This is the time between {@link #onCaptureProcessStarted} until
+ * the processed frame returns back to the client registered surface.
+ * Both first and second values will be in milliseconds. The total still capture latency will be
+ * the sum of both the first and second values of the pair.
+ * The pair is expected to be null if the dynamic latency estimation is not supported.
+ * If clients have not configured a still capture output, then this method can also return a
+ * null pair.
+ * @since 1.4
+ */
+ Pair<Long, Long> getRealtimeCaptureLatency();
+
+ /**
+ * Callback for notifying the status of {@link #startCapture(CaptureCallback)} and
+ * {@link #startRepeating(CaptureCallback)}.
+ */
+ interface CaptureCallback {
+ /**
+ * This method is called when the camera device has started capturing the initial input
+ * image.
+ *
+ * For a multi-frame capture, the method is called when the
+ * CameraCaptureSession.CaptureCallback onCaptureStarted of first frame is called and its
+ * timestamp is directly forwarded to timestamp parameter of
+ * this method.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ * @param timestamp the timestamp at start of capture for repeating
+ * request or the timestamp at start of capture of the
+ * first frame in a multi-frame capture, in nanoseconds.
+ */
+ void onCaptureStarted(int captureSequenceId, long timestamp);
+
+ /**
+ * This method is called when an image (or images in case of multi-frame
+ * capture) is captured and device-specific extension processing is triggered.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureProcessStarted(int captureSequenceId);
+
+ /**
+ * This method is called instead of
+ * {@link #onCaptureProcessStarted} when the camera device failed
+ * to produce the required input for the device-specific extension. The
+ * cause could be a failed camera capture request, a failed
+ * capture result or dropped camera frame.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureFailed(int captureSequenceId);
+
+ /**
+ * This method is called independently of the others in the CaptureCallback, when a capture
+ * sequence finishes.
+ *
+ * <p>In total, there will be at least one
+ * {@link #onCaptureProcessStarted}/{@link #onCaptureFailed}
+ * invocation before this callback is triggered. If the capture
+ * sequence is aborted before any requests have begun processing,
+ * {@link #onCaptureSequenceAborted} is invoked instead.</p>
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceCompleted(int captureSequenceId);
+
+ /**
+ * This method is called when a capture sequence aborts.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceAborted(int captureSequenceId);
+
+ /**
+ * Capture result callback that needs to be called when the process capture results are
+ * ready as part of frame post-processing.
+ *
+ * This callback will fire after {@link #onCaptureStarted}, {@link #onCaptureProcessStarted}
+ * and before {@link #onCaptureSequenceCompleted}. The callback is not expected to fire
+ * in case of capture failure {@link #onCaptureFailed} or capture abort
+ * {@link #onCaptureSequenceAborted}.
+ *
+ * @param timestamp The timestamp at start of capture. The same timestamp value
+ * passed to {@link #onCaptureStarted}.
+ * @param captureSequenceId the capture id of the request that generated the capture
+ * results. This is the return value of either
+ * {@link #startRepeating} or {@link #startCapture}.
+ * @param result Map containing the supported capture results. Do note
+ * that if results 'android.jpeg.quality' and
+ * 'android.jpeg.orientation' are present in the process
+ * capture input results, then the values must also be passed
+ * as part of this callback. Both Camera2 and CameraX guarantee
+ * that those two settings and results are always supported and
+ * applied by the corresponding framework.
+ */
+ void onCaptureCompleted(long timestamp, int captureSequenceId,
+ Map<CaptureResult.Key, Object> result);
+
+ /**
+ * Capture progress callback that needs to be called when the process capture is
+ * ongoing and includes the estimated progress of the processing.
+ *
+ * <p>Extensions must ensure that they always call this callback with monotonically
+ * increasing values.</p>
+ *
+ * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the
+ * callback is expected to be called once when processing is done with value 100.</p>
+ *
+ * @param progress Value between 0 and 100.
+ * @since 1.4
+ */
+ void onCaptureProcessProgressed(int progress);
+ }
+}
diff --git a/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
new file mode 100644
index 00000000..7b8d83c1
--- /dev/null
+++ b/camera2/extensions/advancedSample/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.view.Surface;
+
+/**
+ * Use Surface directly to create the OutputConfiguration.
+ */
+@SuppressLint("UnknownNullness")
+public interface SurfaceOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Get the {@link Surface}. It'll return valid surface only when type is TYPE_SURFACE.
+ */
+ Surface getSurface();
+}
diff --git a/camera2/extensions/jni/Android.bp b/camera2/extensions/jni/Android.bp
new file mode 100644
index 00000000..b30253e8
--- /dev/null
+++ b/camera2/extensions/jni/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_shared {
+ name: "libencoderjpeg_jni",
+ srcs: [
+ "JpegEncoder.cpp"
+ ],
+ include_dirs: ["external/libjpeg-turbo"],
+
+ header_libs: [
+ "jni_headers",
+ ],
+
+ shared_libs: [
+ "libnativehelper",
+ "liblog",
+ "libjpeg",
+ ],
+ static_libs: [
+ "android.hardware.camera.device@3.2",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+
+ system_ext_specific: true,
+}
diff --git a/camera2/extensions/jni/JpegEncoder.cpp b/camera2/extensions/jni/JpegEncoder.cpp
new file mode 100644
index 00000000..dac6d00f
--- /dev/null
+++ b/camera2/extensions/jni/JpegEncoder.cpp
@@ -0,0 +1,647 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <cstring>
+#include <cstdio>
+#include <inttypes.h>
+#include <memory.h>
+#include <vector>
+#include <iostream>
+#include <utils/Log.h>
+#include <setjmp.h>
+
+#include <android/hardware/camera/device/3.2/types.h>
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+using namespace std;
+using namespace android;
+
+using android::hardware::camera::device::V3_2::CameraBlob;
+using android::hardware::camera::device::V3_2::CameraBlobId;
+
+class Transform;
+struct Plane;
+
+inline int sgn(int val) { return (0 < val) - (val < 0); }
+
+inline int min(int a, int b) { return a < b ? a : b; }
+
+inline int max(int a, int b) { return a > b ? a : b; }
+
+/**
+ * Represents a combined cropping and rotation transformation.
+ *
+ * The transformation maps the coordinates (mOrigX, mOrigY) and (mOneX, mOneY)
+ * in the input image to the origin and (mOutputWidth, mOutputHeight)
+ * respectively.
+ */
+class Transform {
+ public:
+ Transform(int origX, int origY, int oneX, int oneY);
+
+ static Transform forCropFollowedByRotation(int cropLeft, int cropTop,
+ int cropRight, int cropBottom, int rot90);
+
+ inline int getOutputWidth() const { return mOutputWidth; }
+
+ inline int getOutputHeight() const { return mOutputHeight; }
+
+ bool operator==(const Transform& other) const;
+
+ /**
+ * Transforms the input coordinates. Coordinates outside the cropped region
+ * are clamped to valid values.
+ */
+ void map(int x, int y, int* outX, int* outY) const;
+
+ private:
+ int mOutputWidth;
+ int mOutputHeight;
+
+ // The coordinates of the point to map the origin to.
+ const int mOrigX, mOrigY;
+ // The coordinates of the point to map the point (getOutputWidth(),
+ // getOutputHeight()) to.
+ const int mOneX, mOneY;
+
+ // A matrix for the rotational component.
+ int mMat00, mMat01;
+ int mMat10, mMat11;
+};
+
+/**
+ * Represents a model for accessing pixel data for a single plane of an image.
+ * Note that the actual data is not owned by this class, and the underlying
+ * data does not need to be stored in separate planes.
+ */
+struct Plane {
+ // The dimensions of this plane of the image
+ int width;
+ int height;
+
+ // A pointer to raw pixel data
+ const unsigned char* data;
+ // The difference in address between consecutive pixels in the same row
+ int pixelStride;
+ // The difference in address between the start of consecutive rows
+ int rowStride;
+};
+
+/**
+ * Provides an interface for simultaneously reading a certain number of rows of
+ * an image plane as contiguous arrays, suitable for use with libjpeg.
+ */
+template <unsigned int ROWS>
+class RowIterator {
+ public:
+ /**
+ * Creates a new RowIterator which will crop and rotate with the given
+ * transform.
+ *
+ * @param plane the plane to iterate over
+ * @param transform the transformation to map output values into the
+ * coordinate space of the plane
+ * @param rowLength the length of the rows returned via LoadAt(). If this is
+ * longer than the width of the output (after applying the transform), then
+ * the right-most value is repeated.
+ */
+ inline RowIterator(Plane plane, Transform transform, int rowLength);
+
+ /**
+ * Returns an array of pointers into consecutive rows of contiguous image
+ * data starting at y. That is, samples within each row are contiguous.
+ * However, the individual arrays pointed-to may be separate.
+ * When the end of the image is reached, the last row of the image is
+ * repeated.
+ * The returned pointers are valid until the next call to loadAt().
+ */
+ inline const std::array<unsigned char*, ROWS> loadAt(int baseY);
+
+ private:
+ Plane mPlane;
+ Transform mTransform;
+ // The length of a row, with padding to the next multiple of 64.
+ int mPaddedRowLength;
+ std::vector<unsigned char> mBuffer;
+};
+
+template <unsigned int ROWS>
+RowIterator<ROWS>::RowIterator(Plane plane, Transform transform,
+ int rowLength)
+ : mPlane(plane), mTransform(transform) {
+ mPaddedRowLength = rowLength;
+ mBuffer = std::vector<unsigned char>(rowLength * ROWS);
+}
+
+template <unsigned int ROWS>
+const std::array<unsigned char*, ROWS> RowIterator<ROWS>::loadAt(int baseY) {
+ std::array<unsigned char*, ROWS> bufPtrs;
+ for (unsigned int i = 0; i < ROWS; i++) {
+ bufPtrs[i] = &mBuffer[mPaddedRowLength * i];
+ }
+
+ if (mPlane.width == 0 || mPlane.height == 0) {
+ return bufPtrs;
+ }
+
+ for (unsigned int i = 0; i < ROWS; i++) {
+ int y = i + baseY;
+ y = min(y, mTransform.getOutputHeight() - 1);
+
+ int output_width = mPaddedRowLength;
+ output_width = min(output_width, mTransform.getOutputWidth());
+ output_width = min(output_width, mPlane.width);
+
+ // Each row in the output image will be copied into buf_ by gathering pixels
+ // along an axis-aligned line in the plane.
+ // The line is defined by (startX, startY) -> (endX, endY), computed via the
+ // current Transform.
+ int startX;
+ int startY;
+ mTransform.map(0, y, &startX, &startY);
+
+ int endX;
+ int endY;
+ mTransform.map(output_width - 1, y, &endX, &endY);
+
+ // Clamp (startX, startY) and (endX, endY) to the valid bounds of the plane.
+ startX = min(startX, mPlane.width - 1);
+ startY = min(startY, mPlane.height - 1);
+ endX = min(endX, mPlane.width - 1);
+ endY = min(endY, mPlane.height - 1);
+ startX = max(startX, 0);
+ startY = max(startY, 0);
+ endX = max(endX, 0);
+ endY = max(endY, 0);
+
+ // To reduce work inside the copy-loop, precompute the start, end, and
+ // stride relating the values to be gathered from mPlane into buf
+ // for this particular scan-line.
+ int dx = sgn(endX - startX);
+ int dy = sgn(endY - startY);
+ if (!(dx == 0 || dy == 0)) {
+ ALOGE("%s: Unexpected bounds: %dx%d %dx%d!", __FUNCTION__, startX, endX, startY, endY);
+ return bufPtrs;
+ }
+
+ // The index into mPlane.data of (startX, startY)
+ int plane_start = startX * mPlane.pixelStride + startY * mPlane.rowStride;
+ // The index into mPlane.data of (endX, endY)
+ int plane_end = endX * mPlane.pixelStride + endY * mPlane.rowStride;
+ // The stride, in terms of indices in plane_data, required to enumerate the
+ // samples between the start and end points.
+ int stride = dx * mPlane.pixelStride + dy * mPlane.rowStride;
+ // In the degenerate-case of a 1x1 plane, startX and endX are equal, so
+ // stride would be 0, resulting in an infinite-loop. To avoid this case,
+ // use a stride of at-least 1.
+ if (stride == 0) {
+ stride = 1;
+ }
+
+ int outX = 0;
+ for (int idx = plane_start; idx >= min(plane_start, plane_end) &&
+ idx <= max(plane_start, plane_end); idx += stride) {
+ bufPtrs[i][outX] = mPlane.data[idx];
+ outX++;
+ }
+
+ // Fill the remaining right-edge of the buffer by extending the last
+ // value.
+ unsigned char right_padding_value = bufPtrs[i][outX - 1];
+ for (; outX < mPaddedRowLength; outX++) {
+ bufPtrs[i][outX] = right_padding_value;
+ }
+ }
+
+ return bufPtrs;
+}
+
+template <typename T>
+void safeDelete(T& t) {
+ delete t;
+ t = nullptr;
+}
+
+template <typename T>
+void safeDeleteArray(T& t) {
+ delete[] t;
+ t = nullptr;
+}
+
+Transform::Transform(int origX, int origY, int oneX, int oneY)
+ : mOrigX(origX), mOrigY(origY), mOneX(oneX), mOneY(oneY) {
+ if (origX == oneX || origY == oneY) {
+ // Handle the degenerate case of cropping to a 0x0 rectangle.
+ mMat00 = 0;
+ mMat01 = 0;
+ mMat10 = 0;
+ mMat11 = 0;
+ return;
+ }
+
+ if (oneX > origX && oneY > origY) {
+ // 0-degree rotation
+ mMat00 = 1;
+ mMat01 = 0;
+ mMat10 = 0;
+ mMat11 = 1;
+ mOutputWidth = abs(oneX - origX);
+ mOutputHeight = abs(oneY - origY);
+ } else if (oneX < origX && oneY > origY) {
+ // 90-degree CCW rotation
+ mMat00 = 0;
+ mMat01 = -1;
+ mMat10 = 1;
+ mMat11 = 0;
+ mOutputWidth = abs(oneY - origY);
+ mOutputHeight = abs(oneX - origX);
+ } else if (oneX > origX && oneY < origY) {
+ // 270-degree CCW rotation
+ mMat00 = 0;
+ mMat01 = 1;
+ mMat10 = -1;
+ mMat11 = 0;
+ mOutputWidth = abs(oneY - origY);
+ mOutputHeight = abs(oneX - origX);;
+ } else if (oneX < origX && oneY < origY) {
+ // 180-degree CCW rotation
+ mMat00 = -1;
+ mMat01 = 0;
+ mMat10 = 0;
+ mMat11 = -1;
+ mOutputWidth = abs(oneX - origX);
+ mOutputHeight = abs(oneY - origY);
+ }
+}
+
+Transform Transform::forCropFollowedByRotation(int cropLeft, int cropTop, int cropRight,
+ int cropBottom, int rot90) {
+ // The input crop-region excludes cropRight and cropBottom, so transform the
+ // crop rect such that it defines the entire valid region of pixels
+ // inclusively.
+ cropRight -= 1;
+ cropBottom -= 1;
+
+ int cropXLow = min(cropLeft, cropRight);
+ int cropYLow = min(cropTop, cropBottom);
+ int cropXHigh = max(cropLeft, cropRight);
+ int cropYHigh = max(cropTop, cropBottom);
+ rot90 %= 4;
+ if (rot90 == 0) {
+ return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1);
+ } else if (rot90 == 1) {
+ return Transform(cropXHigh, cropYLow, cropXLow - 1, cropYHigh + 1);
+ } else if (rot90 == 2) {
+ return Transform(cropXHigh, cropYHigh, cropXLow - 1, cropYLow - 1);
+ } else if (rot90 == 3) {
+ return Transform(cropXLow, cropYHigh, cropXHigh + 1, cropYLow - 1);
+ }
+ // Impossible case.
+ return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1);
+}
+
+bool Transform::operator==(const Transform& other) const {
+ return other.mOrigX == mOrigX && //
+ other.mOrigY == mOrigY && //
+ other.mOneX == mOneX && //
+ other.mOneY == mOneY;
+}
+
+/**
+ * Transforms the input coordinates. Coordinates outside the cropped region
+ * are clamped to valid values.
+ */
+void Transform::map(int x, int y, int* outX, int* outY) const {
+ x = max(x, 0);
+ y = max(y, 0);
+ x = min(x, getOutputWidth() - 1);
+ y = min(y, getOutputHeight() - 1);
+ *outX = x * mMat00 + y * mMat01 + mOrigX;
+ *outY = x * mMat10 + y * mMat11 + mOrigY;
+}
+
+int compress(int img_width, int img_height, RowIterator<16>& y_row_generator,
+ RowIterator<8>& cb_row_generator, RowIterator<8>& cr_row_generator,
+ unsigned char* out_buf, size_t out_buf_capacity, std::function<void(size_t)> flush,
+ int quality) {
+ // libjpeg requires the use of setjmp/longjmp to recover from errors. Since
+ // this doesn't play well with RAII, we must use pointers and manually call
+ // delete. See POSIX documentation for longjmp() for details on why the
+ // volatile keyword is necessary.
+ volatile jpeg_compress_struct cinfov;
+
+ jpeg_compress_struct& cinfo =
+ *const_cast<struct jpeg_compress_struct*>(&cinfov);
+
+ JSAMPROW* volatile yArr = nullptr;
+ JSAMPROW* volatile cbArr = nullptr;
+ JSAMPROW* volatile crArr = nullptr;
+
+ JSAMPARRAY imgArr[3];
+
+ // Error handling
+
+ struct my_error_mgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+ } err;
+
+ cinfo.err = jpeg_std_error(&err.pub);
+
+ // Default error_exit will call exit(), so override
+ // to return control via setjmp/longjmp.
+ err.pub.error_exit = [](j_common_ptr cinfo) {
+ my_error_mgr* myerr = reinterpret_cast<my_error_mgr*>(cinfo->err);
+
+ (*cinfo->err->output_message)(cinfo);
+
+ // Return control to the setjmp point (see call to setjmp()).
+ longjmp(myerr->setjmp_buffer, 1);
+ };
+
+ cinfo.err = (struct jpeg_error_mgr*)&err;
+
+ // Set the setjmp point to return to in case of error.
+ if (setjmp(err.setjmp_buffer)) {
+ // If libjpeg hits an error, control will jump to this point (see call to
+ // longjmp()).
+ jpeg_destroy_compress(&cinfo);
+
+ safeDeleteArray(yArr);
+ safeDeleteArray(cbArr);
+ safeDeleteArray(crArr);
+
+ return -1;
+ }
+
+ // Create jpeg compression context
+ jpeg_create_compress(&cinfo);
+
+ // Stores data needed by our c-style callbacks into libjpeg
+ struct ClientData {
+ unsigned char* out_buf;
+ size_t out_buf_capacity;
+ std::function<void(size_t)> flush;
+ int totalOutputBytes;
+ } clientData{out_buf, out_buf_capacity, flush, 0};
+
+ cinfo.client_data = &clientData;
+
+ // Initialize destination manager
+ jpeg_destination_mgr dest;
+
+ dest.init_destination = [](j_compress_ptr cinfo) {
+ ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data);
+
+ cinfo->dest->next_output_byte = cdata.out_buf;
+ cinfo->dest->free_in_buffer = cdata.out_buf_capacity;
+ };
+
+ dest.empty_output_buffer = [](j_compress_ptr cinfo) -> boolean {
+ ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data);
+
+ size_t numBytesInBuffer = cdata.out_buf_capacity;
+ cdata.flush(numBytesInBuffer);
+ cdata.totalOutputBytes += numBytesInBuffer;
+
+ // Reset the buffer
+ cinfo->dest->next_output_byte = cdata.out_buf;
+ cinfo->dest->free_in_buffer = cdata.out_buf_capacity;
+
+ return true;
+ };
+
+ dest.term_destination = [](j_compress_ptr cinfo __unused) {
+ // do nothing to terminate the output buffer
+ };
+
+ cinfo.dest = &dest;
+
+ // Set jpeg parameters
+ cinfo.image_width = img_width;
+ cinfo.image_height = img_height;
+ cinfo.input_components = 3;
+
+ // Set defaults based on the above values
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_set_quality(&cinfo, quality, true);
+
+ cinfo.dct_method = JDCT_IFAST;
+
+ cinfo.raw_data_in = true;
+
+ jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+
+ cinfo.comp_info[0].h_samp_factor = 2;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ cinfo.comp_info[1].h_samp_factor = 1;
+ cinfo.comp_info[1].v_samp_factor = 1;
+ cinfo.comp_info[2].h_samp_factor = 1;
+ cinfo.comp_info[2].v_samp_factor = 1;
+
+ jpeg_start_compress(&cinfo, true);
+
+ yArr = new JSAMPROW[cinfo.comp_info[0].v_samp_factor * DCTSIZE];
+ cbArr = new JSAMPROW[cinfo.comp_info[1].v_samp_factor * DCTSIZE];
+ crArr = new JSAMPROW[cinfo.comp_info[2].v_samp_factor * DCTSIZE];
+
+ imgArr[0] = const_cast<JSAMPARRAY>(yArr);
+ imgArr[1] = const_cast<JSAMPARRAY>(cbArr);
+ imgArr[2] = const_cast<JSAMPARRAY>(crArr);
+
+ for (int y = 0; y < img_height; y += DCTSIZE * 2) {
+ std::array<unsigned char*, 16> yData = y_row_generator.loadAt(y);
+ std::array<unsigned char*, 8> cbData = cb_row_generator.loadAt(y / 2);
+ std::array<unsigned char*, 8> crData = cr_row_generator.loadAt(y / 2);
+
+ for (int row = 0; row < DCTSIZE * 2; row++) {
+ yArr[row] = yData[row];
+ }
+ for (int row = 0; row < DCTSIZE; row++) {
+ cbArr[row] = cbData[row];
+ crArr[row] = crData[row];
+ }
+
+ jpeg_write_raw_data(&cinfo, imgArr, DCTSIZE * 2);
+ }
+
+ jpeg_finish_compress(&cinfo);
+
+ int numBytesInBuffer = cinfo.dest->next_output_byte - out_buf;
+
+ flush(numBytesInBuffer);
+
+ clientData.totalOutputBytes += numBytesInBuffer;
+
+ safeDeleteArray(yArr);
+ safeDeleteArray(cbArr);
+ safeDeleteArray(crArr);
+
+ jpeg_destroy_compress(&cinfo);
+
+ return clientData.totalOutputBytes;
+}
+
+int compress(
+ /** Input image dimensions */
+ int width, int height,
+ /** Y Plane */
+ unsigned char* yBuf, int yPStride, int yRStride,
+ /** Cb Plane */
+ unsigned char* cbBuf, int cbPStride, int cbRStride,
+ /** Cr Plane */
+ unsigned char* crBuf, int crPStride, int crRStride,
+ /** Output */
+ unsigned char* outBuf, size_t outBufCapacity,
+ /** Jpeg compression parameters */
+ int quality,
+ /** Crop */
+ int cropLeft, int cropTop, int cropRight, int cropBottom,
+ /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree
+ * rotation. */
+ int rot90) {
+ int finalWidth;
+ int finalHeight;
+ finalWidth = cropRight - cropLeft;
+ finalHeight = cropBottom - cropTop;
+
+ rot90 %= 4;
+ // for 90 and 270-degree rotations, flip the final width and height
+ if (rot90 == 1) {
+ finalWidth = cropBottom - cropTop;
+ finalHeight = cropRight - cropLeft;
+ } else if (rot90 == 3) {
+ finalWidth = cropBottom - cropTop;
+ finalHeight = cropRight - cropLeft;
+ }
+
+ const Plane yP = {width, height, yBuf, yPStride, yRStride};
+ const Plane cbP = {width / 2, height / 2, cbBuf, cbPStride, cbRStride};
+ const Plane crP = {width / 2, height / 2, crBuf, crPStride, crRStride};
+
+ auto flush = [](size_t numBytes __unused) {
+ // do nothing
+ };
+
+ // Round up to the nearest multiple of 64.
+ int y_row_length = (finalWidth + 16 + 63) & ~63;
+ int cb_row_length = (finalWidth / 2 + 16 + 63) & ~63;
+ int cr_row_length = (finalWidth / 2 + 16 + 63) & ~63;
+
+ Transform yTrans = Transform::forCropFollowedByRotation(
+ cropLeft, cropTop, cropRight, cropBottom, rot90);
+
+ Transform chromaTrans = Transform::forCropFollowedByRotation(
+ cropLeft / 2, cropTop / 2, cropRight / 2, cropBottom / 2, rot90);
+
+ RowIterator<16> yIter(yP, yTrans, y_row_length);
+ RowIterator<8> cbIter(cbP, chromaTrans, cb_row_length);
+ RowIterator<8> crIter(crP, chromaTrans, cr_row_length);
+
+ return compress(finalWidth, finalHeight, yIter, cbIter, crIter, outBuf, outBufCapacity, flush,
+ quality);
+}
+
+extern "C" {
+
+static jint JpegEncoder_compressJpegFromYUV420p(
+ JNIEnv* env, jclass clazz __unused,
+ /** Input image dimensions */
+ jint width, jint height,
+ /** Y Plane */
+ jobject yBuf, jint yPStride, jint yRStride,
+ /** Cb Plane */
+ jobject cbBuf, jint cbPStride, jint cbRStride,
+ /** Cr Plane */
+ jobject crBuf, jint crPStride, jint crRStride,
+ /** Output */
+ jobject outBuf, jint outBufCapacity,
+ /** Jpeg compression parameters */
+ jint quality,
+ /** Crop */
+ jint cropLeft, jint cropTop, jint cropRight, jint cropBottom,
+ /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree
+ * rotation. */
+ jint rot90) {
+ // ALOGE("Insert log inside JpegEncoder_compressJpegFromYUV420p");
+ jbyte* y = (jbyte*)env->GetDirectBufferAddress(yBuf);
+ jbyte* cb = (jbyte*)env->GetDirectBufferAddress(cbBuf);
+ jbyte* cr = (jbyte*)env->GetDirectBufferAddress(crBuf);
+ jbyte* out = (jbyte*)env->GetDirectBufferAddress(outBuf);
+
+ size_t actualJpegSize = compress(width, height,
+ (unsigned char*)y, yPStride, yRStride,
+ (unsigned char*)cb, cbPStride, cbRStride,
+ (unsigned char*)cr, crPStride, crRStride,
+ (unsigned char*)out, (size_t)outBufCapacity,
+ quality, cropLeft, cropTop, cropRight, cropBottom, rot90);
+
+ size_t finalJpegSize = actualJpegSize + sizeof(CameraBlob);
+ if (finalJpegSize > outBufCapacity) {
+ // ALOGE("%s: Final jpeg buffer %zu not large enough for the jpeg blob header with "\
+ // "capacity %d", __FUNCTION__, finalJpegSize, outBufCapacity);
+ return actualJpegSize;
+ }
+
+ int8_t* header = static_cast<int8_t *> (out) +
+ (outBufCapacity - sizeof(CameraBlob));
+ CameraBlob *blob = reinterpret_cast<CameraBlob *> (header);
+ blob->blobId = CameraBlobId::JPEG;
+ blob->blobSize = actualJpegSize;
+
+ return actualJpegSize;
+}
+
+} // extern "C"
+
+static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
+ const JNINativeMethod* gMethods, int numMethods) {
+ int res = jniRegisterNativeMethods(env, className, gMethods, numMethods);
+ return res;
+}
+
+static const JNINativeMethod gJpegEncoderMethods[] = {
+ {"compressJpegFromYUV420pNative",
+ "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IIIIIII)I",
+ (void*)JpegEncoder_compressJpegFromYUV420p}};
+
+int register_android_hardware_camera2_impl_JpegEncoder(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "androidx/camera/extensions/impl/advanced/JpegEncoder",
+ gJpegEncoderMethods, NELEM(gJpegEncoderMethods));
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+ JNIEnv* env;
+
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return -1;
+ }
+
+ if (register_android_hardware_camera2_impl_JpegEncoder(env) < 0) {
+ ALOGE("ERROR: JpegEncoder native registration failed");
+ return -1;
+ }
+
+ return JNI_VERSION_1_6;
+} \ No newline at end of file
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
index 5f6cb2ba..30a79a6b 100755
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -20,6 +20,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.SessionConfiguration;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Build;
@@ -116,6 +117,26 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI
}
@Override
+ public void onPostviewOutputSurface(Surface surface) {
+
+ }
+
+ @Override
+ public void processWithPostview(
+ Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor) {
+ if (!isPostviewAvailable()) {
+ throw new RuntimeException("The extension doesn't support postview");
+ }
+
+ if (resultCallback != null) {
+ process(results, resultCallback, executor);
+ } else {
+ process(results);
+ }
+ }
+
+ @Override
public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor) {
throw new RuntimeException("The extension doesn't support capture " +
@@ -164,6 +185,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI
}
@Override
+ public void onResolutionUpdate(Size size, Size postviewSize) {
+
+ }
+
+ @Override
public void onImageFormatUpdate(int imageFormat) {
}
@@ -244,6 +270,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI
}
@Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ return new ArrayList<>();
+ }
+
+ @Override
public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) {
return null;
}
@@ -257,4 +288,24 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
return new ArrayList<>();
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
index 5018df8a..aa95a4a7 100755
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -18,6 +18,7 @@ package androidx.camera.extensions.impl;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
import android.util.Pair;
import android.util.Size;
@@ -162,4 +163,9 @@ public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl {
return captureStage;
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
index 5c9b2d39..c9b24206 100755
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -21,6 +21,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageWriter;
@@ -118,6 +119,26 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende
}
@Override
+ public void onPostviewOutputSurface(Surface surface) {
+
+ }
+
+ @Override
+ public void processWithPostview(
+ Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor) {
+ if (!isPostviewAvailable()) {
+ throw new RuntimeException("The extension doesn't support postview");
+ }
+
+ if (resultCallback != null) {
+ process(results, resultCallback, executor);
+ } else {
+ process(results);
+ }
+ }
+
+ @Override
public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor) {
throw new RuntimeException("The extension doesn't support capture " +
@@ -166,6 +187,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende
}
@Override
+ public void onResolutionUpdate(Size size, Size postviewSize) {
+
+ }
+
+ @Override
public void onImageFormatUpdate(int imageFormat) {
}
@@ -267,6 +293,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende
}
@Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ return new ArrayList<>();
+ }
+
+ @Override
public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) {
return null;
}
@@ -280,4 +311,24 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
return new ArrayList<>();
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
index fcc78d55..2ef357c3 100755
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -19,6 +19,7 @@ import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.util.Pair;
import android.util.Size;
@@ -183,4 +184,9 @@ public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl {
return captureStage;
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
index 5c3882b8..a72deef6 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -16,10 +16,13 @@
package androidx.camera.extensions.impl;
import android.content.Context;
+import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Build;
@@ -51,6 +54,8 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
private static final int SESSION_STAGE_ID = 101;
private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_SHADE;
+ private CameraCharacteristics mCameraCharacteristics;
+
/**
* @hide
*/
@@ -62,6 +67,7 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
*/
@Override
public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ mCameraCharacteristics = cameraCharacteristics;
}
/**
@@ -104,6 +110,7 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
CaptureProcessorImpl captureProcessor =
new CaptureProcessorImpl() {
private ImageWriter mImageWriter;
+ private ImageWriter mImageWriterPostview;
@Override
public void onOutputSurface(Surface surface, int imageFormat) {
@@ -113,6 +120,61 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
}
@Override
+ public void onPostviewOutputSurface(Surface surface) {
+ if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) &&
+ mImageWriterPostview == null) {
+ mImageWriterPostview = ImageWriter.newInstance(surface, 1);
+ }
+ }
+
+ @Override
+ public void processWithPostview(
+ Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor) {
+
+ Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID);
+ if (result == null) {
+ Log.w(TAG,
+ "Unable to process since images does not contain all " +
+ "stages.");
+ return;
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Image image = mImageWriterPostview.dequeueInputImage();
+
+ // Postview processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ // For sample, allocate empty buffer to match postview size
+ yByteBuffer.put(ByteBuffer.allocate(image.getPlanes()[0]
+ .getBuffer().capacity()));
+ uByteBuffer.put(ByteBuffer.allocate(image.getPlanes()[2]
+ .getBuffer().capacity()));
+ vByteBuffer.put(ByteBuffer.allocate(image.getPlanes()[1]
+ .getBuffer().capacity()));
+ Long sensorTimestamp =
+ result.second.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (sensorTimestamp != null) {
+ image.setTimestamp(sensorTimestamp);
+ } else {
+ Log.e(TAG, "Sensor timestamp absent using default!");
+ }
+
+ mImageWriterPostview.queueInputImage(image);
+ }
+ }
+
+ // Process still capture
+ if (resultCallback != null) {
+ process(results, resultCallback, executor);
+ } else {
+ process(results);
+ }
+ }
+
+ @Override
public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor) {
Pair<Image, TotalCaptureResult> result = results.get(DEFAULT_STAGE_ID);
@@ -241,6 +303,11 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
}
@Override
+ public void onResolutionUpdate(Size size, Size postviewSize) {
+
+ }
+
+ @Override
public void onImageFormatUpdate(int imageFormat) {
}
@@ -317,7 +384,59 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
*/
@Override
public List<Pair<Integer, Size[]>> getSupportedResolutions() {
- return null;
+ List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>();
+
+ StreamConfigurationMap map =
+ mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ if (map != null) {
+ // The sample implementation only retrieves originally supported resolutions from
+ // CameraCharacteristics for JPEG and YUV_420_888 formats to return.
+ Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG);
+
+ if (outputSizes != null) {
+ formatResolutionsPairList.add(Pair.create(ImageFormat.JPEG, outputSizes));
+ }
+
+ outputSizes = map.getOutputSizes(ImageFormat.YUV_420_888);
+
+ if (outputSizes != null) {
+ formatResolutionsPairList.add(Pair.create(ImageFormat.YUV_420_888, outputSizes));
+ }
+ }
+
+ return formatResolutionsPairList;
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ // Sample for supported postview sizes, returns subset of supported resolutions for
+ // still capture that are less than its size and match the aspect ratio
+ List<Pair<Integer, Size[]>> res = new ArrayList<>();
+ List<Pair<Integer, Size[]>> captureSupportedResolutions = getSupportedResolutions();
+ float targetAr = ((float) captureSize.getWidth()) / captureSize.getHeight();
+
+ for (Pair<Integer, Size[]> elem : captureSupportedResolutions) {
+ Integer currFormat = elem.first;
+ Size[] currFormatSizes = elem.second;
+ List<Size> postviewSizes = new ArrayList<>();
+
+ for (Size s : currFormatSizes) {
+ if ((s.equals(captureSize)) || (s.getWidth() > captureSize.getWidth())
+ || (s.getHeight() > captureSize.getHeight())) continue;
+ float currentAr = ((float) s.getWidth()) / s.getHeight();
+ if (Math.abs(targetAr - currentAr) < 0.01) {
+ postviewSizes.add(s);
+ }
+ }
+
+ if (!postviewSizes.isEmpty()) {
+ res.add(new Pair<Integer, Size[]>(currFormat,
+ postviewSizes.toArray(new Size[postviewSizes.size()])));
+ }
+ }
+
+ return res;
}
@Override
@@ -341,4 +460,24 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
CaptureResult.FLASH_STATE};
return Arrays.asList(CAPTURE_RESULT_SET);
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return true;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
index 45c7f47c..ace54c8b 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -19,6 +19,7 @@ import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.SessionConfiguration;
import android.util.Pair;
import android.util.Size;
import android.view.Surface;
@@ -202,4 +203,9 @@ public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl {
return captureStage;
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
index efd0afac..f4719b8b 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -16,46 +16,60 @@
package androidx.camera.extensions.impl;
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.util.Pair;
import android.util.Size;
import android.view.Surface;
-import java.util.concurrent.Executor;
import java.util.Map;
+import java.util.concurrent.Executor;
/**
* The interface for processing a set of {@link Image}s that have captured.
*
* @since 1.0
- * @hide
*/
-public interface CaptureProcessorImpl {
- /**
- * This gets called to update where the CaptureProcessor should write the output of {@link
- * #process(Map)}.
- *
- * @param surface The {@link Surface} that the CaptureProcessor should write data into.
- * @param imageFormat The format of that the surface expects.
- * @hide
- */
- void onOutputSurface(Surface surface, int imageFormat);
-
+@SuppressLint("UnknownNullness")
+public interface CaptureProcessorImpl extends ProcessorImpl {
/**
* Process a set images captured that were requested.
*
* <p> The result of the processing step should be written to the {@link Surface} that was
* received by {@link #onOutputSurface(Surface, int)}.
*
- * @param results The map of images and metadata to process. The {@link Image} that are
- * contained within the map will become invalid after this method completes,
- * so no references to them should be kept.
- * @hide
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata to
+ * process. The {@link Image} that are contained within the map will become
+ * invalid after this method completes, so no references to them should be kept.
*/
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
/**
+ * Informs the CaptureProcessorImpl where it should write the postview output to.
+ * This will only be invoked once if a valid postview surface was set.
+ *
+ * @param surface A valid {@link ImageFormat#YUV_420_888} {@link Surface}
+ * that the CaptureProcessorImpl should write data into.
+ * @since 1.4
+ */
+ void onPostviewOutputSurface(Surface surface);
+
+ /**
+ * Invoked when the Camera Framework changes the configured output resolution for
+ * still capture and postview.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input for still capture and postview to be at the specified resolutions.
+ *
+ * @param size for the surface for still capture.
+ * @param postviewSize for the surface for postview.
+ * @since 1.4
+ */
+ void onResolutionUpdate(Size size, Size postviewSize);
+
+ /**
* Process a set images captured that were requested.
*
* <p> The result of the processing step should be written to the {@link Surface} that was
@@ -66,7 +80,7 @@ public interface CaptureProcessorImpl {
* become invalid after this method completes, so no references to them
* should be kept.
* @param resultCallback Capture result callback to be called once the capture result
- * values are ready.
+ * values of the processed image are ready.
* @param executor The executor to run the callback on. If null then the callback will
* run on any arbitrary executor.
* @since 1.3
@@ -75,22 +89,28 @@ public interface CaptureProcessorImpl {
ProcessResultImpl resultCallback, Executor executor);
/**
- * This callback will be invoked when CameraX changes the configured input resolution. After
- * this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as input
- * to be at the specified resolution.
+ * Process a set images captured that were requested for both postview and
+ * still capture.
*
- * @param size for the surface.
- * @hide
- */
- void onResolutionUpdate(Size size);
-
- /**
- * This callback will be invoked when CameraX changes the configured input image format.
- * After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
- * input to have the specified image format.
+ * <p> This processing method will be called if a postview was requested, therefore the
+ * processed postview should be written to the
+ * {@link Surface} received by {@link #onPostviewOutputSurface(Surface, int)}.
+ * The final result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}. Since postview should be available
+ * before the capture, it should be processed and written to the surface before
+ * the final capture is processed.
*
- * @param imageFormat for the surface.
- * @hide
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and
+ * metadata to process. The {@link Image} that are contained within
+ * the map will become invalid after this method completes, so no
+ * references to them should be kept.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback
+ * will run on any arbitrary executor.
+ * @throws RuntimeException if postview feature is not supported
+ * @since 1.4
*/
- void onImageFormatUpdate(int imageFormat);
+ void processWithPostview(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor);
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
index f926cff9..23570c4b 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -84,4 +84,21 @@ public interface ExtenderStateListener {
* @hide
*/
CaptureStageImpl onDisableSession();
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * initialized and must return a valid camera session type
+ * {@link android.hardware.camera2.params.SessionConfiguration#getSessionType}
+ * to be used to configure camera capture session. Both the preview and the image capture
+ * extender must return the same session type value for a specific extension type. If there
+ * is inconsistency between the session type values from preview and image extenders, then
+ * the session configuration will fail.
+ *
+ *
+ * @since 1.4
+ * @return Camera capture session type. Regular and vendor specific types are supported but
+ * not high speed values. The extension can return -1 in which case the camera capture session
+ * will be configured to use the default regular type.
+ */
+ int onSessionType();
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
index af147ed7..75739ce0 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -29,7 +29,7 @@ import android.util.Log;
*/
public class ExtensionVersionImpl {
private static final String TAG = "ExtenderVersionImpl";
- private static final String VERSION = "1.3.0";
+ private static final String VERSION = "1.4.0";
/**
* @hide
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
index 57b7fe65..25232635 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -17,10 +17,12 @@ package androidx.camera.extensions.impl;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.SessionConfiguration;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Build;
@@ -130,6 +132,26 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
}
@Override
+ public void onPostviewOutputSurface(Surface surface) {
+
+ }
+
+ @Override
+ public void processWithPostview(
+ Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor) {
+ if (!isPostviewAvailable()) {
+ throw new RuntimeException("The extension doesn't support postview");
+ }
+
+ if (resultCallback != null) {
+ process(results, resultCallback, executor);
+ } else {
+ process(results);
+ }
+ }
+
+ @Override
public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor) {
Pair<Image, TotalCaptureResult> result = results.get(NORMAL_STAGE_ID);
@@ -184,12 +206,25 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
jpegOrientation));
}
+ Integer strength = result.second.get(
+ CaptureResult.EXTENSION_STRENGTH);
+ if (strength != null) {
+ captureResults.add(new Pair<>(CaptureResult.EXTENSION_STRENGTH,
+ strength));
+ }
+
+ captureResults.add(new Pair<>(CaptureResult.EXTENSION_CURRENT_TYPE,
+ CameraExtensionCharacteristics.EXTENSION_HDR));
+
if (executor != null) {
executor.execute(() -> resultCallback.onCaptureCompleted(
shutterTimestamp, captureResults));
+ executor.execute(() ->
+ resultCallback.onCaptureProcessProgressed(100));
} else {
resultCallback.onCaptureCompleted(shutterTimestamp,
captureResults);
+ resultCallback.onCaptureProcessProgressed(100);
}
}
}
@@ -264,6 +299,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
}
@Override
+ public void onResolutionUpdate(Size size, Size postviewSize) {
+
+ }
+
+ @Override
public void onImageFormatUpdate(int imageFormat) {
}
@@ -332,6 +372,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
}
@Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ return new ArrayList<>();
+ }
+
+ @Override
public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) {
return null;
}
@@ -340,7 +385,7 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
final CaptureRequest.Key [] CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_ZOOM_RATIO,
CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_REGIONS,
- CaptureRequest.CONTROL_AF_TRIGGER};
+ CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.EXTENSION_STRENGTH};
return Arrays.asList(CAPTURE_REQUEST_SET);
}
@@ -348,7 +393,28 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
final CaptureResult.Key [] CAPTURE_RESULT_SET = {CaptureResult.CONTROL_ZOOM_RATIO,
CaptureResult.CONTROL_AF_MODE, CaptureResult.CONTROL_AF_REGIONS,
- CaptureResult.CONTROL_AF_TRIGGER, CaptureResult.CONTROL_AF_STATE};
+ CaptureResult.CONTROL_AF_TRIGGER, CaptureResult.CONTROL_AF_STATE,
+ CaptureResult.EXTENSION_CURRENT_TYPE, CaptureResult.EXTENSION_STRENGTH};
return Arrays.asList(CAPTURE_RESULT_SET);
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return true;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
index 78b0a9d0..7777bfa2 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -18,15 +18,18 @@ package androidx.camera.extensions.impl;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.SessionConfiguration;
import android.media.ImageWriter;
import android.media.Image;
import android.util.Pair;
import android.util.Size;
import android.view.Surface;
+import java.io.Closeable;
import java.util.ArrayList;
import java.util.concurrent.Executor;
import java.util.List;
@@ -43,8 +46,6 @@ import java.util.List;
public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
private static final int DEFAULT_STAGE_ID = 0;
- ImageWriter mWriter;
-
/**
* @hide
*/
@@ -109,17 +110,32 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
return null;
}
- private PreviewImageProcessorImpl mProcessor = new PreviewImageProcessorImpl() {
+ private HdrPreviewProcessor mProcessor = new HdrPreviewProcessor();
+
+ private static class HdrPreviewProcessor implements PreviewImageProcessorImpl, Closeable {
Surface mSurface;
int mFormat = -1;
+ final Object mLock = new Object(); // Synchronize access to 'mWriter'
+ ImageWriter mWriter;
- private void setWindowSurface() {
- if (mSurface != null && mFormat >= 0) {
+ public void close() {
+ synchronized(mLock) {
if (mWriter != null) {
mWriter.close();
+ mWriter = null;
}
+ }
+ }
- mWriter = ImageWriter.newInstance(mSurface, 2, mFormat);
+ private void setWindowSurface() {
+ synchronized(mLock) {
+ if (mSurface != null && mFormat >= 0) {
+ if (mWriter != null) {
+ mWriter.close();
+ }
+
+ mWriter = ImageWriter.newInstance(mSurface, 2, mFormat);
+ }
}
}
@@ -132,7 +148,11 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
@Override
public void process(Image image, TotalCaptureResult result) {
- mWriter.queueInputImage(image);
+ synchronized(mLock) {
+ if (mWriter != null) {
+ mWriter.queueInputImage(image);
+ }
+ }
}
@Override
@@ -175,6 +195,14 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
jpegOrientation));
}
+ Integer strength = result.get(CaptureResult.EXTENSION_STRENGTH);
+ if (strength != null) {
+ captureResults.add(new Pair<>(CaptureResult.EXTENSION_STRENGTH, strength));
+ }
+
+ captureResults.add(new Pair<>(CaptureResult.EXTENSION_CURRENT_TYPE,
+ CameraExtensionCharacteristics.EXTENSION_HDR));
+
if (executor != null) {
executor.execute(() -> resultCallback.onCaptureCompleted(shutterTimestamp,
captureResults));
@@ -209,10 +237,7 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
*/
@Override
public void onDeInit() {
- if (mWriter != null) {
- mWriter.close();
- mWriter = null;
- }
+ mProcessor.close();
}
/**
@@ -238,4 +263,9 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
public CaptureStageImpl onDisableSession() {
return null;
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
index c27a5dbb..37e7baf3 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -91,6 +91,21 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
List<Pair<Integer, Size[]>> getSupportedResolutions();
/**
+ * Returns the customized supported postview resolutions for a still capture using
+ * its size.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device.
+ *
+ * @return the customized supported resolutions, or null to support all sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap}.
+ * @since 1.4
+ */
+ List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize);
+
+ /**
* Returns the estimated capture latency range in milliseconds for the target capture
* resolution.
*
@@ -138,5 +153,44 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
* @since 1.3
*/
List<CaptureResult.Key> getAvailableCaptureResultKeys();
-}
+ /**
+ * Advertise support for {@link ProcessResultImpl#onCaptureProcessProgressed}.
+ *
+ * @return {@code true} in case the process progress callback is supported and is expected to
+ * be triggered, {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isCaptureProcessProgressAvailable();
+
+ /**
+ * Returns the dynamically calculated capture latency pair in milliseconds.
+ *
+ * <p>In contrast to {@link #getEstimatedCaptureLatencyRange} this method is guaranteed to be
+ * called after the camera capture session is initialized and camera preview is enabled.
+ * The measurement is expected to take in to account dynamic parameters such as the current
+ * scene, the state of 3A algorithms, the state of internal HW modules and return a more
+ * accurate assessment of the still capture latency.</p>
+ *
+ * @return pair that includes the estimated input frame/frames camera capture latency as the
+ * first field and the estimated post-processing latency {@link CaptureProcessorImpl#process}
+ * as the second pair field. Both first and second fields will be in milliseconds. The total
+ * still capture latency will be the sum of both the first and second values.
+ * The pair is expected to be null if the dynamic latency estimation is not supported.
+ * If clients have not configured a still capture output, then this method can also return a
+ * null pair.
+ * @since 1.4
+ */
+ Pair<Long, Long> getRealtimeCaptureLatency();
+
+ /**
+ * Indicates whether the extension supports the postview for still capture feature.
+ * If the extension is using HAL processing, false should be returned since the
+ * postview feature is not currently supported for this case.
+ *
+ * @return {@code true} in case postview for still capture is supported
+ * {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isPostviewAvailable();
+}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
index f0821ed7..e3317d94 100755
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -20,6 +20,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.SessionConfiguration;
import android.media.Image;
import android.media.ImageWriter;
import android.os.Build;
@@ -116,6 +117,26 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender
}
@Override
+ public void onPostviewOutputSurface(Surface surface) {
+
+ }
+
+ @Override
+ public void processWithPostview(
+ Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor) {
+ if (!isPostviewAvailable()) {
+ throw new RuntimeException("The extension doesn't support postview");
+ }
+
+ if (resultCallback != null) {
+ process(results, resultCallback, executor);
+ } else {
+ process(results);
+ }
+ }
+
+ @Override
public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor) {
throw new RuntimeException("The extension doesn't support capture " +
@@ -164,6 +185,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender
}
@Override
+ public void onResolutionUpdate(Size size, Size postviewSize) {
+
+ }
+
+ @Override
public void onImageFormatUpdate(int imageFormat) {
}
@@ -244,6 +270,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender
}
@Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ return new ArrayList<>();
+ }
+
+ @Override
public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) {
return null;
}
@@ -257,4 +288,24 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
return new ArrayList<>();
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ return false;
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ return null;
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ return false;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
index e29abec1..46be86ab 100755
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -18,6 +18,7 @@ package androidx.camera.extensions.impl;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
import android.util.Pair;
import android.util.Size;
@@ -162,4 +163,9 @@ public final class NightPreviewExtenderImpl implements PreviewExtenderImpl {
return captureStage;
}
+
+ @Override
+ public int onSessionType() {
+ return SessionConfiguration.SESSION_REGULAR;
+ }
}
diff --git a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
index d4c2014d..518942e9 100644
--- a/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
+++ b/camera2/extensions/sample/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
@@ -24,7 +24,6 @@ import java.util.List;
/**
* Allows clients to receive information about the capture result values of processed frames.
*
- * @since 1.3
*/
public interface ProcessResultImpl {
/**
@@ -38,6 +37,23 @@ public interface ProcessResultImpl {
* must also be passed as part of this callback. Both Camera2 and
* CameraX guarantee that those two settings and results are always
* supported and applied by the corresponding framework.
+ * @since 1.3
*/
void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result);
+
+
+ /**
+ * Capture progress callback that needs to be called when the process capture is
+ * ongoing and includes the estimated progress of the processing.
+ *
+ * <p>Extensions must ensure that they always call this callback with monotonically increasing
+ * values.</p>
+ *
+ * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the
+ * callback is expected to be called once when processing is done with value 100.</p>
+ *
+ * @param progress Value between 0 and 100.
+ * @since 1.4
+ */
+ void onCaptureProcessProgressed(int progress);
}
diff --git a/camera2/extensions/service_based_sample/README.txt b/camera2/extensions/service_based_sample/README.txt
new file mode 100644
index 00000000..a212a39a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/README.txt
@@ -0,0 +1,26 @@
+Service-Based reference implementation
+This reference implementation demonstrates how to implement the Extensions in a standalone service.
+
+It contains the following components:
+1) oem_library:
+ A Camera Extensions OEM library that implements the Extensions-Interface to enable both Camera2
+ and CameraX Extensions APIS. It is basically a pass-through that forwards all calls from
+ Extensions-Interface to the service. If it works well for you, you don't have to modify it.
+
+ It also contains the AIDL and wrapper classes for communicating with the service. AIDL and
+ wrapper classes are located in androidx.camera.extensions.impl.service package.
+
+ Both Advanced Extender and Basic Extender is supported, however, Advanced Extender is enabled
+ by default. If you want to use Basic Extender to implement, change
+ ExtensionsVersionImpl#isAdvancedExtenderImplemented to return false.
+
+2) extensions_service:
+ A sample implementation of extensions service is provided. You should add your real implementation
+ here. The sample service is built using Android.bp, but you can transform it into a gradle
+ project by adding the stub jar of oem_library (located in
+ out/target/common/obj/JAVA_LIBRARIES/service_based_camera_extensions_intermediates/) to the
+ dependencies.
+
+In this service-based architecture, all functionalities of the Extensions-Interface are supposed to
+be implemented in extensions_service except for ExtensionVersionImpl#checkApiVersion and
+#isAdvancedExtenderImplemented which require you to implement it in the oem_library. \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/extensions_service/Android.bp b/camera2/extensions/service_based_sample/extensions_service/Android.bp
new file mode 100644
index 00000000..383a3c0b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "ExtensionsService",
+ srcs: ["src/**/*.java"],
+ libs: ["service_based_camera_extensions"],
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ enforce_uses_libs: false,
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml b/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml
new file mode 100644
index 00000000..abd40763
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.oemextensions">
+ <queries>
+ <intent>
+ <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" />
+ </intent>
+ </queries>
+
+ <application
+ android:label="@string/app_name"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
+ <uses-library android:name="androidx.camera.extensions.impl" android:required="true" />
+ <service
+ android:name="ExtensionsService"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" />
+ </intent-filter>
+ </service>
+ </application>
+
+</manifest>
diff --git a/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml b/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml
new file mode 100644
index 00000000..7a8f9d4a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">Camera Extensions Service</string>
+
+</resources>
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java
new file mode 100644
index 00000000..960f9a4c
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/AdvancedExtenderImplStub.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.MeteringRectangle;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+public class AdvancedExtenderImplStub extends IAdvancedExtenderImpl.Stub {
+ private static final String TAG = "AdvancedExtenderStub";
+ private Context mContext;
+ private int mExtensionType;
+ private String mCurrentCameraId;
+ private CameraCharacteristics mCameraCharacteristics;
+
+ /**
+ * Construct the AdvancedExtenderImplStub instance.
+ *
+ * @param context a context.
+ * @param extensionType CameraExtensionCharacteristics#EXTENSION_AUTOMATIC for Auto,
+ * CameraExtensionCharacteristics#EXTENSION_NIGHT for Night,
+ * CameraExtensionCharacteristics#EXTENSION_HDR for HDR,
+ * CameraExtensionCharacteristics#EXTENSION_BOKEH for Bokeh,
+ * CameraExtensionCharacteristics#EXTENSION_FACE_RETOUCH for face retouch.
+ */
+ public AdvancedExtenderImplStub(@NonNull Context context, int extensionType) {
+ mContext = context;
+ mExtensionType = extensionType;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId) throws RemoteException {
+ return true;
+ }
+
+ @Override
+ public void init(@NonNull String cameraId) throws RemoteException {
+ mCurrentCameraId = cameraId;
+ try {
+ CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
+ mCameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
+ } catch (CameraAccessException e) {
+ throw new IllegalStateException("Cannot get CameraCharacteristics", e);
+ }
+ }
+
+ @Override
+ @NonNull
+ public LatencyRange getEstimatedCaptureLatencyRange(@NonNull String cameraId,
+ @Nullable androidx.camera.extensions.impl.service.Size outputSize,
+ int format) throws RemoteException {
+ Log.d(TAG, "getEstimatedCaptureLatencyRange format" + format);
+
+ LatencyRange latencyRange = new LatencyRange();
+ latencyRange.min = 100;
+ latencyRange.max = 1000;
+ return latencyRange;
+ }
+
+ private static SizeList getSupportedSizeByFormat(
+ CameraCharacteristics cameraCharacteristics, int imageFormat) {
+ StreamConfigurationMap streamConfigMap =
+ cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ Size[] sizes = streamConfigMap.getOutputSizes(imageFormat);
+ SizeList sizeList = new SizeList();
+ sizeList.sizes = new ArrayList<>();
+ for (Size size : sizes) {
+ androidx.camera.extensions.impl.service.Size sz =
+ new androidx.camera.extensions.impl.service.Size();
+ sz.width = size.getWidth();
+ sz.height = size.getHeight();
+ sizeList.sizes.add(sz);
+ }
+ sizeList.format = imageFormat;
+ return sizeList;
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedPreviewOutputResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ return Arrays.asList(
+ getSupportedSizeByFormat(mCameraCharacteristics, ImageFormat.PRIVATE));
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedCaptureOutputResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ return Arrays.asList(
+ getSupportedSizeByFormat(mCameraCharacteristics,
+ ImageFormat.JPEG),
+ getSupportedSizeByFormat(mCameraCharacteristics,
+ ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ @NonNull
+ public List<SizeList> getSupportedYuvAnalysisResolutions(@NonNull String cameraId)
+ throws RemoteException {
+ return Arrays.asList(
+ getSupportedSizeByFormat(mCameraCharacteristics, ImageFormat.YUV_420_888));
+ }
+
+ @Override
+ @NonNull
+ public ISessionProcessorImpl getSessionProcessor() throws RemoteException {
+ Log.d(TAG, "getSessionProcessor");
+ return new SimpleSessionProcessorStub(mCameraCharacteristics,
+ getSupportedCaptureRequestKeys().keySet(),
+ getSupportedCaptureResultKeys().keySet());
+ }
+
+ private Map<CaptureRequest.Key, Object> getSupportedCaptureRequestKeys() {
+ Map<CaptureRequest.Key, Object> map = new HashMap<>();
+ map.put(CaptureRequest.CONTROL_ZOOM_RATIO,
+ 1.0f /* don't care, must not be null */);
+ map.put(CaptureRequest.SCALER_CROP_REGION,
+ new Rect() /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AE_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AWB_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureRequest.JPEG_QUALITY,
+ (byte)0 /* don't care, must not be null */);
+ map.put(CaptureRequest.JPEG_ORIENTATION,
+ 0 /* don't care, must not be null */);
+ if (isAfAutoSupported()) {
+ map.put(CaptureRequest.CONTROL_AF_TRIGGER,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AF_MODE,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureRequest.CONTROL_AF_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ }
+
+
+ // Filters out unsupported keys
+ List<CaptureRequest.Key<?>> camera2SupportKeys=
+ mCameraCharacteristics.getAvailableCaptureRequestKeys();
+ for (CaptureRequest.Key key : new HashSet<>(map.keySet())) {
+ if (!camera2SupportKeys.contains(key)) {
+ map.remove(key);
+ }
+ }
+
+ return map;
+ }
+
+ private Map<CaptureResult.Key, Object> getSupportedCaptureResultKeys() {
+ Map<CaptureResult.Key, Object> map = new HashMap<>();
+ map.put(CaptureResult.CONTROL_ZOOM_RATIO,
+ 1.0f /* don't care, must not be null */);
+ map.put(CaptureResult.SCALER_CROP_REGION,
+ new Rect() /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AE_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AWB_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.JPEG_QUALITY,
+ (byte)0 /* don't care, must not be null */);
+ map.put(CaptureResult.JPEG_ORIENTATION,
+ 0 /* don't care, must not be null */);
+ if (isAfAutoSupported()) {
+ map.put(CaptureResult.CONTROL_AF_REGIONS,
+ new MeteringRectangle[0] /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_TRIGGER,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_MODE,
+ 0 /* don't care, must not be null */);
+ map.put(CaptureResult.CONTROL_AF_STATE,
+ 0 /* don't care, must not be null */);
+ }
+
+ // Filters out unsupported keys
+ List<CaptureResult.Key<?>> camera2SupportKeys=
+ mCameraCharacteristics.getAvailableCaptureResultKeys();
+ for (CaptureResult.Key key : new HashSet<>(map.keySet())) {
+ if (!camera2SupportKeys.contains(key)) {
+ map.remove(key);
+ }
+ }
+ return map;
+ }
+
+
+ private boolean isAfAutoSupported() {
+ int[] afModes = mCameraCharacteristics
+ .get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
+ if (afModes == null) {
+ return false;
+ }
+
+ for (int afMode : afModes) {
+ if (afMode == CameraCharacteristics.CONTROL_AF_MODE_AUTO) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureRequestKeys()
+ throws RemoteException {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(mCameraCharacteristics);
+ Map<CaptureRequest.Key, Object> keysmap = getSupportedCaptureRequestKeys();
+ for (CaptureRequest.Key key : keysmap.keySet()) {
+ cameraMetadataWrapper.set(key, keysmap.get(key));
+ }
+
+ return cameraMetadataWrapper;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureResultKeys()
+ throws RemoteException {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(mCameraCharacteristics);
+ Map<CaptureResult.Key, Object> keysmap = getSupportedCaptureResultKeys();
+ for (CaptureResult.Key key : keysmap.keySet()) {
+ cameraMetadataWrapper.set(key, keysmap.get(key));
+ }
+
+ return cameraMetadataWrapper;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java
new file mode 100644
index 00000000..c339ed98
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/CameraOutputConfigBuilder.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.annotation.NonNull;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.view.Surface;
+
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.Size;
+
+import java.util.ArrayList;
+
+public class CameraOutputConfigBuilder {
+ private final CameraOutputConfig mConfig;
+
+ private CameraOutputConfigBuilder(CameraOutputConfig config) {
+ mConfig = config;
+ mConfig.surfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE;
+ }
+
+ public static CameraOutputConfigBuilder createSurfaceOutput(
+ int outputId, @NonNull Surface surface) {
+ CameraOutputConfig config = new CameraOutputConfig();
+ config.type = CameraOutputConfig.TYPE_SURFACE;
+ config.outputId = outputId;
+ config.surface = surface;
+ return new CameraOutputConfigBuilder(config);
+ }
+
+ public static CameraOutputConfigBuilder createImageReaderOutput(
+ int outputId, int width, int height, int imageFormat, int maxImages) {
+ CameraOutputConfig config = new CameraOutputConfig();
+ config.type = CameraOutputConfig.TYPE_IMAGEREADER;
+ config.outputId = outputId;
+ config.size = new Size();
+ config.size.width = width;
+ config.size.height = height;
+ config.imageFormat = imageFormat;
+ config.capacity = maxImages;
+ return new CameraOutputConfigBuilder(config);
+ }
+
+ public CameraOutputConfigBuilder setPhysicalCameraId(String physicalCameraId) {
+ mConfig.physicalCameraId = physicalCameraId;
+ return this;
+ }
+
+ public CameraOutputConfigBuilder setSurfaceGroupId(int surfaceGroupId) {
+ mConfig.surfaceGroupId = surfaceGroupId;
+ return this;
+ }
+
+ public CameraOutputConfigBuilder addSharedOutputConfig(CameraOutputConfig cameraOutputConfig) {
+ if (mConfig.sharedSurfaceConfigs == null) {
+ mConfig.sharedSurfaceConfigs = new ArrayList<>();
+ }
+ mConfig.sharedSurfaceConfigs.add(cameraOutputConfig);
+ return this;
+ }
+
+ public CameraOutputConfig build() {
+ CameraOutputConfig result = new CameraOutputConfig();
+ result.outputId = mConfig.outputId;
+ result.type = mConfig.type;
+ result.surface = mConfig.surface;
+ result.physicalCameraId = mConfig.physicalCameraId;
+ result.surfaceGroupId = mConfig.surfaceGroupId;
+ result.capacity = mConfig.capacity;
+ result.imageFormat = mConfig.imageFormat;
+ if (mConfig.size != null) {
+ result.size = new Size();
+ result.size.width = mConfig.size.width;
+ result.size.height = mConfig.size.height;
+ }
+ if (mConfig.sharedSurfaceConfigs != null) {
+ result.sharedSurfaceConfigs = new ArrayList<>(mConfig.sharedSurfaceConfigs);
+ }
+ return result;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java
new file mode 100644
index 00000000..3a279716
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ExtensionsService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.camera.extensions.impl.PreviewExtenderImpl;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.IExtensionsService;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+import androidx.camera.extensions.impl.service.IImageCaptureExtenderImpl;
+import androidx.camera.extensions.impl.service.IPreviewExtenderImpl;
+
+public class ExtensionsService extends Service {
+ private static final String TAG = "ExtensionsService";
+
+ public ExtensionsService() {
+ }
+
+ @Override
+ @NonNull
+ public IBinder onBind(Intent intent) {
+ return new ExtensionsServiceStub();
+ }
+
+ class ExtensionsServiceStub extends IExtensionsService.Stub {
+ @Override
+ public boolean isAdvancedExtenderImplemented() throws RemoteException {
+ return true;
+ }
+
+ @Override
+ public void initialize(String version, IOnExtensionsInitializedCallback callback)
+ throws RemoteException {
+ Log.d(TAG, "initialize");
+ callback.onSuccess();
+ }
+
+ @Override
+ public void deInitialize(IOnExtensionsDeinitializedCallback callback)
+ throws RemoteException {
+ Log.d(TAG, "deInitialize");
+ callback.onSuccess();
+ }
+
+ @Override
+ public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType)
+ throws RemoteException {
+ Log.d(TAG, "initializeAdvancedExtension");
+ return new AdvancedExtenderImplStub(ExtensionsService.this, extensionType);
+ }
+
+ @Override
+ public IPreviewExtenderImpl initializePreviewExtension(int extensionType) {
+ return new PreviewExtenderImplStub(ExtensionsService.this, extensionType);
+ }
+
+ @Override
+ public IImageCaptureExtenderImpl initializeImageCaptureExtension(int extensionType) {
+ return new ImageCaptureExtenderImplStub(ExtensionsService.this, extensionType);
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ImageCaptureExtenderImplStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ImageCaptureExtenderImplStub.java
new file mode 100644
index 00000000..75cd99c9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/ImageCaptureExtenderImplStub.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.content.Context;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CaptureBundle;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import androidx.camera.extensions.impl.service.ICaptureProcessorImpl;
+import androidx.camera.extensions.impl.service.IImageCaptureExtenderImpl;
+import androidx.camera.extensions.impl.service.IProcessResultImpl;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.Size;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+public class ImageCaptureExtenderImplStub extends IImageCaptureExtenderImpl.Stub {
+ private static final String TAG = "ImageCaptureExtenderImplStub";
+
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_SHADE;
+
+ private final Context mContext;
+ private final List<CaptureResult.Key> mResultKeyList = Arrays.asList(
+ CaptureResult.CONTROL_AE_MODE,
+ CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER,
+ CaptureResult.CONTROL_AE_LOCK,
+ CaptureResult.CONTROL_AE_STATE,
+ CaptureResult.FLASH_MODE,
+ CaptureResult.FLASH_STATE,
+ CaptureResult.JPEG_QUALITY,
+ CaptureResult.JPEG_ORIENTATION
+ );
+
+ private CameraCharacteristics mCameraCharacteristics;
+ ICaptureProcessorImpl mCaptureProcessor =
+ new ICaptureProcessorImpl.Stub() {
+ private ImageWriter mImageWriter;
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ mImageWriter = ImageWriter.newInstance(surface, 1);
+ }
+
+ @Override
+ public void process(List<CaptureBundle> captureList,
+ IProcessResultImpl resultCallback) {
+ CaptureBundle captureBundle = captureList.get(0);
+ TotalCaptureResult captureResult =
+ captureBundle.captureResult.toTotalCaptureResult();
+
+ if (resultCallback != null) {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(mCameraCharacteristics);
+ Long shutterTimestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (shutterTimestamp != null) {
+ for (CaptureResult.Key key : mResultKeyList) {
+ if (captureResult.get(key) != null) {
+ cameraMetadataWrapper.set(key, captureResult.get(key));
+ }
+ }
+ try {
+ resultCallback.onCaptureCompleted(shutterTimestamp,
+ cameraMetadataWrapper);
+ } catch (RemoteException e) {
+
+ }
+ }
+ }
+ Image image = mImageWriter.dequeueInputImage();
+
+ // Do processing here
+ ByteBuffer yByteBuffer = image.getPlanes()[0].getBuffer();
+ ByteBuffer uByteBuffer = image.getPlanes()[2].getBuffer();
+ ByteBuffer vByteBuffer = image.getPlanes()[1].getBuffer();
+
+ Image captureImage = captureBundle.captureImage.get();
+
+ // Sample here just simply copy/paste the capture image result
+ yByteBuffer.put(captureImage.getPlanes()[0].getBuffer());
+ uByteBuffer.put(captureImage.getPlanes()[2].getBuffer());
+ vByteBuffer.put(captureImage.getPlanes()[1].getBuffer());
+ Long sensorTimestamp =
+ captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (sensorTimestamp != null) {
+ image.setTimestamp(sensorTimestamp);
+ } else {
+ Log.e(TAG, "Sensor timestamp absent using default!");
+ }
+
+ mImageWriter.queueInputImage(image);
+
+ for (CaptureBundle bundle : captureList) {
+ bundle.captureImage.decrement();
+ }
+ }
+
+ @Override
+ public void onResolutionUpdate(androidx.camera.extensions.impl.service.Size size) {
+
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+
+ }
+ };
+
+ public ImageCaptureExtenderImplStub(@NonNull Context context, int extensionType) {
+ mContext = context;
+
+ }
+
+ @Override
+ public void onInit(String cameraId) {
+
+ }
+
+ @Override
+ public void onDeInit() {
+
+ }
+
+ @Override
+ @Nullable
+ public CaptureStageImplWrapper onPresetSession() {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public CaptureStageImplWrapper onEnableSession() {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public CaptureStageImplWrapper onDisableSession() {
+ return null;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId) {
+ return true;
+ }
+
+ @Override
+ public void init(String cameraId) {
+ try {
+ CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
+ mCameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Cannot get CameraCharacteristics", e);
+ }
+
+ }
+
+ @Override
+ public ICaptureProcessorImpl getCaptureProcessor() {
+ return mCaptureProcessor;
+ }
+
+ @Override
+ public List<CaptureStageImplWrapper> getCaptureStages() {
+ CaptureStageImplWrapper captureStage = new CaptureStageImplWrapper();
+ captureStage.id = DEFAULT_STAGE_ID;
+ captureStage.parameters = new CameraMetadataWrapper(mCameraCharacteristics);
+ return Arrays.asList(captureStage);
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ return 1;
+ }
+
+ @Override
+ public List<SizeList> getSupportedResolutions() {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public LatencyRange getEstimatedCaptureLatencyRange(Size outputSize) {
+ return null;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureRequestKeys() {
+ return null;
+ }
+
+ @Override
+ public CameraMetadataWrapper getAvailableCaptureResultKeys() {
+ return null;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/PreviewExtenderImplStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/PreviewExtenderImplStub.java
new file mode 100644
index 00000000..c9add1c7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/PreviewExtenderImplStub.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.content.Context;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.media.ImageWriter;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import androidx.camera.extensions.impl.service.IPreviewExtenderImpl;
+import androidx.camera.extensions.impl.service.IPreviewImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IProcessResultImpl;
+import androidx.camera.extensions.impl.service.IRequestUpdateProcessorImpl;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+import androidx.camera.extensions.impl.service.SizeList;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.List;
+
+public class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub {
+ private static final String TAG = "PreviewExtenderImplStub";
+
+ private static final int DEFAULT_STAGE_ID = 0;
+ private static final int SESSION_STAGE_ID = 101;
+ private static final int MODE = CaptureRequest.CONTROL_AWB_MODE_SHADE;
+ private final int mProcessorType;
+ private final Context mContext;
+ private CaptureStageImplWrapper mCaptureStage;
+ private CameraCharacteristics mCameraCharacteristics;
+ private final SimplePreviewImageProcessor mPreviewImageProcessor;
+ private final SimpleRequestUpdateProcessor mRequestUpdateProcessor;
+
+ public PreviewExtenderImplStub(@NonNull Context context, int extensionType) {
+ mContext = context;
+ switch (extensionType) {
+ case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
+ case CameraExtensionCharacteristics.EXTENSION_BOKEH:
+ mRequestUpdateProcessor = new SimpleRequestUpdateProcessor();
+ mPreviewImageProcessor = null;
+ mProcessorType = IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
+ break;
+ case CameraExtensionCharacteristics.EXTENSION_HDR:
+ case CameraExtensionCharacteristics.EXTENSION_NIGHT:
+ mRequestUpdateProcessor = null;
+ mPreviewImageProcessor = new SimplePreviewImageProcessor();
+ mProcessorType = IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR;
+ break;
+ case CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH:
+ default:
+ mRequestUpdateProcessor = null;
+ mPreviewImageProcessor = null;
+ mProcessorType = IPreviewExtenderImpl.PROCESSOR_TYPE_NONE;
+ break;
+ }
+ }
+
+ private class SimpleRequestUpdateProcessor extends IRequestUpdateProcessorImpl.Stub {
+ private int mFrameCount = 0;
+ private Integer mWBMode = CaptureRequest.CONTROL_AWB_MODE_AUTO;
+
+ @Override
+ public CaptureStageImplWrapper process(TotalCaptureResultWrapper result) {
+ mFrameCount++;
+ if (mFrameCount % 90 == 0) {
+ mCaptureStage = new CaptureStageImplWrapper();
+ mCaptureStage.id = DEFAULT_STAGE_ID;
+ switch (mWBMode) {
+ case CaptureRequest.CONTROL_AWB_MODE_AUTO:
+ mWBMode = MODE;
+ break;
+ case MODE:
+ mWBMode = CaptureRequest.CONTROL_AWB_MODE_AUTO;
+ break; default:
+ }
+ mCaptureStage.parameters = new CameraMetadataWrapper(
+ mCameraCharacteristics);
+ mCaptureStage.parameters.set(CaptureRequest.CONTROL_AWB_MODE,
+ mWBMode);
+ mFrameCount = 0;
+
+ return mCaptureStage;
+ }
+ return null;
+ }
+ };
+ private static class SimplePreviewImageProcessor extends IPreviewImageProcessorImpl.Stub {
+ private ImageWriter mWriter;
+
+ public void close() {
+ if (mWriter != null) {
+ mWriter.close();
+ }
+ }
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ mWriter = ImageWriter.newInstance(surface, imageFormat);
+ }
+
+ @Override
+ public void onResolutionUpdate(
+ androidx.camera.extensions.impl.service.Size size) {
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+ }
+
+ @Override
+ public void process(ImageWrapper image, TotalCaptureResultWrapper result,
+ IProcessResultImpl resultCallback) {
+ mWriter.queueInputImage(image.get());
+ image.decrement();
+ }
+ }
+
+ @Override
+ public void onInit(String cameraId) {
+
+ }
+
+ @Override
+ public void onDeInit() {
+ if (mPreviewImageProcessor != null) {
+ mPreviewImageProcessor.close();
+ }
+ }
+
+ @Override
+ @Nullable
+ public CaptureStageImplWrapper onPresetSession() {
+ CaptureStageImplWrapper captureStage = new CaptureStageImplWrapper();
+ captureStage.id = SESSION_STAGE_ID;
+ captureStage.parameters = new CameraMetadataWrapper(mCameraCharacteristics);
+ captureStage.parameters.set(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ return captureStage;
+ }
+
+ @Override
+ @Nullable
+ public CaptureStageImplWrapper onEnableSession() {
+ CaptureStageImplWrapper captureStage = new CaptureStageImplWrapper();
+ captureStage.id = SESSION_STAGE_ID;
+ captureStage.parameters = new CameraMetadataWrapper(mCameraCharacteristics);
+ captureStage.parameters.set(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ return captureStage;
+ }
+
+ @Override
+ @Nullable
+ public CaptureStageImplWrapper onDisableSession() {
+ CaptureStageImplWrapper captureStage = new CaptureStageImplWrapper();
+ captureStage.id = SESSION_STAGE_ID;
+ captureStage.parameters = new CameraMetadataWrapper(mCameraCharacteristics);
+ captureStage.parameters.set(CaptureRequest.CONTROL_AWB_MODE, MODE);
+ return captureStage;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId) {
+ return true;
+ }
+
+ @Override
+ public void init(String cameraId) {
+ try {
+ CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
+ mCameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Cannot get CameraCharacteristics", e);
+ }
+
+ mCaptureStage = new CaptureStageImplWrapper();
+ mCaptureStage.id = DEFAULT_STAGE_ID;
+ mCaptureStage.parameters = new CameraMetadataWrapper(mCameraCharacteristics);
+ mCaptureStage.parameters.set(CaptureRequest.CONTROL_AWB_MODE,
+ CaptureRequest.CONTROL_AWB_MODE_AUTO);
+ }
+
+ @Override
+ public CaptureStageImplWrapper getCaptureStage() {
+ return mCaptureStage;
+ }
+
+ @Override
+ public int getProcessorType() {
+ return mProcessorType;
+ }
+
+ @Override
+ @Nullable
+ public IPreviewImageProcessorImpl getPreviewImageProcessor() {
+ return mPreviewImageProcessor;
+ }
+
+ @Override
+ @Nullable
+ public IRequestUpdateProcessorImpl getRequestUpdateProcessor() {
+ return mRequestUpdateProcessor;
+ }
+
+ @Override
+ @Nullable
+ public List<SizeList> getSupportedResolutions() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java
new file mode 100644
index 00000000..52bb26b4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/RequestBuilder.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.Request;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class RequestBuilder {
+ private static final AtomicInteger sNextRequestId = new AtomicInteger(0);
+ private final List<Integer> mTargetOutputConfigIds = new ArrayList<>();
+ private final CameraMetadataWrapper mParameters;
+ private int mTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ private final int mRequestId = 0;
+
+ public RequestBuilder(CameraCharacteristics cameraCharacteristics) {
+ mParameters = new CameraMetadataWrapper(cameraCharacteristics);
+ }
+
+ public RequestBuilder addTargetOutputConfigId(int... outputConfigIds) {
+ for (int id : outputConfigIds) {
+ mTargetOutputConfigIds.add(id);
+ }
+ return this;
+ }
+
+ public <T> RequestBuilder setParameter(CaptureRequest.Key<T> key, T value) {
+ mParameters.set(key, value);
+ return this;
+ }
+
+ public RequestBuilder setTemplateId(int templateId) {
+ mTemplateId = templateId;
+ return this;
+ }
+
+ public Request build() {
+ Request request = new Request();
+ int[] idArray = new int[mTargetOutputConfigIds.size()];
+ for (int i = 0; i < idArray.length; i++) {
+ idArray[i] = mTargetOutputConfigIds.get(i);
+ }
+ request.targetOutputConfigIds = idArray;
+ request.requestId = mRequestId;
+ request.parameters = mParameters;
+ request.templateId = mTemplateId;
+ request.requestId = sNextRequestId.getAndIncrement();
+ return request;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java
new file mode 100644
index 00000000..ed749aec
--- /dev/null
+++ b/camera2/extensions/service_based_sample/extensions_service/src/com/android/oemextensions/SimpleSessionProcessorStub.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.oemextensions;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.OutputSurface;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Demonstrates a very simple SessionProcessor which just pass all the output surface into the
+ * camera pipeline directly. No postprocessing is performed.
+ */
+public class SimpleSessionProcessorStub extends ISessionProcessorImpl.Stub {
+ private static final String TAG = "SimpleSessionProcessor";
+ private final CameraCharacteristics mCameraCharacteristics;
+ private final Set<CaptureRequest.Key> mSupportedRequestKeys;
+ private final Set<CaptureResult.Key> mSupportedResultKeys;
+
+ private IRequestProcessorImpl mIRequestProcessor;
+ private AtomicInteger mNextCaptureSequenceId = new AtomicInteger(1);
+ private Map<CaptureRequest.Key, Object> mParameters = new HashMap<>();
+ private boolean mHasAnalysisOutput = false;
+
+ private static final int PREVIEW_OUTPUT_ID = 1;
+ private static final int CAPTURE_OUTPUT_ID = 2;
+ private static final int ANALYSIS_OUTPUT_ID = 3;
+
+ public SimpleSessionProcessorStub(@NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Set<CaptureRequest.Key> supportedRequestKeys,
+ @NonNull Set<CaptureResult.Key> supportedResultKeys) {
+ mCameraCharacteristics = cameraCharacteristics;
+ mSupportedRequestKeys = supportedRequestKeys;
+ mSupportedResultKeys = supportedResultKeys;
+ }
+
+ @Override
+ public CameraSessionConfig initSession(@NonNull String cameraId,
+ @NonNull OutputSurface outputSurfacePreview,
+ @NonNull OutputSurface outputSurfaceStillCapture,
+ @Nullable OutputSurface outputSurfaceAnalysis) throws RemoteException {
+ Log.d(TAG, "initSession cameraId=" + cameraId);
+ CameraSessionConfig cameraSessionConfig = new CameraSessionConfig();
+ cameraSessionConfig.sessionParameter = new CameraMetadataWrapper(mCameraCharacteristics);
+ // if needed, invoke cameraSessionConfig.sessionParameter.set(...) to set session parameters
+ cameraSessionConfig.sessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ List<CameraOutputConfig> outputConfigList = new ArrayList<>();
+
+ // Preview
+ CameraOutputConfig previewOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(PREVIEW_OUTPUT_ID, outputSurfacePreview.surface)
+ .build();
+ outputConfigList.add(previewOutputConfig);
+
+ // Still capture
+ CameraOutputConfig captureOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(CAPTURE_OUTPUT_ID, outputSurfaceStillCapture.surface)
+ .build();
+ outputConfigList.add(captureOutputConfig);
+
+ // ImageAnalysis
+ if (outputSurfaceAnalysis != null) {
+ mHasAnalysisOutput = true;
+ CameraOutputConfig analysisOutputConfig =
+ CameraOutputConfigBuilder
+ .createSurfaceOutput(ANALYSIS_OUTPUT_ID, outputSurfaceAnalysis.surface)
+ .build();
+ outputConfigList.add(analysisOutputConfig);
+ }
+
+ cameraSessionConfig.outputConfigs = outputConfigList;
+ return cameraSessionConfig;
+ }
+
+ @Override
+ public void deInitSession() throws RemoteException {
+ Log.d(TAG, "deInitSession");
+ }
+
+ @Override
+ public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor)
+ throws RemoteException {
+ Log.d(TAG, "onCaptureSessionStart");
+ mIRequestProcessor = requestProcessor;
+ }
+
+ @Override
+ public void onCaptureSessionEnd() throws RemoteException {
+ Log.d(TAG, "onCaptureSessionEnd");
+
+ mIRequestProcessor = null;
+ }
+
+ @Override
+ public void setParameters(CaptureRequest captureRequest) throws RemoteException {
+ Log.d(TAG, "setParameters");
+
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ if (mSupportedRequestKeys.contains(key)) {
+ mParameters.put(key, captureRequest.get(key));
+ }
+ }
+ }
+
+ protected void notifyOnCaptureCompleted(
+ @NonNull int seqId,
+ @NonNull TotalCaptureResult result,
+ @NonNull ICaptureCallback captureCallback) {
+ Long shutterTimestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (shutterTimestamp != null) {
+ CameraMetadataWrapper cameraMetadataWrapper =
+ new CameraMetadataWrapper(mCameraCharacteristics);
+
+ for (CaptureResult.Key key : mSupportedResultKeys) {
+ if (result.get(key) != null) {
+ cameraMetadataWrapper.set(key, result.get(key));
+ }
+ }
+
+ try {
+ captureCallback.onCaptureCompleted(shutterTimestamp, seqId,
+ cameraMetadataWrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot notify onCaptureCompleted", e);
+ }
+ }
+ }
+
+ @Override
+ public int startTrigger(CaptureRequest captureRequest, ICaptureCallback captureCallback)
+ throws RemoteException {
+ Log.d(TAG, "startTrigger");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(PREVIEW_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+
+ if (mHasAnalysisOutput) {
+ requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID);
+ }
+ applyParameters(requestBuilder);
+
+ for (CaptureRequest.Key key : captureRequest.getKeys()) {
+ if (mSupportedRequestKeys.contains(key)) {
+ requestBuilder.setParameter(key, captureRequest.get(key));
+ } else {
+ Log.e(TAG, "startTrigger: key " + key + " not supported");
+ }
+ }
+
+ mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult)
+ throws RemoteException {
+ CaptureResult captureResult = partialResult.toCaptureResult();
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResult) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure();
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+ }
+ });
+ return captureSequenceId;
+ }
+
+ private void applyParameters(RequestBuilder requestBuilder) {
+ for (CaptureRequest.Key key : mParameters.keySet()) {
+ requestBuilder.setParameter(key, mParameters.get(key));
+ }
+ }
+
+ @Override
+ public int startRepeating(ICaptureCallback captureCallback) throws RemoteException {
+ Log.d(TAG, "startRepeating");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(PREVIEW_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_PREVIEW);
+ if (mHasAnalysisOutput) {
+ requestBuilder.addTargetOutputConfigId(ANALYSIS_OUTPUT_ID);
+ }
+ applyParameters(requestBuilder);
+
+ mIRequestProcessor.setRepeating(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId, CaptureResultWrapper partialResult)
+ throws RemoteException {
+ CaptureResult captureResult = partialResult.toCaptureResult();
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResult) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResult.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ CaptureFailure captureFailure = captureFailureWrapper.toCaptureFailure();
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+ }
+ });
+ return captureSequenceId;
+ }
+
+ @Override
+ public void stopRepeating() throws RemoteException {
+ Log.d(TAG, "stopRepeating");
+
+ mIRequestProcessor.stopRepeating();
+ }
+
+ @Override
+ public int startCapture(ICaptureCallback captureCallback) throws RemoteException {
+ Log.d(TAG, "startCapture");
+
+ int captureSequenceId = mNextCaptureSequenceId.getAndIncrement();
+
+ RequestBuilder requestBuilder = new RequestBuilder(mCameraCharacteristics)
+ .addTargetOutputConfigId(CAPTURE_OUTPUT_ID)
+ .setTemplateId(CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+ applyParameters(requestBuilder);
+
+ mIRequestProcessor.submit(requestBuilder.build(), new IRequestCallback.Stub() {
+ @Override
+ public void onCaptureStarted(int requestId, long frameNumber, long timestamp)
+ throws RemoteException {
+ captureCallback.onCaptureStarted(captureSequenceId, timestamp);
+ }
+
+ @Override
+ public void onCaptureProgressed(int requestId,
+ CaptureResultWrapper captureResultWrapper)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onCaptureCompleted(int requestId,
+ TotalCaptureResultWrapper totalCaptureResultWrapper) throws RemoteException {
+ TotalCaptureResult captureResult = totalCaptureResultWrapper.toTotalCaptureResult();
+ captureCallback.onCaptureProcessStarted(captureSequenceId);
+ notifyOnCaptureCompleted(captureSequenceId, captureResult, captureCallback);
+ }
+
+ @Override
+ public void onCaptureFailed(int requestId, CaptureFailureWrapper captureFailureWrapper)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId)
+ throws RemoteException {
+ captureCallback.onCaptureFailed(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber)
+ throws RemoteException {
+ captureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) throws RemoteException {
+ captureCallback.onCaptureSequenceAborted(captureSequenceId);
+
+ }
+ });
+ return captureSequenceId;
+ }
+
+ @Override
+ public void abortCapture(int i) throws RemoteException {
+ Log.d(TAG, "abortCapture");
+ mIRequestProcessor.abortCaptures();
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/Android.bp b/camera2/extensions/service_based_sample/oem_library/Android.bp
new file mode 100644
index 00000000..adfb1b51
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "service_based_camera_extensions",
+ installable: true,
+ srcs: [
+ "src/java/**/*.java",
+ "src/java/**/*.aidl",
+ ],
+ static_libs: [
+ "androidx.annotation_annotation",
+ ],
+ aidl: {
+ local_include_dirs: ["src/java"],
+ include_dirs: [
+ "frameworks/native/aidl/gui", // For SurfaceView AIDL
+ "frameworks/av/camera/aidl", // For CaptureRequest AIDL
+ ]
+ },
+ system_ext_specific: true,
+ platform_apis: true,
+}
+
+prebuilt_etc {
+ name: "service_based_camera_extensions.xml",
+ src: "service_based_camera_extensions.xml",
+ sub_dir: "permissions",
+ system_ext_specific: true,
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml b/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml
new file mode 100644
index 00000000..54b5b10a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="androidx.camera.extensions.impl" >
+</manifest>
diff --git a/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml b/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml
new file mode 100644
index 00000000..6501b9b4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/service_based_camera_extensions.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <library name="androidx.camera.extensions.impl"
+ file="/system_ext/framework/service_based_camera_extensions.jar"/>
+</permissions>
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..55486a3c
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardImageCaptureExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for auto image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class AutoImageCaptureExtenderImpl extends ForwardImageCaptureExtender {
+ public AutoImageCaptureExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_AUTOMATIC);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
new file mode 100755
index 00000000..94b8808a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardPreviewExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for auto preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class AutoPreviewExtenderImpl extends ForwardPreviewExtender {
+ public AutoPreviewExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_AUTOMATIC);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..ce9e9ea1
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardImageCaptureExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for beauty image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BeautyImageCaptureExtenderImpl extends ForwardImageCaptureExtender {
+ public BeautyImageCaptureExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
new file mode 100755
index 00000000..0a452c33
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardPreviewExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for beauty preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BeautyPreviewExtenderImpl extends ForwardPreviewExtender {
+ public BeautyPreviewExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_FACE_RETOUCH);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..f24e9f1d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardImageCaptureExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for bokeh image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BokehImageCaptureExtenderImpl extends ForwardImageCaptureExtender {
+ public BokehImageCaptureExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_BOKEH);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
new file mode 100644
index 00000000..e17d9415
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardPreviewExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for bokeh preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class BokehPreviewExtenderImpl extends ForwardPreviewExtender {
+ public BokehPreviewExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_BOKEH);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
new file mode 100644
index 00000000..3eee146a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.util.Pair;
+import android.view.Surface;
+
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * The interface for processing a set of {@link Image}s that have captured.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface CaptureProcessorImpl extends ProcessorImpl {
+ /**
+ * Process a set images captured that were requested.
+ *
+ * <p> The result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata to
+ * process. The {@link Image} that are contained within the map will become
+ * invalid after this method completes, so no references to them should be kept.
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
+
+ /**
+ * Process a set images captured that were requested.
+ *
+ * <p> The result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and metadata
+ * to process. The {@link Image} that are contained within the map will
+ * become invalid after this method completes, so no references to them
+ * should be kept.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback will
+ * run on any arbitrary executor.
+ * @since 1.3
+ */
+ void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
new file mode 100644
index 00000000..c4f4a47d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.hardware.camera2.CaptureRequest;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * The set of parameters that defines a single capture that will be sent to the camera.
+ *
+ * @since 1.0
+ */
+public interface CaptureStageImpl {
+ /** Returns the identifier for the {@link CaptureStageImpl}. */
+ int getId();
+
+ /**
+ * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be
+ * set for a single {@link CaptureRequest}.
+ */
+ @NonNull
+ List<Pair<CaptureRequest.Key, Object>> getParameters();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
new file mode 100644
index 00000000..a74a8804
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Provides interfaces that the OEM needs to implement to handle the state change.
+ *
+ * @since 1.0
+ */
+public interface ExtenderStateListener {
+
+ /**
+ * Notify to initialize the extension. This will be called after bindToLifeCycle. This is
+ * where the use case is started and would be able to allocate resources here. After onInit() is
+ * called, the camera ID, cameraCharacteristics and context will not change until onDeInit()
+ * has been called.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @param context The {@link Context} used for CameraX.
+ */
+ void onInit(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics,
+ @NonNull Context context);
+
+ /**
+ * Notify to de-initialize the extension. This callback will be invoked after unbind.
+ * After onDeInit() was called, it is expected that the camera ID, cameraCharacteristics will
+ * no longer hold, this should be where to clear all resources allocated for this use case.
+ */
+ void onDeInit();
+
+ /**
+ * This will be invoked before creating a
+ * {@link CameraCaptureSession}. The {@link CaptureRequest}
+ * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as
+ * part of the capture session initialization via
+ * {@link SessionConfiguration#setSessionParameters(CaptureRequest)} which only supported from
+ * API level 28. The valid parameter is a subset of the available capture request parameters.
+ *
+ * @return The request information to set the session wide camera parameters.
+ */
+ @Nullable
+ CaptureStageImpl onPresetSession();
+
+ /**
+ * This will be invoked once after the {@link CameraCaptureSession}
+ * has been created. The {@link CaptureRequest} parameters returned via
+ * {@link CaptureStageImpl} will be used to generate a single request to the current
+ * configured {@link CameraDevice}. The generated request will be submitted to camera before
+ * processing other single requests.
+ *
+ * @return The request information to create a single capture request to camera device.
+ */
+ @Nullable
+ CaptureStageImpl onEnableSession();
+
+ /**
+ * This will be invoked before the {@link CameraCaptureSession} is
+ * closed. The {@link CaptureRequest} parameters returned via {@link CaptureStageImpl} will
+ * be used to generate a single request to the currently configured {@link CameraDevice}. The
+ * generated request will be submitted to camera before the CameraCaptureSession is closed.
+ *
+ * @return The request information to customize the session.
+ */
+ @Nullable
+ CaptureStageImpl onDisableSession();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
new file mode 100644
index 00000000..cc357b1a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Stub implementation for the extension version check.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public class ExtensionVersionImpl {
+ public ExtensionVersionImpl() {
+ }
+
+ /**
+ * Provide the current CameraX extension library version to vendor library and vendor would
+ * need to return the supported version for this device. If the returned version is not
+ * supported by CameraX library, the Preview and ImageCapture would not be able to enable the
+ * specific effects provided by the vendor.
+ *
+ * <p>CameraX library provides the Semantic Versioning string in a form of
+ * MAJOR.MINOR.PATCH-description
+ * We will increment the
+ * MAJOR version when make incompatible API changes,
+ * MINOR version when add functionality in a backwards-compatible manner, and
+ * PATCH version when make backwards-compatible bug fixes. And the description can be ignored.
+ *
+ * <p>Vendor library should provide MAJOR.MINOR.PATCH to CameraX. The MAJOR and MINOR
+ * version is used to map to the version of CameraX that it supports, and CameraX extension
+ * would only available when MAJOR version is matched with CameraX current version. The PATCH
+ * version does not indicate compatibility. The patch version should be incremented whenever
+ * the vendor library makes bug fixes or updates to the algorithm.
+ *
+ * @param version the version of CameraX library formatted as MAJOR.MINOR.PATCH-description.
+ * @return the version that vendor supported in this device. The MAJOR.MINOR.PATCH format
+ * should be used.
+ */
+ @SuppressWarnings("unused")
+ @NonNull
+ public String checkApiVersion(@NonNull String version) {
+ // This sample implements Extensions-Interface 1.3.0.
+ return "1.3.0";
+ }
+
+ /**
+ * Specify whether or not CameraX should invoke the AdvancedExtenderImpl instead of
+ * PreviewExtenderImpl/ImageCaptureExtenderImpl.
+ *
+ * <p>Starting from version 1.2, a set of alternative interfaces called advanced extender for
+ * implementing extensions are provided to OEMs as another option. OEMs can continue using
+ * previous interfaces (PreviewExtenderImpl/ImageCaptureExtenderImpl, also called basic
+ * extender).
+ *
+ * <p>OEMs should return false here if only basic extender is implemented. When returning true,
+ * CameraX will invoke the AdvancedExtenderImpl implementation in advanced package for all
+ * types of extension modes.
+ *
+ * <p>ExtensionVersionImpl, InitializerImpl will still be called for both basic and advanced
+ * extender implementation paths.
+ *
+ * @return true if AdvancedExtenderImpl is implemented
+ * @since 1.2
+ */
+ public boolean isAdvancedExtenderImplemented() {
+ return true;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..264a714e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardImageCaptureExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for HDR image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class HdrImageCaptureExtenderImpl extends ForwardImageCaptureExtender {
+ public HdrImageCaptureExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_HDR);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
new file mode 100644
index 00000000..8e7bbd85
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardPreviewExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for HDR preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class HdrPreviewExtenderImpl extends ForwardPreviewExtender {
+ public HdrPreviewExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_HDR);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
new file mode 100644
index 00000000..10b45134
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions for image capture.
+ *
+ * @since 1.0
+ */
+public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable(String, CameraCharacteristics)}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ */
+ void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The processing that will be done on a set of captures to create and image with the effect.
+ */
+ @Nullable
+ CaptureProcessorImpl getCaptureProcessor();
+
+ /** The set of captures that are needed to create an image with the effect. */
+ @Nullable
+ List<CaptureStageImpl> getCaptureStages();
+
+ /**
+ * Returns the maximum size of the list returned by {@link #getCaptureStages()}.
+ * @return the maximum count.
+ */
+ int getMaxCaptureStage();
+
+ /**
+ * Returns the customized supported resolutions.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link StreamConfigurationMap} for the camera device. If the
+ * returned list is not null, it will be used to find the best resolutions combination for
+ * the bound use cases.
+ *
+ * @return the customized supported resolutions, or null to support all sizes retrieved from
+ * {@link StreamConfigurationMap}.
+ * @since 1.1
+ */
+ @Nullable
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+
+ /**
+ * Returns the estimated capture latency range in milliseconds for the target capture
+ * resolution.
+ *
+ * <p>This includes the time spent processing the multi-frame capture request along with any
+ * additional time for encoding of the processed buffer in the framework if necessary.</p>
+ *
+ * @param captureOutputSize size of the capture output surface. If it is null or not in the
+ * supported output sizes, maximum capture output size is used for
+ * the estimation.
+ * @return the range of estimated minimal and maximal capture latency in milliseconds, or
+ * null if no capture latency info can be provided.
+ * @since 1.2
+ */
+ @Nullable
+ Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize);
+
+ /**
+ * Return a list of orthogonal capture request keys.
+ *
+ * <p>Any keys included in the list will be configurable by clients of the extension and will
+ * affect the extension functionality.</p>
+ *
+ * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p>
+ *
+ * <p>Also note that the keys {@link CaptureRequest#JPEG_QUALITY} and
+ * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the
+ * list or not. To support common camera operations like zoom, tap-to-focus, flash and
+ * exposure compensation, we recommend supporting the following keys if possible.
+ * <pre>
+ * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO}
+ * {@link CaptureRequest#SCALER_CROP_REGION}
+ * tap-to-focus:
+ * {@link CaptureRequest#CONTROL_AF_MODE}
+ * {@link CaptureRequest#CONTROL_AF_TRIGGER}
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}
+ * {@link CaptureRequest#CONTROL_AE_REGIONS}
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS}
+ * flash:
+ * {@link CaptureRequest#CONTROL_AE_MODE}
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
+ * {@link CaptureRequest#FLASH_MODE}
+ * exposure compensation:
+ * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
+ * </pre>
+ * On basic extensions that implement 1.2 or prior version, the above keys are all supported
+ * explicitly. When migrating from 1.2 or prior to 1.3, please note that both CameraX and
+ * Camera2 will honor the returned list and support only the keys contained in it. For
+ * example, if OEM decides to return only {@link CaptureRequest#CONTROL_ZOOM_RATIO} and
+ * {@link CaptureRequest#SCALER_CROP_REGION} in the 1.3 implementation, it means only zoom is
+ * supported for the app while tap-to-focus , flash and exposure compensation are not allowed.
+ *
+ * @return List of supported orthogonal capture keys, or an empty list if no capture settings
+ * are not supported.
+ * @since 1.3
+ */
+ @NonNull
+ List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
+
+ /**
+ * Return a list of supported capture result keys.
+ *
+ * <p>Any keys included in this list must be available as part of the registered
+ * {@link ProcessResultImpl} callback. In case frame processing is not supported,
+ * then the Camera2/CameraX framework will use the list to filter and notify camera clients
+ * using the respective camera results.</p>
+ *
+ * <p>At the very minimum, it is expected that the result key list is a superset of the
+ * capture request keys.</p>
+ *
+ * <p>Do note that the list of keys applies to {@link PreviewExtenderImpl} as well.</p>
+ *
+ * @return List of supported capture result keys, or an empty list if capture results are not
+ * supported.
+ * @since 1.3
+ */
+ @NonNull
+ List<CaptureResult.Key> getAvailableCaptureResultKeys();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java
new file mode 100644
index 00000000..5a9f0ffc
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/InitializerImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ServiceManager;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Used for initializing the extensions library.
+ *
+ * @since 1.1
+ */
+public class InitializerImpl {
+ private InitializerImpl() {
+ }
+
+ /** An unknown error has occurred. */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /**
+ * Error reported if the application version of extensions is incompatible with the on device
+ * library version.
+ */
+ public static final int ERROR_INITIALIZE_VERSION_INCOMPATIBLE = 1;
+
+ /**
+ * Initializes the {@link Context}.
+ *
+ * <p>Before this call has been made no calls to the extensions library should be made except
+ * for {@link ExtensionVersionImpl#checkApiVersion(String)}.
+ *
+ * @param version The version of the extension used by the application.
+ * @param context The {@link Context} of the calling application.
+ * @param executor The executor to run the callback on. If null then the callback will run on
+ * any arbitrary executor.
+ */
+ public static void init(@NonNull String version, @NonNull Context context,
+ @NonNull OnExtensionsInitializedCallback callback, @Nullable Executor executor) {
+ ServiceManager.init(context, version, callback, executor);
+ }
+
+ /**
+ * Deinitializes the extensions to release resources.
+ *
+ * <p>After this call has been made no calls to the extensions library should be made except
+ * for {@link ExtensionVersionImpl#checkApiVersion(String)}.
+ *
+ * @param executor The executor to run the callback on. If null then the callback will run on
+ * any arbitrary executor.
+ */
+ public static void deinit(@NonNull OnExtensionsDeinitializedCallback callback,
+ @Nullable Executor executor) {
+ ServiceManager.getInstance().deinit(callback, executor);
+ }
+
+ /**
+ * Callback that gets called when the library has finished initializing and is ready for used.
+ */
+ public interface OnExtensionsInitializedCallback {
+ /** Called if the library successfully initializes. */
+ void onSuccess();
+
+ /**
+ * Called if the library is unable to successfully initialize.
+ *
+ * @param error The reason for failing to initialize.
+ */
+ void onFailure(int error);
+ }
+
+ /**
+ * Callback that gets called when the library has finished deinitialized.
+ *
+ * <p> Once this interface has been called then
+ * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} can be called
+ * again regardless of whether or not the deinitialization has succeeded or failed.
+ */
+ public interface OnExtensionsDeinitializedCallback {
+ /**
+ * Called if the library successfully deinitializes.
+ */
+ void onSuccess();
+
+ /**
+ * Called if the library encountered some error during the deinitialization.
+ *
+ * <p>Even if the library fails to deinitialize it is now valid for
+ * {@link #init(String, Context, OnExtensionsInitializedCallback, Executor)} to be called
+ * again.
+ *
+ * @param error The reason for failing to deinitialize.
+ */
+ void onFailure(int error);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
new file mode 100755
index 00000000..36c554fb
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardImageCaptureExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for night image capture use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class NightImageCaptureExtenderImpl extends ForwardImageCaptureExtender {
+ public NightImageCaptureExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_NIGHT);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
new file mode 100755
index 00000000..973e79cf
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.serviceforward.ForwardPreviewExtender;
+
+import java.util.List;
+
+/**
+ * Stub implementation for night preview use case.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.0
+ */
+public final class NightPreviewExtenderImpl extends ForwardPreviewExtender {
+ public NightPreviewExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_NIGHT);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
new file mode 100644
index 00000000..b3208137
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.util.Pair;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides abstract methods that the OEM needs to implement to enable extensions in the preview.
+ *
+ * @since 1.0
+ */
+public interface PreviewExtenderImpl extends ExtenderStateListener {
+ /** The different types of the preview processing. */
+ enum ProcessorType {
+ /** Processor which only updates the {@link CaptureStageImpl}. */
+ PROCESSOR_TYPE_REQUEST_UPDATE_ONLY,
+ /** Processor which updates the received {@link android.media.Image}. */
+ PROCESSOR_TYPE_IMAGE_PROCESSOR,
+ /** No processor, only a {@link CaptureStageImpl} is defined. */
+ PROCESSOR_TYPE_NONE
+ }
+
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable(String, CameraCharacteristics)}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
+ */
+ void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
+
+ /**
+ * The set of parameters required to produce the effect on the preview stream.
+ *
+ * <p> This will be the initial set of parameters used for the preview
+ * {@link CaptureRequest}. If the {@link ProcessorType} is defined as
+ * {@link ProcessorType#PROCESSOR_TYPE_REQUEST_UPDATE_ONLY} then this will be updated when
+ * the {@link RequestUpdateProcessorImpl#process(TotalCaptureResult)} from {@link
+ * #getProcessor()} has been called, this should be updated to reflect the new {@link
+ * CaptureStageImpl}. If the processing step returns a {@code null}, meaning the required
+ * parameters has not changed, then calling this will return the previous non-null value.
+ */
+ @NonNull
+ CaptureStageImpl getCaptureStage();
+
+ /** The type of preview processing to use. */
+ @NonNull
+ ProcessorType getProcessorType();
+
+ /**
+ * Returns a processor which only updates the {@link CaptureStageImpl}.
+ *
+ * <p>The type of processor is dependent on the return of {@link #getProcessorType()}. The
+ * type of ProcessorImpl returned will be according to the following table.
+ *
+ * <table>
+ * <tr><th> ProcessorType </th> <th> ProcessorImpl </th> </tr>
+ * <tr><td> PROCESSOR_TYPE_REQUEST_UPDATE_ONLY </td> <td> RequestUpdateProcessorImpl </td> </tr>
+ * <tr><td> PROCESSOR_TYPE_IMAGE_PROCESSOR </td> <td> PreviewImageProcessorImpl </td> </tr>
+ * <tr><td> PROCESSOR_TYPE_NONE </td> <td> null </td> </tr>
+ * </table>
+ */
+ @Nullable
+ ProcessorImpl getProcessor();
+
+ /**
+ * Returns the customized supported resolutions.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the
+ * returned list is not null, it will be used to find the best resolutions combination for
+ * the bound use cases.
+ *
+ * @return the customized supported resolutions.
+ * @since 1.1
+ */
+ @Nullable
+ List<Pair<Integer, Size[]>> getSupportedResolutions();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
new file mode 100644
index 00000000..f203ebad
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Processes a single {@link Image} and {@link TotalCaptureResult} to produce an output to a
+ * stream.
+ *
+ * @since 1.0
+ */
+@SuppressLint("UnknownNullness")
+public interface PreviewImageProcessorImpl extends ProcessorImpl {
+ /**
+ * Processes the requested image capture.
+ *
+ * <p> The result of the processing step should be written to the {@link android.view.Surface}
+ * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}.
+ *
+ * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will be
+ * invalid after the method completes so no reference to it should be kept.
+ * @param result The metadata associated with the image to process.
+ */
+ void process(Image image, TotalCaptureResult result);
+
+ /**
+ * Processes the requested image capture.
+ *
+ * <p> The result of the processing step should be written to the {@link android.view.Surface}
+ * that was received by {@link ProcessorImpl#onOutputSurface(android.view.Surface, int)}.
+ *
+ * @param image The {@link ImageFormat#YUV_420_888} format image to process. This will
+ * be invalid after the method completes so no reference to it should be
+ * kept.
+ * @param result The metadata associated with the image to process.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback will
+ * run on any arbitrary executor.
+ * @since 1.3
+ */
+ void process(Image image, TotalCaptureResult result, ProcessResultImpl resultCallback,
+ Executor executor);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
new file mode 100644
index 00000000..d0e3605d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessResultImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
+
+import java.util.List;
+
+/**
+ * Allows clients to receive information about the capture result values of processed frames.
+ *
+ * @since 1.3
+ */
+@SuppressLint("UnknownNullness")
+public interface ProcessResultImpl {
+ /**
+ * Capture result callback that needs to be called when the process capture results are
+ * ready as part of frame post-processing.
+ *
+ * @param shutterTimestamp The shutter time stamp of the processed frame.
+ * @param result Key value pairs for all supported capture results. Do note that
+ * if results 'android.jpeg.quality' and 'android.jpeg.orientation'
+ * are present in the process capture input results, then the values
+ * must also be passed as part of this callback. Both Camera2 and
+ * CameraX guarantee that those two settings and results are always
+ * supported and applied by the corresponding framework.
+ */
+ void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
new file mode 100644
index 00000000..e5ca19e9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Processes an input image stream and produces an output image stream.
+ *
+ * @since 1.0
+ */
+public interface ProcessorImpl {
+ /**
+ * Updates where the ProcessorImpl should write the output to.
+ *
+ * @param surface The {@link Surface} that the ProcessorImpl should write data into.
+ * @param imageFormat The format of that the surface expects.
+ */
+ void onOutputSurface(@NonNull Surface surface, int imageFormat);
+
+ /**
+ * Invoked when CameraX changes the configured output resolution.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any
+ * {@link android.media.Image} received as input to be at the specified resolution.
+ *
+ * @param size for the surface.
+ */
+ void onResolutionUpdate(@NonNull Size size);
+
+ /**
+ * Invoked when CameraX changes the configured input image format.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any
+ * {@link android.media.Image} received as input to have the specified image format.
+ *
+ * @param imageFormat for the surface.
+ */
+ void onImageFormatUpdate(int imageFormat);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
new file mode 100644
index 00000000..ac3bfb3e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl;
+
+import android.hardware.camera2.TotalCaptureResult;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Processes a {@link TotalCaptureResult} to update a CaptureStage.
+ *
+ * @since 1.0
+ */
+public interface RequestUpdateProcessorImpl extends ProcessorImpl {
+ /**
+ * Process the {@link TotalCaptureResult} to update the {@link CaptureStageImpl}
+ *
+ * @param result The metadata associated with the image. Can be null if the image and meta have
+ * not been synced.
+ * @return The updated parameters used for the repeating requests. If this is {@code null} then
+ * the previous parameters will be used.
+ */
+ @Nullable
+ CaptureStageImpl process(@Nullable TotalCaptureResult result);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
new file mode 100644
index 00000000..465bfe88
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.camera.extensions.impl.ExtensionVersionImpl;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Advanced OEM contract for implementing Extensions. ImageCapture/Preview Extensions are both
+ * implemented on this interface.
+ *
+ * <p>This advanced OEM contract empowers OEM to gain access to more Camera2 capability. This
+ * includes: (1) Add custom surfaces with specific formats like YUV, RAW, RAW_DEPTH. (2) Access to
+ * the capture request callbacks as well as all the images retrieved of various image formats. (3)
+ * Able to triggers single or repeating request with the capabilities to specify target surfaces,
+ * template id and parameters.
+ *
+ * <p>OEM needs to implement it with class name HdrAdvancedExtenderImpl for HDR,
+ * NightAdvancedExtenderImpl for night mode, BeautyAdvancedExtenderImpl for beauty mode,
+ * BokehAdvancedExtenderImpl for bokeh mode and AutoAdvancedExtenderImpl for auto mode.
+ *
+ * <p>OEMs are required to return true in
+ * {@link ExtensionVersionImpl#isAdvancedExtenderImplemented()} in order to request CameraX to
+ * use advanced extender over basic extender. OEM is okay to implement advanced
+ * extender only Or basic extender only. However the caveat of advanced-only implementation is,
+ * extensions will be unavailable on the apps using interfaces prior to 1.2.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public interface AdvancedExtenderImpl {
+
+ /**
+ * Indicates whether the extension is supported on the device.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param characteristicsMap A map consisting of the camera ids and the
+ * {@link CameraCharacteristics}s. For every camera, the map
+ * contains at least the CameraCharacteristics for the camera id.
+ * If the camera is logical camera, it will also contain associated
+ * physical camera ids and their CameraCharacteristics.
+ * @return true if the extension is supported, otherwise false
+ */
+ boolean isExtensionAvailable(String cameraId,
+ Map<String, CameraCharacteristics> characteristicsMap);
+
+ /**
+ * Initializes the extender to be used with the specified camera.
+ *
+ * <p>This should be called before any other method on the extender. The exception is {@link
+ * #isExtensionAvailable}.
+ *
+ * @param cameraId The camera2 id string of the camera.
+ * @param characteristicsMap A map consisting of the camera ids and the
+ * {@link CameraCharacteristics}s. For every camera, the map
+ * contains at least the CameraCharacteristics for the camera id.
+ * If the camera is logical camera, it will also contain associated
+ * physical camera ids and their CameraCharacteristics.
+ */
+ void init(String cameraId, Map<String, CameraCharacteristics> characteristicsMap);
+
+ /**
+ * Returns the estimated capture latency range in milliseconds for the
+ * target capture resolution during the calls to
+ * {@link SessionProcessorImpl#startCapture}. This
+ * includes the time spent processing the multi-frame capture request along with any additional
+ * time for encoding of the processed buffer in the framework if necessary.
+ *
+ * @param cameraId the camera id
+ * @param captureOutputSize size of the capture output surface. If it is null or not in the
+ * supported output sizes, maximum capture output size is used for
+ * the estimation.
+ * @param imageFormat the image format of the capture output surface.
+ * @return the range of estimated minimal and maximal capture latency in milliseconds.
+ * Returns null if no capture latency info can be provided.
+ */
+ Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
+ Size captureOutputSize, int imageFormat);
+
+ /**
+ * Returns supported output format/size map for preview. The format could be PRIVATE or
+ * YUV_420_888. OEM must support PRIVATE format at least. CameraX will only use resolutions
+ * for preview from the list.
+ *
+ * <p>The preview surface format in the CameraCaptureSession may not be identical to the
+ * supported preview output format returned here. Like in the basic extender interface, the
+ * preview PRIVATE surface could be added to the CameraCaptureSession and OEM processes it in
+ * the HAL. Alternatively OEM can configure a intermediate YUV surface of the same size and
+ * writes the output to the preview output surface.
+ */
+ Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId);
+
+ /**
+ * Returns supported output format/size map for image capture. OEM is required to support
+ * both JPEG and YUV_420_888 format output.
+ *
+ * <p>Like in the basic extender interface, the surface created with this supported
+ * format/size could be either added in CameraCaptureSession with HAL processing OR it
+ * configures intermediate surfaces(YUV/RAW..) and writes the output to the output surface.
+ */
+ Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId);
+
+ /**
+ * Returns supported output sizes for Image Analysis (YUV_420_888 format).
+ *
+ * <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture
+ * output surfaces. If imageAnalysis YUV surface is not supported, OEM should return null or
+ * empty list.
+ */
+ List<Size> getSupportedYuvAnalysisResolutions(String cameraId);
+
+ /**
+ * Returns a processor for activating extension sessions. It implements all the interactions
+ * required for starting a extension and cleanup.
+ */
+ SessionProcessorImpl createSessionProcessor();
+
+ /**
+ * Returns a list of orthogonal capture request keys.
+ *
+ * <p>Any keys included in the list will be configurable by clients of the extension and will
+ * affect the extension functionality.</p>
+ *
+ * <p>Please note that the keys {@link CaptureRequest#JPEG_QUALITY} and
+ * {@link CaptureRequest#JPEG_ORIENTATION} are always supported regardless being added in the
+ * list or not. To support common camera operations like zoom, tap-to-focus, flash and
+ * exposure compensation, we recommend supporting the following keys if possible.
+ * <pre>
+ * zoom: {@link CaptureRequest#CONTROL_ZOOM_RATIO}
+ * {@link CaptureRequest#SCALER_CROP_REGION}
+ * tap-to-focus:
+ * {@link CaptureRequest#CONTROL_AF_MODE}
+ * {@link CaptureRequest#CONTROL_AF_TRIGGER}
+ * {@link CaptureRequest#CONTROL_AF_REGIONS}
+ * {@link CaptureRequest#CONTROL_AE_REGIONS}
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS}
+ * flash:
+ * {@link CaptureRequest#CONTROL_AE_MODE}
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER}
+ * {@link CaptureRequest#FLASH_MODE}
+ * exposure compensation:
+ * {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION}
+ * </pre>
+ *
+ * @return List of supported orthogonal capture keys, or an empty list if no capture settings
+ * are not supported.
+ * @since 1.3
+ */
+ List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
+
+ /**
+ * Returns a list of supported capture result keys.
+ *
+ * <p>Any keys included in this list must be available as part of the registered
+ * {@link SessionProcessorImpl.CaptureCallback#onCaptureCompleted} callback.</p>
+ *
+ * <p>At the very minimum, it is expected that the result key list is a superset of the
+ * capture request keys.</p>
+ *
+ * @return List of supported capture result keys, or
+ * an empty list if capture results are not supported.
+ * @since 1.3
+ */
+ List<CaptureResult.Key> getAvailableCaptureResultKeys();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
new file mode 100644
index 00000000..c67dc799
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for auto.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class AutoAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public AutoAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_AUTOMATIC);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
new file mode 100644
index 00000000..2e10e255
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for beauty.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class BeautyAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public BeautyAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_BEAUTY);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
new file mode 100644
index 00000000..ae55790b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for bokeh.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class BokehAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public BokehAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_BOKEH);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
new file mode 100644
index 00000000..68de01b6
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+import java.util.List;
+
+/**
+ * A config representing a {@link android.hardware.camera2.params.OutputConfiguration} where
+ * Surface will be created by the information in this config.
+ */
+@SuppressLint("UnknownNullness")
+public interface Camera2OutputConfigImpl {
+ /**
+ * Gets thd id of this output config. The id can be used to identify the stream in vendor
+ * implementations.
+ */
+ int getId();
+
+ /**
+ * Gets the surface group id. Vendor can use the surface group id to share memory between
+ * Surfaces.
+ */
+ int getSurfaceGroupId();
+
+ /**
+ * Gets the physical camera id. Returns null if not specified.
+ */
+ String getPhysicalCameraId();
+
+ /**
+ * If non-null, enable surface sharing and add the surface constructed by the return
+ * Camera2OutputConfig.
+ */
+ List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
new file mode 100644
index 00000000..718870f4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2OutputConfigImplBuilder.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A builder implementation to help OEM build the {@link Camera2OutputConfigImpl} instance.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2OutputConfigImplBuilder {
+ static AtomicInteger sLastId = new AtomicInteger(0);
+ private OutputConfigImplImpl mOutputConfig;
+ private int mSurfaceGroupId = OutputConfiguration.SURFACE_GROUP_ID_NONE;
+ private int mOutputConfigId = -1;
+ private String mPhysicalCameraId;
+ private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs;
+
+ private Camera2OutputConfigImplBuilder(OutputConfigImplImpl outputConfig) {
+ mOutputConfig = outputConfig;
+ }
+
+ private int getNextId() {
+ return sLastId.getAndIncrement();
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that represents a {@link android.media.ImageReader}
+ * with the given parameters.
+ */
+ public static Camera2OutputConfigImplBuilder newImageReaderConfig(
+ Size size, int imageFormat, int maxImages) {
+ return new Camera2OutputConfigImplBuilder(
+ new ImageReaderOutputConfigImplImpl(size, imageFormat, maxImages));
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that represents a MultiResolutionImageReader with
+ * the given parameters.
+ */
+ public static Camera2OutputConfigImplBuilder newMultiResolutionImageReaderConfig(
+ int imageFormat, int maxImages) {
+ return new Camera2OutputConfigImplBuilder(
+ new MultiResolutionImageReaderOutputConfigImplImpl(imageFormat, maxImages));
+ }
+
+ /**
+ * Creates a {@link Camera2OutputConfigImpl} that contains the Surface directly.
+ */
+ public static Camera2OutputConfigImplBuilder newSurfaceConfig(Surface surface) {
+ return new Camera2OutputConfigImplBuilder(new SurfaceOutputConfigImplImpl(surface));
+ }
+
+ /**
+ * Adds a {@link Camera2SessionConfigImpl} to be shared with current config.
+ */
+ public Camera2OutputConfigImplBuilder addSurfaceSharingOutputConfig(
+ Camera2OutputConfigImpl camera2OutputConfig) {
+ if (mSurfaceSharingConfigs == null) {
+ mSurfaceSharingConfigs = new ArrayList<>();
+ }
+
+ mSurfaceSharingConfigs.add(camera2OutputConfig);
+ return this;
+ }
+
+ /**
+ * Sets a physical camera id.
+ */
+ public Camera2OutputConfigImplBuilder setPhysicalCameraId(String physicalCameraId) {
+ mPhysicalCameraId = physicalCameraId;
+ return this;
+ }
+
+ /**
+ * Sets surface group id.
+ */
+ public Camera2OutputConfigImplBuilder setSurfaceGroupId(int surfaceGroupId) {
+ mSurfaceGroupId = surfaceGroupId;
+ return this;
+ }
+
+ /**
+ * Sets output config id.
+ */
+ public Camera2OutputConfigImplBuilder setOutputConfigId(int outputConfigId) {
+ mOutputConfigId = outputConfigId;
+ return this;
+ }
+
+
+ /**
+ * Build a {@link Camera2OutputConfigImpl} instance.
+ */
+ public Camera2OutputConfigImpl build() {
+ // Use the Atomic Integer if setOutputConfigId is never called
+ if(mOutputConfigId == -1) {
+ mOutputConfig.setId(getNextId());
+ }
+ else {
+ mOutputConfig.setId(mOutputConfigId);
+ }
+ mOutputConfig.setPhysicalCameraId(mPhysicalCameraId);
+ mOutputConfig.setSurfaceGroup(mSurfaceGroupId);
+ mOutputConfig.setSurfaceSharingConfigs(mSurfaceSharingConfigs);
+ return mOutputConfig;
+ }
+
+ private static class OutputConfigImplImpl implements Camera2OutputConfigImpl {
+ private int mId;
+ private int mSurfaceGroup;
+ private String mPhysicalCameraId;
+ private List<Camera2OutputConfigImpl> mSurfaceSharingConfigs;
+
+ OutputConfigImplImpl() {
+ mId = -1;
+ mSurfaceGroup = 0;
+ mPhysicalCameraId = null;
+ mSurfaceSharingConfigs = null;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public int getSurfaceGroupId() {
+ return mSurfaceGroup;
+ }
+
+ @Override
+ public String getPhysicalCameraId() {
+ return mPhysicalCameraId;
+ }
+
+ @Override
+ public List<Camera2OutputConfigImpl> getSurfaceSharingOutputConfigs() {
+ return mSurfaceSharingConfigs;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
+
+ public void setSurfaceGroup(int surfaceGroup) {
+ mSurfaceGroup = surfaceGroup;
+ }
+
+ public void setPhysicalCameraId(String physicalCameraId) {
+ mPhysicalCameraId = physicalCameraId;
+ }
+
+ public void setSurfaceSharingConfigs(
+ List<Camera2OutputConfigImpl> surfaceSharingConfigs) {
+ mSurfaceSharingConfigs = surfaceSharingConfigs;
+ }
+ }
+
+ private static class SurfaceOutputConfigImplImpl extends OutputConfigImplImpl
+ implements SurfaceOutputConfigImpl {
+ private Surface mSurface;
+
+ SurfaceOutputConfigImplImpl(Surface surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ public Surface getSurface() {
+ return mSurface;
+ }
+ }
+
+ private static class ImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
+ implements ImageReaderOutputConfigImpl {
+ private Size mSize;
+ private int mImageFormat;
+ private int mMaxImages;
+
+ ImageReaderOutputConfigImplImpl(Size size, int imageFormat, int maxImages) {
+ mSize = size;
+ mImageFormat = imageFormat;
+ mMaxImages = maxImages;
+ }
+
+ @Override
+ public Size getSize() {
+ return mSize;
+ }
+
+ @Override
+ public int getImageFormat() {
+ return mImageFormat;
+ }
+
+ @Override
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+ }
+
+ private static class MultiResolutionImageReaderOutputConfigImplImpl extends OutputConfigImplImpl
+ implements MultiResolutionImageReaderOutputConfigImpl {
+ private int mImageFormat;
+ private int mMaxImages;
+
+ MultiResolutionImageReaderOutputConfigImplImpl(int imageFormat, int maxImages) {
+ mImageFormat = imageFormat;
+ mMaxImages = maxImages;
+ }
+
+ @Override
+ public int getImageFormat() {
+ return mImageFormat;
+ }
+
+ @Override
+ public int getMaxImages() {
+ return mMaxImages;
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
new file mode 100644
index 00000000..d1217177
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureRequest;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A config representing a {@link android.hardware.camera2.params.SessionConfiguration}
+ */
+@SuppressLint("UnknownNullness")
+public interface Camera2SessionConfigImpl {
+ /**
+ * Returns all the {@link Camera2OutputConfigImpl}s that will be used to create
+ * {@link android.hardware.camera2.params.OutputConfiguration}.
+ */
+ List<Camera2OutputConfigImpl> getOutputConfigs();
+
+ /**
+ * Gets all the parameters to create the session parameters with.
+ */
+ Map<CaptureRequest.Key<?>, Object> getSessionParameters();
+
+ /**
+ * Gets the template id used for creating {@link CaptureRequest}s to be passed in
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}.
+ */
+ int getSessionTemplateId();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
new file mode 100644
index 00000000..a3011666
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A builder implementation to help OEM build the {@link Camera2SessionConfigImpl} instance.
+ */
+@SuppressLint("UnknownNullness")
+public class Camera2SessionConfigImplBuilder {
+ private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>();
+ List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>();
+
+ public Camera2SessionConfigImplBuilder() {
+ }
+
+ /**
+ * Adds a output config.
+ */
+ public Camera2SessionConfigImplBuilder addOutputConfig(
+ Camera2OutputConfigImpl outputConfig) {
+ mCamera2OutputConfigs.add(outputConfig);
+ return this;
+ }
+
+ /**
+ * Sets session parameters.
+ */
+ public <T> Camera2SessionConfigImplBuilder addSessionParameter(
+ CaptureRequest.Key<T> key, T value) {
+ mSessionParameters.put(key, value);
+ return this;
+ }
+
+ /**
+ * Sets the template id for session parameters request.
+ */
+ public Camera2SessionConfigImplBuilder setSessionTemplateId(int templateId) {
+ mSessionTemplateId = templateId;
+ return this;
+ }
+
+ /**
+ * Gets the session template id.
+ */
+ public int getSessionTemplateId() {
+ return mSessionTemplateId;
+ }
+
+ /**
+ * Gets the session parameters.
+ */
+ public Map<CaptureRequest.Key<?>, Object> getSessionParameters() {
+ return mSessionParameters;
+ }
+
+ /**
+ * Gets all the output configs.
+ */
+ public List<Camera2OutputConfigImpl> getCamera2OutputConfigs() {
+ return mCamera2OutputConfigs;
+ }
+
+ /**
+ * Builds a {@link Camera2SessionConfigImpl} instance.
+ */
+ public Camera2SessionConfigImpl build() {
+ return new Camera2SessionConfigImplImpl(this);
+ }
+
+ private static class Camera2SessionConfigImplImpl implements
+ Camera2SessionConfigImpl {
+ int mSessionTemplateId;
+ Map<CaptureRequest.Key<?>, Object> mSessionParameters;
+ List<Camera2OutputConfigImpl> mCamera2OutputConfigs;
+
+ Camera2SessionConfigImplImpl(Camera2SessionConfigImplBuilder builder) {
+ mSessionTemplateId = builder.getSessionTemplateId();
+ mSessionParameters = builder.getSessionParameters();
+ mCamera2OutputConfigs = builder.getCamera2OutputConfigs();
+ }
+
+ @Override
+ public List<Camera2OutputConfigImpl> getOutputConfigs() {
+ return mCamera2OutputConfigs;
+ }
+
+ @Override
+ public Map<CaptureRequest.Key<?>, Object> getSessionParameters() {
+ return mSessionParameters;
+ }
+
+ @Override
+ public int getSessionTemplateId() {
+ return mSessionTemplateId;
+ }
+ }
+}
+
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
new file mode 100644
index 00000000..e7dbb7d8
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for hdr.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class HdrAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public HdrAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_HDR);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
new file mode 100644
index 00000000..037e9479
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+/**
+ * A interface to receive and process the upcoming next available Image.
+ *
+ * <p>Implemented by OEM.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageProcessorImpl {
+ /**
+ * The reference count will not be decremented when this method returns. Extensions must
+ * decrement it when the image is no longer needed.
+ *
+ * <p>If OEM is not closing(decrement) the image fast enough, the imageReference passed
+ * in this method might contain null image meaning that the Image was closed to prevent
+ * preview from stalling.
+ *
+ * @param outputConfigId the id of {@link Camera2OutputConfigImpl} which identifies
+ * corresponding Surface
+ * @param timestampNs the timestamp in nanoseconds associated with this image
+ * @param imageReference A reference to the {@link android.media.Image} which might contain
+ * null if OEM close(decrement) the image too slowly
+ * @param physicalCameraId used to distinguish which physical camera id the image comes from
+ * when the output configuration is
+ * MultiResolutionImageReaderOutputConfigImpl. It is also set if
+ * physicalCameraId is set in other Camera2OutputConfigImpl types.
+ *
+ */
+ void onNextImageAvailable(
+ int outputConfigId,
+ long timestampNs,
+ ImageReferenceImpl imageReference,
+ String physicalCameraId
+ );
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
new file mode 100644
index 00000000..ca4dcafa
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReaderOutputConfigImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.util.Size;
+
+/**
+ * Surface will be created by constructing a ImageReader.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageReaderOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Returns the size of the surface.
+ */
+ Size getSize();
+
+ /**
+ * Gets the image format of the surface.
+ */
+ int getImageFormat();
+
+ /**
+ * Gets the capacity for TYPE_IMAGEREADER.
+ */
+ int getMaxImages();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
new file mode 100644
index 00000000..95f2c3b9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/ImageReferenceImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.media.Image;
+
+/**
+ * A Image reference container that enables the Image sharing between Camera2/CameraX and OEM
+ * using reference counting. The wrapped Image will be closed once the reference count
+ * reaches 0.
+ *
+ * <p>Implemented by Camera2/CameraX.
+ */
+@SuppressLint("UnknownNullness")
+public interface ImageReferenceImpl {
+
+ /**
+ * Increment the reference count. Returns true if the value was incremented.
+ * (returns false if the reference count has already reached zero.)
+ */
+ boolean increment();
+
+ /**
+ * Decrement the reference count. Image will be closed if reference count reaches 0.
+ * Returns true if the value was decremented (returns false if the reference count has
+ * already reached zero)
+ */
+ boolean decrement();
+
+ /**
+ * Return the Android image. This object MUST not be closed directly.
+ * Returns null when the reference count is zero.
+ */
+ Image get();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
new file mode 100644
index 00000000..c3ad61bc
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/MultiResolutionImageReaderOutputConfigImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+/**
+ * Surface will be created by constructing a MultiResolutionImageReader.
+ */
+public interface MultiResolutionImageReaderOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Gets the image format of the surface.
+ */
+ int getImageFormat();
+
+ /**
+ * Gets the max images of the ImageReader.
+ */
+ int getMaxImages();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
new file mode 100644
index 00000000..be298443
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+
+import androidx.camera.extensions.impl.serviceforward.ForwardAdvancedExtender;
+
+/**
+ * Stub advanced extender implementation for night.
+ *
+ * <p>This class should be implemented by OEM and deployed to the target devices.
+ *
+ * @since 1.2
+ */
+@SuppressLint("UnknownNullness")
+public class NightAdvancedExtenderImpl extends ForwardAdvancedExtender {
+ public NightAdvancedExtenderImpl() {
+ super(CameraExtensionCharacteristics.EXTENSION_NIGHT);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
new file mode 100644
index 00000000..f6920296
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/OutputSurfaceImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.util.Size;
+import android.view.Surface;
+
+/**
+ * For specifying output surface of the extension.
+ */
+@SuppressLint("UnknownNullness")
+public interface OutputSurfaceImpl {
+ /**
+ * Gets the surface.
+ */
+ Surface getSurface();
+
+ /**
+ * Gets the size.
+ */
+ Size getSize();
+
+ /**
+ * Gets the image format.
+ */
+ int getImageFormat();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
new file mode 100644
index 00000000..51853334
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/RequestProcessorImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An Interface to execute Camera2 capture requests.
+ */
+@SuppressLint("UnknownNullness")
+public interface RequestProcessorImpl {
+ /**
+ * Sets a {@link ImageProcessorImpl} to receive {@link ImageReferenceImpl} to process.
+ */
+ void setImageProcessor(int outputconfigId, ImageProcessorImpl imageProcessor);
+
+ /**
+ * Submits a request.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int submit(Request request, Callback callback);
+
+ /**
+ * Submits a list of requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int submit(List<Request> requests, Callback callback);
+
+ /**
+ * Set repeating requests.
+ * @return the id of the capture sequence or -1 in case the processor encounters a fatal error
+ * or receives an invalid argument.
+ */
+ int setRepeating(Request request, Callback callback);
+
+
+ /**
+ * Abort captures.
+ */
+ void abortCaptures();
+
+ /**
+ * Stop Repeating.
+ */
+ void stopRepeating();
+
+ /**
+ * A interface representing a capture request configuration used for submitting requests in
+ * {@link RequestProcessorImpl}.
+ */
+ interface Request {
+ /**
+ * Gets the target ids of {@link Camera2OutputConfigImpl} which identifies corresponding
+ * Surface to be the targeted for the request.
+ */
+ List<Integer> getTargetOutputConfigIds();
+
+ /**
+ * Gets all the parameters.
+ */
+ Map<CaptureRequest.Key<?>, Object> getParameters();
+
+ /**
+ * Gets the template id.
+ */
+ Integer getTemplateId();
+ }
+
+ /**
+ * Callback to be invoked during the capture.
+ */
+ interface Callback {
+ void onCaptureStarted(
+ Request request,
+ long frameNumber,
+ long timestamp);
+
+ void onCaptureProgressed(
+ Request request,
+ CaptureResult partialResult);
+
+ void onCaptureCompleted(
+ Request request,
+ TotalCaptureResult totalCaptureResult);
+
+ void onCaptureFailed(
+ Request request,
+ CaptureFailure captureFailure);
+
+ void onCaptureBufferLost(
+ Request request,
+ long frameNumber,
+ int outputStreamId);
+
+ void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+
+ void onCaptureSequenceAborted(int sequenceId);
+
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
new file mode 100644
index 00000000..fabfc2bf
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.view.Surface;
+
+import java.util.Map;
+
+/**
+ * Interface for creating Camera2 CameraCaptureSessions with extension enabled based on
+ * advanced vendor implementation.
+ *
+ * <p><pre>
+ * The flow of a extension session is shown below:
+ * (1) {@link #initSession}: CameraX prepares streams configuration for creating
+ * CameraCaptureSession. Output surfaces for Preview, ImageCapture and ImageAnalysis are passed
+ * in and vendor is responsible for outputting the results to these surfaces.
+ *
+ * (2) {@link #onCaptureSessionStart}: It is called after CameraCaptureSession is configured.
+ * A {@link RequestProcessorImpl} is passed for vendor to send repeating requests and
+ * single requests.
+ *
+ * (3) {@link #startRepeating}: CameraX will call this method to start the repeating request
+ * after CameraCaptureSession is called. Vendor should start the repeating request by
+ * {@link RequestProcessorImpl}. Vendor can also update the repeating request if needed later.
+ *
+ * (4) {@link #setParameters(Map)}: The passed parameters will be attached to the repeating request
+ * and single requests but vendor can choose to apply some of them only.
+ *
+ * (5) {@link #startCapture(CaptureCallback)}: It is called when apps want to
+ * start a multi-frame image capture. {@link CaptureCallback} will be called
+ * to report the status and the output image will be written to the capture output surface
+ * specified in {@link #initSession}.
+ *
+ * (5) {@link #onCaptureSessionEnd}: It is called right BEFORE CameraCaptureSession.close() is
+ * called.
+ *
+ * (6) {@link #deInitSession}: called when CameraCaptureSession is closed.
+ * </pre>
+ */
+@SuppressLint("UnknownNullness")
+public interface SessionProcessorImpl {
+ /**
+ * Initializes the session for the extension. This is where the OEMs allocate resources for
+ * preparing a CameraCaptureSession. After initSession() is called, the camera ID,
+ * cameraCharacteristics and context will not change until deInitSession() has been called.
+ *
+ * <p>CameraX specifies the output surface configurations for preview, image capture and image
+ * analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which consists of a
+ * list of {@link Camera2OutputConfigImpl} and session parameters. The
+ * {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession.
+ *
+ * <p>OEM is responsible for outputting correct camera images output to these output surfaces.
+ * OEM can have the following options to enable the output:
+ * <pre>
+ * (1) Add these output surfaces in CameraCaptureSession directly using
+ * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in
+ * HAL.
+ *
+ * (2) Use surface sharing with other surface by calling
+ * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)}
+ * to add the output surface to the other {@link Camera2OutputConfigImpl}.
+ *
+ * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output
+ * surface. The output surface won't be contained in the returned
+ * {@link Camera2SessionConfigImpl}.
+ * </pre>
+ *
+ * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder}
+ * implementations are provided in the stub for OEM to construct the
+ * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances.
+ *
+ * @param previewSurfaceConfig output surface for preview
+ * @param imageCaptureSurfaceConfig output surface for image capture.
+ * @param imageAnalysisSurfaceConfig an optional output config for image analysis
+ * (YUV_420_888).
+ * @return a {@link Camera2SessionConfigImpl} consisting of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters which will decide the
+ * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the
+ * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any
+ * supported or mandatory stream combination BUT OEM must ensure this list will always
+ * produce a valid camera capture session.
+ */
+ Camera2SessionConfigImpl initSession(
+ String cameraId,
+ Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ Context context,
+ OutputSurfaceImpl previewSurfaceConfig,
+ OutputSurfaceImpl imageCaptureSurfaceConfig,
+ OutputSurfaceImpl imageAnalysisSurfaceConfig);
+
+ /**
+ * Notify to de-initialize the extension. This callback will be invoked after
+ * CameraCaptureSession is closed. After onDeInit() was called, it is expected that the
+ * camera ID, cameraCharacteristics will no longer hold and tear down any resources allocated
+ * for this extension. Aborts all pending captures.
+ */
+ void deInitSession();
+
+ /**
+ * CameraX / Camera2 would call these API’s to pass parameters from the app to the OEM. It’s
+ * expected that the OEM would (eventually) update the repeating request if the keys are
+ * supported. Setting a value to null explicitly un-sets the value.
+ */
+ void setParameters(Map<CaptureRequest.Key<?>, Object> parameters);
+
+ /**
+ * CameraX / Camera2 will call this interface in response to client requests involving
+ * the output preview surface. Typical examples include requests that include AF/AE triggers.
+ * Extensions can disregard any capture request keys that were not advertised in
+ * {@link AdvancedExtenderImpl#getAvailableCaptureRequestKeys}.
+ *
+ * @param triggers Capture request key value map.
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ *
+ * @throws IllegalArgumentException If there are no valid settings that can be applied
+ *
+ * @since 1.3
+ */
+ int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback);
+
+ /**
+ * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession}
+ * has been created. {@link RequestProcessorImpl} is passed for OEM to submit single
+ * requests or set repeating requests. This ExtensionRequestProcessor will be valid to use
+ * until onCaptureSessionEnd is called.
+ */
+ void onCaptureSessionStart(RequestProcessorImpl requestProcessor);
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * closed. {@link RequestProcessorImpl} passed in onCaptureSessionStart will no longer
+ * accept any requests after onCaptureSessionEnd() returns.
+ */
+ void onCaptureSessionEnd();
+
+ /**
+ * Starts the repeating request after CameraCaptureSession is called. Vendor should start the
+ * repeating request by {@link RequestProcessorImpl}. Vendor can also update the
+ * repeating request when needed later.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ */
+ int startRepeating(CaptureCallback callback);
+
+ /**
+ * Stop the repeating request. To prevent OEM from not calling stopRepeating, CameraX will
+ * first stop the repeating request of current CameraCaptureSession and call this API to signal
+ * OEM that the repeating request was stopped and going forward calling
+ * {@link RequestProcessorImpl#setRepeating} will simply do nothing.
+ */
+ void stopRepeating();
+
+ /**
+ * Start a multi-frame capture.
+ *
+ * When the capture is completed, {@link CaptureCallback#onCaptureSequenceCompleted}
+ * is called and {@code OnImageAvailableListener#onImageAvailable}
+ * will also be called on the ImageReader that creates the image capture output surface.
+ *
+ * <p>Only one capture can perform at a time. Starting a capture when another capture is running
+ * will cause onCaptureFailed to be called immediately.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ */
+ int startCapture(CaptureCallback callback);
+
+ /**
+ * Abort all capture tasks.
+ */
+ void abortCapture(int captureSequenceId);
+
+ /**
+ * Callback for notifying the status of {@link #startCapture(CaptureCallback)} and
+ * {@link #startRepeating(CaptureCallback)}.
+ */
+ interface CaptureCallback {
+ /**
+ * This method is called when the camera device has started capturing the initial input
+ * image.
+ *
+ * For a multi-frame capture, the method is called when the
+ * CameraCaptureSession.CaptureCallback onCaptureStarted of first frame is called and its
+ * timestamp is directly forwarded to timestamp parameter of
+ * this method.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ * @param timestamp the timestamp at start of capture for repeating
+ * request or the timestamp at start of capture of the
+ * first frame in a multi-frame capture, in nanoseconds.
+ */
+ void onCaptureStarted(int captureSequenceId, long timestamp);
+
+ /**
+ * This method is called when an image (or images in case of multi-frame
+ * capture) is captured and device-specific extension processing is triggered.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureProcessStarted(int captureSequenceId);
+
+ /**
+ * This method is called instead of
+ * {@link #onCaptureProcessStarted} when the camera device failed
+ * to produce the required input for the device-specific extension. The
+ * cause could be a failed camera capture request, a failed
+ * capture result or dropped camera frame.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureFailed(int captureSequenceId);
+
+ /**
+ * This method is called independently of the others in the CaptureCallback, when a capture
+ * sequence finishes.
+ *
+ * <p>In total, there will be at least one
+ * {@link #onCaptureProcessStarted}/{@link #onCaptureFailed}
+ * invocation before this callback is triggered. If the capture
+ * sequence is aborted before any requests have begun processing,
+ * {@link #onCaptureSequenceAborted} is invoked instead.</p>
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceCompleted(int captureSequenceId);
+
+ /**
+ * This method is called when a capture sequence aborts.
+ *
+ * @param captureSequenceId id of the current capture sequence
+ */
+ void onCaptureSequenceAborted(int captureSequenceId);
+
+ /**
+ * Capture result callback that needs to be called when the process capture results are
+ * ready as part of frame post-processing.
+ *
+ * This callback will fire after {@link #onCaptureStarted}, {@link #onCaptureProcessStarted}
+ * and before {@link #onCaptureSequenceCompleted}. The callback is not expected to fire
+ * in case of capture failure {@link #onCaptureFailed} or capture abort
+ * {@link #onCaptureSequenceAborted}.
+ *
+ * @param timestamp The timestamp at start of capture. The same timestamp value
+ * passed to {@link #onCaptureStarted}.
+ * @param captureSequenceId the capture id of the request that generated the capture
+ * results. This is the return value of either
+ * {@link #startRepeating} or {@link #startCapture}.
+ * @param result Map containing the supported capture results. Do note
+ * that if results 'android.jpeg.quality' and
+ * 'android.jpeg.orientation' are present in the process
+ * capture input results, then the values must also be passed
+ * as part of this callback. Both Camera2 and CameraX guarantee
+ * that those two settings and results are always supported and
+ * applied by the corresponding framework.
+ */
+ void onCaptureCompleted(long timestamp, int captureSequenceId,
+ Map<CaptureResult.Key, Object> result);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
new file mode 100644
index 00000000..7b8d83c1
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/advanced/SurfaceOutputConfigImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+import android.view.Surface;
+
+/**
+ * Use Surface directly to create the OutputConfiguration.
+ */
+@SuppressLint("UnknownNullness")
+public interface SurfaceOutputConfigImpl extends Camera2OutputConfigImpl {
+ /**
+ * Get the {@link Surface}. It'll return valid surface only when type is TYPE_SURFACE.
+ */
+ Surface getSurface();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl
new file mode 100644
index 00000000..5be2e737
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.aidl
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+parcelable CameraMetadataWrapper; \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java
new file mode 100644
index 00000000..02f83142
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraMetadataWrapper.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.camera.extensions.impl.serviceforward.PlatformApi;
+
+import java.util.ArrayList;
+
+public class CameraMetadataWrapper implements Parcelable {
+ private CameraMetadataNative mCameraMetadataNative;
+ private long mVendorId = Long.MAX_VALUE;
+
+ public CameraMetadataWrapper(CameraCharacteristics cameraCharacteristics) {
+ mCameraMetadataNative = new CameraMetadataNative();
+ if (cameraCharacteristics != null) {
+ setVendorId(cameraCharacteristics);
+ }
+ }
+
+ public CameraMetadataWrapper(CameraMetadataNative cameraMetadataNative) {
+ mCameraMetadataNative = cameraMetadataNative;
+ }
+
+ protected CameraMetadataWrapper(Parcel in) {
+ mCameraMetadataNative = in.readParcelable(CameraMetadataNative.class.getClassLoader());
+ }
+
+ public static final Creator<CameraMetadataWrapper> CREATOR =
+ new Creator<CameraMetadataWrapper>() {
+ @Override
+ public CameraMetadataWrapper createFromParcel(Parcel in) {
+ return new CameraMetadataWrapper(in);
+ }
+
+ @Override
+ public CameraMetadataWrapper[] newArray(int size) {
+ return new CameraMetadataWrapper[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mCameraMetadataNative, flags);
+ }
+
+ private void setVendorId(CameraCharacteristics chars) {
+ Object thisClass = CameraCharacteristics.Key.class;
+ Class<CameraCharacteristics.Key<?>> keyClass =
+ (Class<CameraCharacteristics.Key<?>>) thisClass;
+ ArrayList<CameraCharacteristics.Key<?>> vendorKeys =
+ chars.getNativeMetadata().getAllVendorKeys(keyClass);
+ if ((vendorKeys != null) && !vendorKeys.isEmpty()) {
+ mVendorId = vendorKeys.get(0).getVendorId();
+ mCameraMetadataNative.setVendorId(mVendorId);
+ }
+ }
+
+ public <T> T get(CaptureRequest.Key<T> key) {
+ return mCameraMetadataNative.get(key);
+ }
+
+ public <T> void set(CaptureRequest.Key<T> key, T value) {
+ mCameraMetadataNative.set(key, value);
+ }
+
+ public <T> void set(CaptureResult.Key<T> key, T value) {
+ mCameraMetadataNative.set(key, value);
+ }
+
+ public CaptureRequest toCaptureRequest() {
+ CameraMetadataNative cameraMetadataNative = new CameraMetadataNative(mCameraMetadataNative);
+ return PlatformApi.createCaptureRequest(cameraMetadataNative);
+ }
+
+ public TotalCaptureResult toTotalCaptureResult() {
+ CameraMetadataNative cameraMetadataNative = new CameraMetadataNative(mCameraMetadataNative);
+ return PlatformApi.createTotalCaptureResult(cameraMetadataNative);
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl
new file mode 100644
index 00000000..0c008487
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraOutputConfig.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.Size;
+import android.view.Surface;
+
+parcelable CameraOutputConfig
+{
+ Size size;
+ Surface surface;
+ int imageFormat;
+ int capacity;
+
+ const int TYPE_SURFACE = 0;
+ const int TYPE_IMAGEREADER = 1;
+ const int TYPE_MULTIRES_IMAGEREADER = 2;
+ int type;
+
+ int outputId;
+ int surfaceGroupId;
+ String physicalCameraId;
+ List<CameraOutputConfig> sharedSurfaceConfigs;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl
new file mode 100644
index 00000000..c0d1dece
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CameraSessionConfig.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+
+parcelable CameraSessionConfig
+{
+ List<CameraOutputConfig> outputConfigs;
+ CameraMetadataWrapper sessionParameter;
+ int sessionTemplateId;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureBundle.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureBundle.aidl
new file mode 100644
index 00000000..6b21485d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureBundle.aidl
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+
+parcelable CaptureBundle
+{
+ int stageId;
+ CameraMetadataWrapper captureResult;
+ ImageWrapper captureImage;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl
new file mode 100644
index 00000000..bf3b331e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable CaptureFailureWrapper; \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java
new file mode 100644
index 00000000..7deb089b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureFailureWrapper.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.util.Log;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureFailure;
+
+public class CaptureFailureWrapper implements Parcelable {
+ private CaptureRequest mRequest;
+ private int mReason;
+ private boolean mWasImageCaptured;
+ private int mSequenceId;
+ private long mFrameNumber;
+ private String mErrorPhysicalCameraId;
+
+ public CaptureFailureWrapper(CaptureFailure captureFailure) {
+ mRequest = captureFailure.getRequest();
+ mReason = captureFailure.getReason();
+ mWasImageCaptured = captureFailure.wasImageCaptured();
+ mSequenceId = captureFailure.getSequenceId();
+ mFrameNumber = captureFailure.getFrameNumber();
+ mErrorPhysicalCameraId = captureFailure.getPhysicalCameraId();
+ }
+
+ public CaptureFailureWrapper(Parcel parcel) {
+ mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader());
+ mReason = parcel.readInt();
+ mWasImageCaptured = parcel.readBoolean();
+ mSequenceId = parcel.readInt();
+ mFrameNumber = parcel.readLong();
+ mErrorPhysicalCameraId = parcel.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mRequest, flags);
+ parcel.writeInt(mReason);
+ parcel.writeBoolean(mWasImageCaptured);
+ parcel.writeInt(mSequenceId);
+ parcel.writeLong(mFrameNumber);
+ parcel.writeString(mErrorPhysicalCameraId);
+ }
+
+ public static final Parcelable.Creator<CaptureFailureWrapper> CREATOR
+ = new Parcelable.Creator<CaptureFailureWrapper>() {
+ @Override
+ public CaptureFailureWrapper createFromParcel(Parcel parcel) {
+ return new CaptureFailureWrapper(parcel);
+ }
+
+ @Override
+ public CaptureFailureWrapper[] newArray(int size) {
+ return new CaptureFailureWrapper[size];
+ }
+ };
+
+ public CaptureFailure toCaptureFailure() {
+ return new CaptureFailure(mRequest, mReason, mWasImageCaptured, mSequenceId,
+ mFrameNumber, mErrorPhysicalCameraId);
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl
new file mode 100644
index 00000000..6a01aa3a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable CaptureResultWrapper;
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java
new file mode 100644
index 00000000..44b5bfa2
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureResultWrapper.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.util.Log;
+
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+public class CaptureResultWrapper implements Parcelable {
+ private String mCameraId;
+ private CameraMetadataNative mResults;
+ private CaptureRequest mRequest;
+ private int mSequenceId;
+ private long mFrameNumber;
+
+ public CaptureResultWrapper(CaptureResult captureResult) {
+ mCameraId = captureResult.getCameraId();
+ mResults = captureResult.getNativeMetadata();
+ mRequest = captureResult.getRequest();
+ mSequenceId = captureResult.getSequenceId();
+ mFrameNumber = captureResult.getFrameNumber();
+ }
+
+ public CaptureResultWrapper(Parcel parcel) {
+ mCameraId = parcel.readString();
+ mResults = parcel.readParcelable(CameraMetadataNative.class.getClassLoader());
+ mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader());
+ mSequenceId = parcel.readInt();
+ mFrameNumber = parcel.readLong();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mCameraId);
+ parcel.writeParcelable(mResults, flags);
+ parcel.writeParcelable(mRequest, flags);
+ parcel.writeInt(mSequenceId);
+ parcel.writeLong(mFrameNumber);
+ }
+
+ public static final Parcelable.Creator<CaptureResultWrapper> CREATOR =
+ new Parcelable.Creator<CaptureResultWrapper>() {
+ @Override
+ public CaptureResultWrapper createFromParcel(Parcel parcel) {
+ return new CaptureResultWrapper(parcel);
+ }
+
+ @Override
+ public CaptureResultWrapper[] newArray(int size) {
+ return new CaptureResultWrapper[size];
+ }
+ };
+
+ public CaptureResult toCaptureResult() {
+ return new CaptureResult(mCameraId, mResults, mRequest, mSequenceId, mFrameNumber);
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureStageImplWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureStageImplWrapper.aidl
new file mode 100644
index 00000000..3092d766
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/CaptureStageImplWrapper.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+parcelable CaptureStageImplWrapper
+{
+ int id;
+ CameraMetadataWrapper parameters;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl
new file mode 100644
index 00000000..35956093
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IAdvancedExtenderImpl.aidl
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+import androidx.camera.extensions.impl.service.Size;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+interface IAdvancedExtenderImpl {
+ boolean isExtensionAvailable(in String cameraId);
+ void init(in String cameraId);
+ LatencyRange getEstimatedCaptureLatencyRange(
+ in String cameraId, in Size outputSize, int format);
+ @nullable List<SizeList> getSupportedPreviewOutputResolutions(in String cameraId);
+ @nullable List<SizeList> getSupportedCaptureOutputResolutions(in String cameraId);
+ @nullable List<SizeList> getSupportedYuvAnalysisResolutions(in String cameraId);
+ ISessionProcessorImpl getSessionProcessor();
+ CameraMetadataWrapper getAvailableCaptureRequestKeys();
+ CameraMetadataWrapper getAvailableCaptureResultKeys();
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl
new file mode 100644
index 00000000..0cf067fa
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureCallback.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+// Declare any non-default types here with import statements
+
+interface ICaptureCallback {
+ void onCaptureStarted(int captureSequenceId, long timestamp);
+ void onCaptureProcessStarted(int captureSequenceId);
+ void onCaptureFailed(int captureSequenceId);
+ void onCaptureSequenceCompleted(int captureSequenceId);
+ void onCaptureSequenceAborted(int captureSequenceId);
+ void onCaptureCompleted(long shutterTimestamp, int captureSequenceId, in CameraMetadataWrapper results);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureProcessorImpl.aidl
new file mode 100644
index 00000000..d3d73589
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ICaptureProcessorImpl.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CaptureBundle;
+import androidx.camera.extensions.impl.service.IProcessResultImpl;
+import androidx.camera.extensions.impl.service.Size;
+
+import android.view.Surface;
+
+interface ICaptureProcessorImpl
+{
+ void onOutputSurface(in Surface surface, int imageFormat);
+ void onResolutionUpdate(in Size size);
+ void onImageFormatUpdate(int imageFormat);
+ void process(in List<CaptureBundle> capturelist, in IProcessResultImpl resultCallback);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl
new file mode 100644
index 00000000..5f0bc57d
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IExtensionsService.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.IPreviewExtenderImpl;
+import androidx.camera.extensions.impl.service.IImageCaptureExtenderImpl;
+
+import androidx.camera.extensions.impl.service.Size;
+
+interface IExtensionsService {
+ boolean isAdvancedExtenderImplemented();
+ void initialize(in String version, in IOnExtensionsInitializedCallback callback);
+ void deInitialize(in IOnExtensionsDeinitializedCallback callback);
+ IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType);
+ IPreviewExtenderImpl initializePreviewExtension(int extensionType);
+ IImageCaptureExtenderImpl initializeImageCaptureExtension(int extensionType);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageCaptureExtenderImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageCaptureExtenderImpl.aidl
new file mode 100644
index 00000000..0ce4856e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageCaptureExtenderImpl.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.SizeList;
+import androidx.camera.extensions.impl.service.ICaptureProcessorImpl;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.Size;
+
+
+interface IImageCaptureExtenderImpl
+{
+ void onInit(in String cameraId);
+ void onDeInit();
+ @nullable CaptureStageImplWrapper onPresetSession();
+ @nullable CaptureStageImplWrapper onEnableSession();
+ @nullable CaptureStageImplWrapper onDisableSession();
+ boolean isExtensionAvailable(in String cameraId);
+ void init(in String cameraId);
+ @nullable ICaptureProcessorImpl getCaptureProcessor();
+ List<CaptureStageImplWrapper> getCaptureStages();
+ int getMaxCaptureStage();
+ @nullable List<SizeList> getSupportedResolutions();
+ @nullable LatencyRange getEstimatedCaptureLatencyRange(in Size outputSize);
+ CameraMetadataWrapper getAvailableCaptureRequestKeys();
+ CameraMetadataWrapper getAvailableCaptureResultKeys();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl
new file mode 100644
index 00000000..940e0f14
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IImageProcessorImpl.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.ImageWrapper;
+
+interface IImageProcessorImpl
+{
+ void onNextImageAvailable(int outputConfigId, in ImageWrapper imageWrapper,
+ in String physicalCameraId);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl
new file mode 100644
index 00000000..c8aa43c8
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsDeinitializedCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+interface IOnExtensionsDeinitializedCallback {
+ void onSuccess();
+ void onFailure(int error);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl
new file mode 100644
index 00000000..ada15d89
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IOnExtensionsInitializedCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+interface IOnExtensionsInitializedCallback {
+ void onSuccess();
+ void onFailure(int error);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewExtenderImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewExtenderImpl.aidl
new file mode 100644
index 00000000..193c4dc7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewExtenderImpl.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.SizeList;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import androidx.camera.extensions.impl.service.IPreviewImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IRequestUpdateProcessorImpl;
+
+interface IPreviewExtenderImpl
+{
+ void onInit(in String cameraId);
+ void onDeInit();
+ @nullable CaptureStageImplWrapper onPresetSession();
+ @nullable CaptureStageImplWrapper onEnableSession();
+ @nullable CaptureStageImplWrapper onDisableSession();
+ boolean isExtensionAvailable(in String cameraId);
+ void init(in String cameraId);
+ @nullable CaptureStageImplWrapper getCaptureStage();
+ const int PROCESSOR_TYPE_REQUEST_UPDATE_ONLY = 0;
+ const int PROCESSOR_TYPE_IMAGE_PROCESSOR = 1;
+ const int PROCESSOR_TYPE_NONE = 2;
+ int getProcessorType();
+ @nullable IPreviewImageProcessorImpl getPreviewImageProcessor();
+ @nullable IRequestUpdateProcessorImpl getRequestUpdateProcessor();
+ @nullable List<SizeList> getSupportedResolutions();
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewImageProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewImageProcessorImpl.aidl
new file mode 100644
index 00000000..22ccfd14
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IPreviewImageProcessorImpl.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+import androidx.camera.extensions.impl.service.IProcessResultImpl;
+import androidx.camera.extensions.impl.service.Size;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+import android.view.Surface;
+
+
+interface IPreviewImageProcessorImpl
+{
+ void onOutputSurface(in Surface surface, int imageFormat);
+ void onResolutionUpdate(in Size size);
+ void onImageFormatUpdate(int imageFormat);
+ void process(in ImageWrapper image, in TotalCaptureResultWrapper result,
+ in IProcessResultImpl resultCallback);
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IProcessResultImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IProcessResultImpl.aidl
new file mode 100644
index 00000000..f921ea02
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IProcessResultImpl.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+interface IProcessResultImpl
+{
+ void onCaptureCompleted(long shutterTimestamp, in CameraMetadataWrapper results);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl
new file mode 100644
index 00000000..8abed9e9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestCallback.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import android.hardware.camera2.CaptureRequest;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+interface IRequestCallback
+{
+ void onCaptureStarted(int requestId, long frameNumber, long timestamp);
+ void onCaptureProgressed(int requestId, in CaptureResultWrapper partialResult);
+ void onCaptureCompleted(int requestId, in TotalCaptureResultWrapper totalCaptureResult);
+ void onCaptureFailed(int requestId, in CaptureFailureWrapper captureFailure);
+ void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId);
+ void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+ void onCaptureSequenceAborted(int sequenceId);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl
new file mode 100644
index 00000000..70b30fa7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestProcessorImpl.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.IImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.Request;
+
+interface IRequestProcessorImpl {
+ void setImageProcessor(int outputConfigId, in IImageProcessorImpl imageProcessor);
+ int submit(in Request request, in IRequestCallback callback);
+ int submitBurst(in List<Request> requests, in IRequestCallback callback);
+ int setRepeating(in Request request, in IRequestCallback callback);
+ void abortCaptures();
+ void stopRepeating();
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestUpdateProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestUpdateProcessorImpl.aidl
new file mode 100644
index 00000000..f6e78d2b
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/IRequestUpdateProcessorImpl.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+import androidx.camera.extensions.impl.service.Size;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import android.view.Surface;
+
+
+interface IRequestUpdateProcessorImpl
+{
+ @nullable CaptureStageImplWrapper process(in TotalCaptureResultWrapper result);
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl
new file mode 100644
index 00000000..376a4a44
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ISessionProcessorImpl.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.OutputSurface;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import android.hardware.camera2.CaptureRequest;
+
+interface ISessionProcessorImpl {
+ CameraSessionConfig initSession(in String cameraId,
+ in OutputSurface previewSurface,
+ in OutputSurface imageCaptureSurface,
+ in OutputSurface imageAnalysisSurface);
+ void deInitSession();
+ void onCaptureSessionStart(IRequestProcessorImpl requestProcessor);
+ void onCaptureSessionEnd();
+ int startRepeating(in ICaptureCallback callback);
+ void stopRepeating();
+ int startCapture(in ICaptureCallback callback);
+ void setParameters(in CaptureRequest captureRequest);
+ int startTrigger(in CaptureRequest captureRequest, in ICaptureCallback callback);
+ void abortCapture(int captureSequenceId);
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl
new file mode 100644
index 00000000..09b7b485
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable ImageWrapper; \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java
new file mode 100644
index 00000000..882980d1
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/ImageWrapper.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.util.Log;
+import android.graphics.Rect;
+
+import android.graphics.GraphicBuffer;
+import android.media.ImageReader;
+import android.hardware.SyncFence;
+
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+
+import androidx.camera.extensions.impl.advanced.ImageReferenceImpl;
+
+public class ImageWrapper implements Parcelable, ImageReferenceImpl {
+ private static final String TAG = "ImageWrapper";
+ private int mFormat;
+ private int mWidth;
+ private int mHeight;
+ private int mTransform;
+ private int mScalingMode;
+ private long mTimestamp;
+ private int mPlaneCount;
+ private Rect mCrop;
+ private HardwareBuffer mBuffer;
+ private ParcelFileDescriptor mFence;
+
+ public ImageWrapper(Image image) {
+ mFormat = image.getFormat();
+ mWidth = image.getWidth();
+ mHeight = image.getHeight();
+ mTransform = image.getTransform();
+ mScalingMode = image.getScalingMode();
+ mTimestamp = image.getTimestamp();
+ if (image.getPlaneCount() <= 0) {
+ mPlaneCount = image.getPlanes().length;
+ } else {
+ mPlaneCount = image.getPlaneCount();
+ }
+
+ mCrop = image.getCropRect();
+ mBuffer = image.getHardwareBuffer();
+ try {
+ SyncFence fd = image.getFence();
+ if (fd.isValid()) {
+ mFence = fd.getFdDup();
+ }
+ } catch (java.io.IOException e) {
+ Log.e(TAG, "Failed to parcel buffer fence!");
+ }
+ }
+
+ public ImageWrapper(Parcel parcel) {
+ mFormat = parcel.readInt();
+ mWidth = parcel.readInt();
+ mHeight = parcel.readInt();
+ mTransform = parcel.readInt();
+ mScalingMode = parcel.readInt();
+ mTimestamp = parcel.readLong();
+ mPlaneCount = parcel.readInt();
+ mCrop = parcel.readParcelable(Rect.class.getClassLoader());
+ mBuffer = parcel.readParcelable(HardwareBuffer.class.getClassLoader());
+ mFence = parcel.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mFormat);
+ parcel.writeInt(mWidth);
+ parcel.writeInt(mHeight);
+ parcel.writeInt(mTransform);
+ parcel.writeInt(mScalingMode);
+ parcel.writeLong(mTimestamp);
+ parcel.writeInt(mPlaneCount);
+ parcel.writeParcelable(mCrop, flags);
+ parcel.writeParcelable(mBuffer, flags);
+ parcel.writeParcelable(mFence, flags);
+ }
+
+ public static final Parcelable.Creator<ImageWrapper> CREATOR
+ = new Parcelable.Creator<ImageWrapper>() {
+ @Override
+ public ImageWrapper createFromParcel(Parcel parcel) {
+ return new ImageWrapper(parcel);
+ }
+
+ @Override
+ public ImageWrapper[] newArray(int size) {
+ return new ImageWrapper[size];
+ }
+ };
+
+
+ // ImageReferenceImpl implementations.
+ private Image mImage = null;
+ private int mRefCount = 1;
+ private final Object mImageLock = new Object();
+
+ @Override
+ public Image get() {
+ if (mImage == null) {
+ mImage = new ExtensionImage(this);
+ }
+ return mImage;
+ }
+
+ @Override
+ public boolean increment() {
+ synchronized (mImageLock) {
+ if (mRefCount <= 0) {
+ return false;
+ }
+ mRefCount++;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean decrement() {
+ synchronized (mImageLock) {
+ if (mRefCount <= 0) {
+ return false;
+ }
+ mRefCount--;
+ if (mRefCount <= 0) {
+ mImage.close();
+ }
+ }
+ return true;
+ }
+
+ private static class ExtensionImage extends android.media.Image {
+ private final ImageWrapper mImageWrapper;
+ private GraphicBuffer mGraphicBuffer;
+ private ImageReader.ImagePlane[] mPlanes;
+
+ private ExtensionImage(ImageWrapper imageWrapper) {
+ mImageWrapper = imageWrapper;
+ mIsImageValid = true;
+ }
+
+ @Override
+ public int getFormat() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mFormat;
+ }
+
+ @Override
+ public int getWidth() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mWidth;
+ }
+
+ @Override
+ public HardwareBuffer getHardwareBuffer() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mBuffer;
+ }
+
+ @Override
+ public int getHeight() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mHeight;
+ }
+
+ @Override
+ public long getTimestamp() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mTimestamp;
+ }
+
+ @Override
+ public int getTransform() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mTransform;
+ }
+
+ @Override
+ public int getScalingMode() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mScalingMode;
+ }
+
+ @Override
+ public Plane[] getPlanes() {
+ throwISEIfImageIsInvalid();
+ if (mPlanes == null) {
+ int fenceFd = mImageWrapper.mFence != null ? mImageWrapper.mFence.getFd() : -1;
+ mGraphicBuffer = GraphicBuffer.createFromHardwareBuffer(mImageWrapper.mBuffer);
+ mPlanes = ImageReader.initializeImagePlanes(mImageWrapper.mPlaneCount,
+ mGraphicBuffer,
+ fenceFd, mImageWrapper.mFormat, mImageWrapper.mTimestamp,
+ mImageWrapper.mTransform, mImageWrapper.mScalingMode, mImageWrapper.mCrop);
+
+ }
+ // Shallow copy is fine.
+ return mPlanes.clone();
+ }
+
+ @Override
+ protected final void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public boolean isAttachable() {
+ throwISEIfImageIsInvalid();
+ // Clients must always detach parcelable images
+ return true;
+ }
+
+ @Override
+ public Rect getCropRect() {
+ throwISEIfImageIsInvalid();
+ return mImageWrapper.mCrop;
+ }
+
+ @Override
+ public void close() {
+ mIsImageValid = false;
+ if (mGraphicBuffer != null) {
+ ImageReader.unlockGraphicBuffer(mGraphicBuffer);
+ mGraphicBuffer.destroy();
+ mGraphicBuffer = null;
+ }
+
+ if (mPlanes != null) {
+ mPlanes = null;
+ }
+
+ if (mImageWrapper.mBuffer != null) {
+ mImageWrapper.mBuffer.close();
+ mImageWrapper.mBuffer = null;
+ }
+
+ if (mImageWrapper.mFence != null) {
+ try {
+ mImageWrapper.mFence.close();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ mImageWrapper.mFence = null;
+ }
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl
new file mode 100644
index 00000000..9d9e22cf
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/LatencyRange.aidl
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable LatencyRange
+{
+ long min;
+ long max;
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl
new file mode 100644
index 00000000..558928c3
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/OutputSurface.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+// Declare any non-default types here with import statements
+import androidx.camera.extensions.impl.service.Size;
+import android.view.Surface;
+
+parcelable OutputSurface {
+ Surface surface;
+ Size size;
+ int imageFormat;
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl
new file mode 100644
index 00000000..08dff963
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Request.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+parcelable Request
+{
+ int[] targetOutputConfigIds;
+ CameraMetadataWrapper parameters;
+ int templateId;
+ int requestId;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl
new file mode 100644
index 00000000..5341b604
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/Size.aidl
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable Size
+{
+ int width;
+ int height;
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl
new file mode 100644
index 00000000..443c769e
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/SizeList.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import androidx.camera.extensions.impl.service.Size;
+
+parcelable SizeList
+{
+ int format;
+ List<Size> sizes;
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl
new file mode 100644
index 00000000..b28861d5
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+parcelable TotalCaptureResultWrapper;
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java
new file mode 100644
index 00000000..28bbcb23
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/service/TotalCaptureResultWrapper.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.util.Log;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+
+public class TotalCaptureResultWrapper implements Parcelable {
+ private String mLogicalCameraId;
+ private CameraMetadataNative mResults;
+ private CaptureRequest mRequest;
+ private int mSequenceId;
+ private long mFrameNumber;
+ private List<CaptureResultWrapper> mPartials = new ArrayList<>();
+ private int mSessionId;
+ private List<PhysicalCaptureResultInfo> mPhysicalResultList = new ArrayList<>();
+
+ public TotalCaptureResultWrapper(TotalCaptureResult totalResult) {
+ mLogicalCameraId = totalResult.getCameraId();
+ mResults = totalResult.getNativeMetadata();
+ mRequest = totalResult.getRequest();
+ mSequenceId = totalResult.getSequenceId();
+ mFrameNumber = totalResult.getFrameNumber();
+ mSessionId = totalResult.getSessionId();
+ for (CaptureResult partial : totalResult.getPartialResults()) {
+ mPartials.add(new CaptureResultWrapper(partial));
+ }
+ Map<String, TotalCaptureResult> physicalResults =
+ totalResult.getPhysicalCameraTotalResults();
+ for (TotalCaptureResult physicalResult : physicalResults.values()) {
+ mPhysicalResultList.add(new PhysicalCaptureResultInfo(physicalResult.getCameraId(),
+ physicalResult.getNativeMetadata()));
+ }
+ }
+
+ public TotalCaptureResultWrapper(Parcel parcel) {
+ mLogicalCameraId = parcel.readString();
+ mResults = parcel.readParcelable(CameraMetadataNative.class.getClassLoader());
+ mRequest = parcel.readParcelable(CaptureRequest.class.getClassLoader());
+ mSequenceId = parcel.readInt();
+ mFrameNumber = parcel.readLong();
+ parcel.readParcelableList(mPartials, CaptureResultWrapper.class.getClassLoader());
+ mSessionId = parcel.readInt();
+ parcel.readParcelableList(mPhysicalResultList,
+ PhysicalCaptureResultInfo.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mLogicalCameraId);
+ parcel.writeParcelable(mResults, flags);
+ parcel.writeParcelable(mRequest, flags);
+ parcel.writeInt(mSequenceId);
+ parcel.writeLong(mFrameNumber);
+ parcel.writeParcelableList(mPartials, flags);
+ parcel.writeInt(mSessionId);
+ parcel.writeParcelableList(mPhysicalResultList, flags);
+ }
+
+ public static final Parcelable.Creator<TotalCaptureResultWrapper> CREATOR
+ = new Parcelable.Creator<TotalCaptureResultWrapper>() {
+ @Override
+ public TotalCaptureResultWrapper createFromParcel(Parcel parcel) {
+ return new TotalCaptureResultWrapper(parcel);
+ }
+
+ @Override
+ public TotalCaptureResultWrapper[] newArray(int size) {
+ return new TotalCaptureResultWrapper[size];
+ }
+ };
+
+ public TotalCaptureResult toTotalCaptureResult() {
+ PhysicalCaptureResultInfo[] physicalResults = new PhysicalCaptureResultInfo[0];
+ if ((mPhysicalResultList != null) && (!mPhysicalResultList.isEmpty())) {
+ physicalResults = new PhysicalCaptureResultInfo[mPhysicalResultList.size()];
+ physicalResults = mPhysicalResultList.toArray(physicalResults);
+ }
+ ArrayList<CaptureResult> partials = new ArrayList<>(mPartials.size());
+ for (CaptureResultWrapper resultWrapper : mPartials) {
+ partials.add(resultWrapper.toCaptureResult());
+ }
+ return new TotalCaptureResult(
+ mLogicalCameraId, mResults,
+ mRequest, mSequenceId,
+ mFrameNumber, partials, mSessionId,
+ physicalResults);
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/CaptureStageImplAdapter.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/CaptureStageImplAdapter.java
new file mode 100644
index 00000000..43ddf4a9
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/CaptureStageImplAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.hardware.camera2.CaptureRequest;
+import android.util.Pair;
+
+import androidx.camera.extensions.impl.CaptureStageImpl;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class CaptureStageImplAdapter implements CaptureStageImpl {
+ private final CaptureStageImplWrapper mCaptureStageImplWrapper;
+ CaptureStageImplAdapter(CaptureStageImplWrapper wrapper) {
+ mCaptureStageImplWrapper = wrapper;
+ }
+
+ @Override
+ public int getId() {
+ return mCaptureStageImplWrapper.id;
+ }
+
+ @Override
+ public List<Pair<CaptureRequest.Key, Object>> getParameters() {
+ CaptureRequest request = mCaptureStageImplWrapper.parameters.toCaptureRequest();
+ List<Pair<CaptureRequest.Key, Object>> result = new ArrayList<>();
+ for (CaptureRequest.Key<?> key : request.getKeys()) {
+ result.add(new Pair(key, request.get(key)));
+ }
+ return result;
+ }
+} \ No newline at end of file
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java
new file mode 100644
index 00000000..dc57590a
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardAdvancedExtender.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Range;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ForwardAdvancedExtender implements AdvancedExtenderImpl {
+ private static final String TAG = "ForwardAdvancedExtender";
+ private IAdvancedExtenderImpl mIAdvancedExtender;
+ private String mCameraId;
+ private final int mExtensionType;
+ private ForwardSessionProcessor mForwardSessionProcessor;
+
+ public ForwardAdvancedExtender(int extensionType) {
+ mIAdvancedExtender = ServiceManager.getInstance().createAdvancedExtenderImpl(
+ extensionType);
+ mExtensionType = extensionType;
+ }
+
+ private static ArrayList<Size> getSupportedSizes(SizeList sizesList) {
+ ArrayList<Size> ret = new ArrayList<>();
+ for (androidx.camera.extensions.impl.service.Size size : sizesList.sizes) {
+ ret.add(new Size(size.width, size.height));
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean isExtensionAvailable(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+ try {
+ return mIAdvancedExtender.isExtensionAvailable(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "isExtensionAvailable failed", e);
+ throw new IllegalStateException("isExtensionAvailable failed", e);
+ }
+ }
+
+ @Override
+ public void init(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> characteristicsMap) {
+ try {
+ mCameraId = cameraId;
+ mIAdvancedExtender.init(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "init failed", e);
+ throw new IllegalStateException("init failed", e);
+ }
+ }
+ @Override
+ @Nullable
+ public Range<Long> getEstimatedCaptureLatencyRange(@NonNull String cameraId,
+ @Nullable Size captureOutputSize,
+ int imageFormat) {
+ try {
+ androidx.camera.extensions.impl.service.Size size = null;
+ if (captureOutputSize != null) {
+ size = new androidx.camera.extensions.impl.service.Size();
+ size.width = captureOutputSize.getWidth();
+ size.height = captureOutputSize.getHeight();
+ }
+ LatencyRange latencyRange =
+ mIAdvancedExtender.getEstimatedCaptureLatencyRange(cameraId,
+ size, imageFormat);
+ return new Range<>(latencyRange.min, latencyRange.max);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getEstimatedCaptureLatencyRange failed", e);
+ throw new IllegalStateException("getEstimatedCaptureLatencyRange failed", e);
+ }
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(String cameraId) {
+ try {
+ List<SizeList> sizeLists = mIAdvancedExtender.getSupportedPreviewOutputResolutions(
+ cameraId);
+ Map<Integer, List<Size>> result = new HashMap<>();
+ for (SizeList sizeList : sizeLists) {
+ result.put(sizeList.format, getSupportedSizes(sizeList));
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedPreviewOutputResolutions failed", e);
+ throw new IllegalStateException("getSupportedPreviewOutputResolutions failed", e);
+ }
+ }
+
+ @Override
+ public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId) {
+ try {
+ List<SizeList> sizeLists = mIAdvancedExtender.getSupportedCaptureOutputResolutions(
+ cameraId);
+ Map<Integer, List<Size>> result = new HashMap<>();
+ for (SizeList sizeList : sizeLists) {
+ result.put(sizeList.format, getSupportedSizes(sizeList));
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedCaptureOutputResolutions failed", e);
+ throw new IllegalStateException("getSupportedCaptureOutputResolutions failed", e);
+ }
+ }
+
+ @Override
+ public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) {
+ try {
+ List<SizeList> sizeLists = mIAdvancedExtender.getSupportedYuvAnalysisResolutions(
+ cameraId);
+
+ if (sizeLists == null) {
+ return null;
+ }
+
+ for (SizeList sizeList : sizeLists) {
+ if (sizeList.format == ImageFormat.YUV_420_888) {
+ return getSupportedSizes(sizeList);
+ }
+ }
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedYuvAnalysisResolutions failed", e);
+ throw new IllegalStateException("getSupportedYuvAnalysisResolutions failed", e);
+ }
+ }
+
+ /**
+ * Re-initialize IAdvancedExtenderImpl when binder died.
+ */
+ private void ensureIAdvancedExtenderImplAlive() {
+ try {
+ if (!mIAdvancedExtender.asBinder().pingBinder()) {
+ Log.e(TAG, "IAdvancedExtenderImpl binder died, recreate");
+ mIAdvancedExtender = ServiceManager.getInstance().createAdvancedExtenderImpl(
+ mExtensionType);
+ mIAdvancedExtender.init(mCameraId);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't create IAdvancedExtenderImpl", e);
+ throw new IllegalStateException("can't create IAdvancedExtenderImpl", e);
+ }
+ }
+ /**
+ * Re-initialize ISessionProcessImpl when binder died.
+ */
+ ISessionProcessorImpl recreateISessionProcessor() {
+ Log.e(TAG, "Recreating ISessionProcessorImpl");
+ try {
+ ensureIAdvancedExtenderImplAlive();
+ return mIAdvancedExtender.getSessionProcessor();
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't get the SessionProcessor from IAdvancedExtenderImpl", e);
+ throw new IllegalStateException(
+ "can't get the SessionProcessor from IAdvancedExtenderImpl", e);
+ }
+ }
+
+ @Override
+ @NonNull
+ public SessionProcessorImpl createSessionProcessor() {
+ try {
+ ISessionProcessorImpl sessionProcessor = mIAdvancedExtender.getSessionProcessor();
+ mForwardSessionProcessor =
+ new ForwardSessionProcessor(this, sessionProcessor);
+ return mForwardSessionProcessor;
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't get the SessionProcessor from IAdvancedExtenderImpl", e);
+ throw new IllegalStateException(
+ "can't get the SessionProcessor from IAdvancedExtenderImpl", e); }
+ }
+
+ @Override
+ @Nullable
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ try {
+ CameraMetadataWrapper cameraMetadataWrapper
+ = mIAdvancedExtender.getAvailableCaptureRequestKeys();
+
+ CaptureRequest captureRequest = cameraMetadataWrapper.toCaptureRequest();
+
+ List<CaptureRequest.Key> result = new ArrayList<>();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ result.add(key);
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getAvailableCaptureRequestKeys failed", e);
+ throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e);
+ }
+ }
+
+ @Override
+ @Nullable
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ try {
+ CameraMetadataWrapper cameraMetadataWrapper
+ = mIAdvancedExtender.getAvailableCaptureResultKeys();
+ TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult();
+
+ List<CaptureResult.Key> result = new ArrayList<>();
+ for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+ result.add(key);
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getAvailableCaptureRequestKeys failed", e);
+ throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e);
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardImageCaptureExtender.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardImageCaptureExtender.java
new file mode 100644
index 00000000..03de94bf
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardImageCaptureExtender.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.CaptureProcessorImpl;
+import androidx.camera.extensions.impl.CaptureStageImpl;
+import androidx.camera.extensions.impl.ImageCaptureExtenderImpl;
+import androidx.camera.extensions.impl.ProcessResultImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CaptureBundle;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import androidx.camera.extensions.impl.service.ICaptureProcessorImpl;
+import androidx.camera.extensions.impl.service.IImageCaptureExtenderImpl;
+import androidx.camera.extensions.impl.service.IProcessResultImpl;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+import androidx.camera.extensions.impl.service.LatencyRange;
+import androidx.camera.extensions.impl.service.SizeList;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+public class ForwardImageCaptureExtender implements ImageCaptureExtenderImpl {
+
+ private static final String TAG = "ForwardPreviewExtender";
+
+ private final int mExtensionType;
+ private IImageCaptureExtenderImpl mIImageCaptureExtender;
+
+ public ForwardImageCaptureExtender(int extensionType) {
+ mExtensionType = extensionType;
+ mIImageCaptureExtender = ServiceManager.getInstance()
+ .createImageCaptureExtenderImpl(extensionType);
+ }
+
+ @Nullable
+ private static CaptureStageImpl convertToCaptureStageImpl(
+ @Nullable CaptureStageImplWrapper wrapper) {
+ if (wrapper == null) {
+ return null;
+ }
+
+ return new CaptureStageImplAdapter(wrapper);
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ try {
+ mIImageCaptureExtender.onInit(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "onInit failed", e);
+ throw new IllegalStateException("onInit failed", e);
+ }
+ }
+
+ @Override
+ public void onDeInit() {
+ try {
+ mIImageCaptureExtender.onDeInit();
+ } catch (RemoteException e) {
+ Log.e(TAG, "onDeInit failed", e);
+ throw new IllegalStateException("onDeInit failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ try {
+ return convertToCaptureStageImpl(mIImageCaptureExtender.onPresetSession());
+ } catch (RemoteException e) {
+ Log.e(TAG, "onPresetSession failed", e);
+ throw new IllegalStateException("onPresetSession failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ try {
+ return convertToCaptureStageImpl(mIImageCaptureExtender.onEnableSession());
+ } catch (RemoteException e) {
+ Log.e(TAG, "onEnableSession failed", e);
+ throw new IllegalStateException("onEnableSession failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ try {
+ return convertToCaptureStageImpl(mIImageCaptureExtender.onDisableSession());
+ } catch (RemoteException e) {
+ Log.e(TAG, "onDisableSession failed", e);
+ throw new IllegalStateException("onDisableSession failed", e);
+ }
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ try {
+ return mIImageCaptureExtender.isExtensionAvailable(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "isExtensionAvailable failed", e);
+ throw new IllegalStateException("isExtensionAvailable failed", e);
+ }
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ try {
+ mIImageCaptureExtender.init(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "init failed", e);
+ throw new IllegalStateException("init failed", e);
+ }
+ }
+
+ @Override
+ public CaptureProcessorImpl getCaptureProcessor() {
+ try {
+ ICaptureProcessorImpl captureProcessor = mIImageCaptureExtender.getCaptureProcessor();
+ if (captureProcessor == null) {
+ return null;
+ }
+ return new CaptureProcessorImplAdapter(captureProcessor);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getCaptureProcessor failed", e);
+ throw new IllegalStateException("getCaptureProcessor failed", e);
+ }
+ }
+
+ @Override
+ public List<CaptureStageImpl> getCaptureStages() {
+ try {
+ List<CaptureStageImpl> results = new ArrayList<>();
+ for (CaptureStageImplWrapper wrapper : mIImageCaptureExtender.getCaptureStages()) {
+ results.add(convertToCaptureStageImpl(wrapper));
+ }
+ return results;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getCaptureStages failed", e);
+ throw new IllegalStateException("getCaptureStages failed", e);
+ }
+ }
+
+ @Override
+ public int getMaxCaptureStage() {
+ try {
+ return mIImageCaptureExtender.getMaxCaptureStage();
+ } catch (RemoteException e) {
+ Log.e(TAG, "getMaxCaptureStage failed", e);
+ throw new IllegalStateException("getMaxCaptureStage failed", e);
+ }
+ }
+
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ try {
+ List<SizeList> sizes = mIImageCaptureExtender.getSupportedResolutions();
+ if (sizes == null) {
+ return null;
+ }
+
+ List<Pair<Integer, Size[]>> list = new ArrayList<>();
+ for (SizeList sizeList : sizes) {
+ Size[] sizeArray = new Size[sizeList.sizes.size()];
+ for (int i = 0; i < sizeList.sizes.size(); i++) {
+ sizeArray[i] = new Size(sizeList.sizes.get(i).width,
+ sizeList.sizes.get(i).height);
+ }
+ list.add(new Pair(sizeList.format, sizeArray));
+ }
+ return list;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSupportedResolutions failed", e);
+ throw new IllegalStateException("getSupportedResolutions failed", e);
+ }
+ }
+
+ @Override
+ public Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize) {
+ try {
+ androidx.camera.extensions.impl.service.Size size = null;
+ if (captureOutputSize != null) {
+ size = new androidx.camera.extensions.impl.service.Size();
+ size.width = captureOutputSize.getWidth();
+ size.height = captureOutputSize.getHeight();
+ }
+ LatencyRange latencyRange =
+ mIImageCaptureExtender.getEstimatedCaptureLatencyRange(size);
+ if (latencyRange == null) {
+ return null;
+ }
+
+ return new Range<Long>(latencyRange.min, latencyRange.max);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getEstimatedCaptureLatencyRange failed", e);
+ throw new IllegalStateException("getEstimatedCaptureLatencyRange failed", e);
+ }
+ }
+
+ @Override
+ public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
+ try {
+ CameraMetadataWrapper cameraMetadataWrapper
+ = mIImageCaptureExtender.getAvailableCaptureRequestKeys();
+ if (cameraMetadataWrapper == null) {
+ return null;
+ }
+
+ CaptureRequest captureRequest = cameraMetadataWrapper.toCaptureRequest();
+ List<CaptureRequest.Key> result = new ArrayList<>();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ result.add(key);
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getAvailableCaptureRequestKeys failed", e);
+ throw new IllegalStateException("getAvailableCaptureRequestKeys failed", e);
+ }
+ }
+
+ @Override
+ public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
+ try {
+ CameraMetadataWrapper cameraMetadataWrapper
+ = mIImageCaptureExtender.getAvailableCaptureResultKeys();
+ if (cameraMetadataWrapper == null) {
+ return null;
+ }
+
+ TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult();
+ List<CaptureResult.Key> result = new ArrayList<>();
+ for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+ result.add(key);
+ }
+ return result;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getAvailableCaptureResultKeys failed", e);
+ throw new IllegalStateException("getAvailableCaptureResultKeys failed", e);
+ }
+ }
+
+ private static class CaptureProcessorImplAdapter implements CaptureProcessorImpl {
+ private ICaptureProcessorImpl mICaptureProcessor;
+
+ private CaptureProcessorImplAdapter(ICaptureProcessorImpl iCaptureProcessor) {
+ mICaptureProcessor = iCaptureProcessor;
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results) {
+ process(results, null, null);
+ }
+
+ @Override
+ public void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor) {
+
+ try {
+ List<CaptureBundle> captureBundleList = new ArrayList<>();
+ for (Integer captureStageId : results.keySet()) {
+ CaptureBundle bundle = new CaptureBundle();
+ bundle.stageId = captureStageId;
+ Pair<Image, TotalCaptureResult> pair = results.get(captureStageId);
+
+ bundle.captureResult =
+ new CameraMetadataWrapper(pair.second.getNativeMetadata());
+ bundle.captureImage = new ImageWrapper(pair.first);
+ captureBundleList.add(bundle);
+ }
+
+ IProcessResultImpl.Stub iProcessResultImpl = null;
+ if (resultCallback != null) {
+ iProcessResultImpl = new IProcessResultImpl.Stub() {
+ @Override
+ public void onCaptureCompleted(long shutterTimestamp,
+ CameraMetadataWrapper result) {
+ List<Pair<CaptureResult.Key, Object>> resultList = new ArrayList<>();
+ TotalCaptureResult captureResult = result.toTotalCaptureResult();
+ for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+ resultList.add(new Pair(key, captureResult.get(key)));
+ }
+ if (executor == null) {
+ resultCallback.onCaptureCompleted(shutterTimestamp,
+ resultList);
+ } else {
+ executor.execute(() -> {
+ resultCallback.onCaptureCompleted(shutterTimestamp,
+ resultList);
+ });
+ }
+ }
+ };
+ }
+ mICaptureProcessor.process(captureBundleList, iProcessResultImpl);
+ } catch (RemoteException e) {
+
+ }
+ }
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ try {
+ mICaptureProcessor.onOutputSurface(surface, imageFormat);
+ } catch (RemoteException e) {
+ Log.e(TAG, "CaptureProcessor onOutputSurface failed", e);
+ throw new IllegalStateException("CaptureProcessor onOutputSurface failed", e);
+ }
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+ try {
+ androidx.camera.extensions.impl.service.Size serviceSize
+ = new androidx.camera.extensions.impl.service.Size();
+ serviceSize.width = size.getWidth();
+ serviceSize.height = size.getHeight();
+ mICaptureProcessor.onResolutionUpdate(serviceSize);
+ } catch (RemoteException e) {
+ Log.e(TAG, "CaptureProcessor onResolutionUpdate failed", e);
+ throw new IllegalStateException("CaptureProcessor onResolutionUpdate failed", e);
+ }
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+ try {
+ mICaptureProcessor.onImageFormatUpdate(imageFormat);
+ } catch (RemoteException e) {
+ Log.e(TAG, "CaptureProcessor imageFormat failed", e);
+ throw new IllegalStateException("CaptureProcessor imageFormat failed", e);
+ }
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardPreviewExtender.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardPreviewExtender.java
new file mode 100644
index 00000000..81969ca4
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardPreviewExtender.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.CaptureStageImpl;
+import androidx.camera.extensions.impl.PreviewExtenderImpl;
+import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
+import androidx.camera.extensions.impl.ProcessResultImpl;
+import androidx.camera.extensions.impl.ProcessorImpl;
+import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CaptureStageImplWrapper;
+import androidx.camera.extensions.impl.service.IPreviewExtenderImpl;
+import androidx.camera.extensions.impl.service.IPreviewImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IProcessResultImpl;
+import androidx.camera.extensions.impl.service.IRequestUpdateProcessorImpl;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+public class ForwardPreviewExtender implements PreviewExtenderImpl {
+ private static final String TAG = "ForwardPreviewExtender";
+
+ private final int mExtensionType;
+ private IPreviewExtenderImpl mIPreviewExtender;
+
+ public ForwardPreviewExtender(int extensionType) {
+ mExtensionType = extensionType;
+ mIPreviewExtender = ServiceManager.getInstance().createPreviewExtenderImpl(extensionType);
+ }
+
+ @Nullable
+ private static CaptureStageImpl convertToCaptureStageImpl(
+ @Nullable CaptureStageImplWrapper wrapper) {
+ if (wrapper == null) {
+ return null;
+ }
+
+ return new CaptureStageImplAdapter(wrapper);
+ }
+
+ @Override
+ public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
+ Context context) {
+ try {
+ mIPreviewExtender.onInit(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "onInit failed", e);
+ throw new IllegalStateException("onInit failed", e);
+ }
+ }
+
+ @Override
+ public void onDeInit() {
+ try {
+ mIPreviewExtender.onDeInit();
+ } catch (RemoteException e) {
+ Log.e(TAG, "onDeInit failed", e);
+ throw new IllegalStateException("onDeInit failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl onPresetSession() {
+ try {
+ return convertToCaptureStageImpl(mIPreviewExtender.onPresetSession());
+ } catch (RemoteException e) {
+ Log.e(TAG, "onPresetSession failed", e);
+ throw new IllegalStateException("onDeInit failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl onEnableSession() {
+ try {
+ return convertToCaptureStageImpl(mIPreviewExtender.onEnableSession());
+ } catch (RemoteException e) {
+ Log.e(TAG, "onEnableSession failed", e);
+ throw new IllegalStateException("onEnableSession failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl onDisableSession() {
+ try {
+ return convertToCaptureStageImpl(mIPreviewExtender.onDisableSession());
+ } catch (RemoteException e) {
+ Log.e(TAG, "onDisableSession failed", e);
+ throw new IllegalStateException("onDisableSession failed", e);
+ }
+ }
+
+ @Override
+ public boolean isExtensionAvailable(String cameraId,
+ CameraCharacteristics cameraCharacteristics) {
+ try {
+ return mIPreviewExtender.isExtensionAvailable(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "isExtensionAvailable failed", e);
+ throw new IllegalStateException("isExtensionAvailable failed", e);
+ }
+ }
+
+ @Override
+ public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+ try {
+ mIPreviewExtender.init(cameraId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "init failed", e);
+ throw new IllegalStateException("init failed", e);
+ }
+ }
+
+ @Override
+ public CaptureStageImpl getCaptureStage() {
+ try {
+ return convertToCaptureStageImpl(mIPreviewExtender.getCaptureStage());
+ } catch (RemoteException e) {
+ Log.e(TAG, "getCaptureStage failed", e);
+ throw new IllegalStateException("getCaptureStage failed", e);
+ }
+ }
+
+ @Override
+ public ProcessorType getProcessorType() {
+ try {
+ switch (mIPreviewExtender.getProcessorType()) {
+ case IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY:
+ return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
+ case IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR:
+ return ProcessorType.PROCESSOR_TYPE_IMAGE_PROCESSOR;
+ case IPreviewExtenderImpl.PROCESSOR_TYPE_NONE:
+ default:
+ return ProcessorType.PROCESSOR_TYPE_NONE;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getProcessorType failed", e);
+ throw new IllegalStateException("getProcessorType failed", e);
+ }
+ }
+
+ @Override
+ public ProcessorImpl getProcessor() {
+ try {
+ switch (getProcessorType()) {
+ case PROCESSOR_TYPE_REQUEST_UPDATE_ONLY:
+ return new RequestUpdateProcessorAdapter(
+ mIPreviewExtender.getRequestUpdateProcessor());
+ case PROCESSOR_TYPE_IMAGE_PROCESSOR:
+ return new PreviewImageProcessorAdapter(
+ mIPreviewExtender.getPreviewImageProcessor());
+ case PROCESSOR_TYPE_NONE:
+ default:
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getProcessorType failed", e);
+ throw new IllegalStateException("getProcessorType failed", e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedResolutions() {
+ return null;
+ }
+
+ private static class PreviewImageProcessorAdapter implements PreviewImageProcessorImpl {
+
+ private final IPreviewImageProcessorImpl mIPreviewImageProcessor;
+
+ private PreviewImageProcessorAdapter(IPreviewImageProcessorImpl iPreviewImageProcessor) {
+ mIPreviewImageProcessor = iPreviewImageProcessor;
+ }
+
+ @Override
+ public void process(Image image, TotalCaptureResult result) {
+ try {
+ mIPreviewImageProcessor.process(
+ new ImageWrapper(image), new TotalCaptureResultWrapper(result), null);
+ } catch (RemoteException e) {
+
+ }
+ }
+
+ @Override
+ public void process(Image image, TotalCaptureResult result,
+ ProcessResultImpl resultCallback, @Nullable Executor executor) {
+ try {
+
+ IProcessResultImpl.Stub iProcessResultImpl = null;
+ if (resultCallback != null) {
+ iProcessResultImpl = new IProcessResultImpl.Stub() {
+ @Override
+ public void onCaptureCompleted(long shutterTimestamp,
+ CameraMetadataWrapper result) {
+ List<Pair<CaptureResult.Key, Object>> resultList = new ArrayList<>();
+ TotalCaptureResult captureResult = result.toTotalCaptureResult();
+ for (CaptureResult.Key<?> key : captureResult.getKeys()) {
+ resultList.add(new Pair(key, captureResult.get(key)));
+ }
+ if (executor == null) {
+ resultCallback.onCaptureCompleted(shutterTimestamp,
+ resultList);
+ } else {
+ executor.execute(() -> {
+ resultCallback.onCaptureCompleted(shutterTimestamp,
+ resultList);
+ });
+ }
+ }
+ };
+ }
+ mIPreviewImageProcessor.process(
+ new ImageWrapper(image), new TotalCaptureResultWrapper(result),
+ iProcessResultImpl);
+ image.close();
+ } catch (RemoteException e) {
+
+ }
+ }
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ try {
+ mIPreviewImageProcessor.onOutputSurface(surface, imageFormat);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PreviewImageProcessorAdapter onOutputSurface failed", e);
+ throw new IllegalStateException(
+ "PreviewImageProcessorAdapter onOutputSurface failed", e);
+ }
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+ try {
+ androidx.camera.extensions.impl.service.Size serviceSize =
+ new androidx.camera.extensions.impl.service.Size();
+ serviceSize.width = size.getWidth();
+ serviceSize.height = size.getHeight();
+ mIPreviewImageProcessor.onResolutionUpdate(serviceSize);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PreviewImageProcessorAdapter onResolutionUpdate", e);
+ throw new IllegalStateException(
+ "PreviewImageProcessorAdapter onResolutionUpdate failed", e);
+ }
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+ try {
+ mIPreviewImageProcessor.onImageFormatUpdate(imageFormat);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PreviewImageProcessorAdapter onImageFormatUpdate failed", e);
+ throw new IllegalStateException(
+ "PreviewImageProcessorAdapter onImageFormatUpdate failed", e);
+ }
+ }
+ }
+
+ private static class RequestUpdateProcessorAdapter
+ implements RequestUpdateProcessorImpl {
+ private IRequestUpdateProcessorImpl mIRequestUpdateProcessor;
+
+ private RequestUpdateProcessorAdapter(IRequestUpdateProcessorImpl iRequestUpdateProcessor) {
+ mIRequestUpdateProcessor = iRequestUpdateProcessor;
+ }
+
+ @Override
+ public void onOutputSurface(Surface surface, int imageFormat) {
+ }
+
+ @Override
+ public void onResolutionUpdate(Size size) {
+ }
+
+ @Override
+ public void onImageFormatUpdate(int imageFormat) {
+ }
+
+ @Nullable
+ @Override
+ public CaptureStageImpl process(TotalCaptureResult result) {
+ try {
+ return convertToCaptureStageImpl(
+ mIRequestUpdateProcessor.process(new TotalCaptureResultWrapper(result)));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RequestUpdateProcessorAdapter process failed", e);
+ throw new IllegalStateException("RequestUpdateProcessorAdapter process failed", e);
+ }
+ }
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java
new file mode 100644
index 00000000..bdb87be7
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ForwardSessionProcessor.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_IMAGEREADER;
+import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER;
+import static androidx.camera.extensions.impl.service.CameraOutputConfig.TYPE_SURFACE;
+
+import android.content.Context;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.Binder;
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImplBuilder;
+import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
+import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImplBuilder;
+import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl;
+import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
+import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
+import androidx.camera.extensions.impl.service.CameraMetadataWrapper;
+import androidx.camera.extensions.impl.service.CameraOutputConfig;
+import androidx.camera.extensions.impl.service.CameraSessionConfig;
+import androidx.camera.extensions.impl.service.ICaptureCallback;
+import androidx.camera.extensions.impl.service.ISessionProcessorImpl;
+import androidx.camera.extensions.impl.service.OutputSurface;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ForwardSessionProcessor implements SessionProcessorImpl {
+ private static final String TAG = "ForwardSessionProcessor";
+ private final ForwardAdvancedExtender mForwardAdvancedExtender;
+
+ private ISessionProcessorImpl mISessionProcessor;
+ public ForwardSessionProcessor(@NonNull ForwardAdvancedExtender forwardAdvancedExtender,
+ @NonNull ISessionProcessorImpl sessionProcessor) {
+ mForwardAdvancedExtender = forwardAdvancedExtender;
+ mISessionProcessor = sessionProcessor;
+ }
+
+ private OutputSurface getOutputSurface(OutputSurfaceImpl outputSurfaceImpl) {
+ OutputSurface outputSurface = new OutputSurface();
+
+ androidx.camera.extensions.impl.service.Size extSize =
+ new androidx.camera.extensions.impl.service.Size();
+ extSize.width = outputSurfaceImpl.getSize().getWidth();
+ extSize.height = outputSurfaceImpl.getSize().getHeight();
+ outputSurface.size = extSize;
+ outputSurface.imageFormat = outputSurfaceImpl.getImageFormat();
+ outputSurface.surface = outputSurfaceImpl.getSurface();
+ return outputSurface;
+ }
+
+ @Override
+ @NonNull
+ public Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig) {
+ return initSession(cameraId, cameraCharacteristicsMap, context, previewSurfaceConfig,
+ imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig,
+ /* isRecoveringFromBinderDeath */ false);
+ }
+
+ @NonNull
+ private Camera2SessionConfigImpl initSession(@NonNull String cameraId,
+ @NonNull Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ @NonNull Context context,
+ @NonNull OutputSurfaceImpl previewSurfaceConfig,
+ @NonNull OutputSurfaceImpl imageCaptureSurfaceConfig,
+ @Nullable OutputSurfaceImpl imageAnalysisSurfaceConfig,
+ boolean isRecoveringFromBinderDeath) {
+ try {
+ OutputSurface outputSurfacePreview = getOutputSurface(previewSurfaceConfig);
+ OutputSurface outputSurfaceCapture = getOutputSurface(imageCaptureSurfaceConfig);
+ OutputSurface outputSurfaceAnalysis = null;
+ if (imageAnalysisSurfaceConfig != null) {
+ outputSurfaceAnalysis = getOutputSurface(imageAnalysisSurfaceConfig);
+ }
+
+ CameraSessionConfig sessionConfig = mISessionProcessor.initSession(
+ cameraId,
+ outputSurfacePreview,
+ outputSurfaceCapture,
+ outputSurfaceAnalysis);
+
+ Camera2SessionConfigImplBuilder sessionConfigBuilder =
+ new Camera2SessionConfigImplBuilder();
+ CaptureRequest captureRequest = sessionConfig.sessionParameter.toCaptureRequest();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
+ sessionConfigBuilder.addSessionParameter(objKey, captureRequest.get(objKey));
+ }
+ for (CameraOutputConfig outputConfig : sessionConfig.outputConfigs) {
+ Camera2OutputConfigImplBuilder builder =
+ getCamera2OutputConfigImplBuilder(outputConfig);
+ if (outputConfig.sharedSurfaceConfigs != null &&
+ (!outputConfig.sharedSurfaceConfigs.isEmpty())) {
+ for (CameraOutputConfig sharedSurfaceConfig :
+ outputConfig.sharedSurfaceConfigs) {
+ builder.addSurfaceSharingOutputConfig(
+ getCamera2OutputConfigImplBuilder(sharedSurfaceConfig).build());
+ }
+ }
+ sessionConfigBuilder.addOutputConfig(builder.build());
+ }
+
+ sessionConfigBuilder.setSessionTemplateId(sessionConfig.sessionTemplateId);
+ return sessionConfigBuilder.build();
+ } catch (RemoteException e) {
+ if ((e instanceof DeadObjectException) && !isRecoveringFromBinderDeath) {
+ // service died, reinitialize.
+ mISessionProcessor = mForwardAdvancedExtender.recreateISessionProcessor();
+ return initSession(cameraId, cameraCharacteristicsMap, context, previewSurfaceConfig
+ , imageCaptureSurfaceConfig, imageAnalysisSurfaceConfig,
+ /* isRecoveringFromBinderDeath */ true );
+ }
+ Log.e(TAG, "initSession failed", e);
+ throw new IllegalStateException("initSession failed", e);
+ }
+ }
+
+ private static Camera2OutputConfigImplBuilder getCamera2OutputConfigImplBuilder(
+ CameraOutputConfig outputConfig) {
+ switch (outputConfig.type) {
+ case TYPE_SURFACE:
+ return Camera2OutputConfigImplBuilder
+ .newSurfaceConfig(outputConfig.surface)
+ .setPhysicalCameraId(outputConfig.physicalCameraId)
+ .setSurfaceGroupId(outputConfig.surfaceGroupId)
+ .setOutputConfigId(outputConfig.outputId);
+ case TYPE_IMAGEREADER:
+ android.util.Size size = new android.util.Size(
+ outputConfig.size.width, outputConfig.size.height);
+ return Camera2OutputConfigImplBuilder
+ .newImageReaderConfig(size, outputConfig.imageFormat, outputConfig.capacity)
+ .setPhysicalCameraId(outputConfig.physicalCameraId)
+ .setSurfaceGroupId(outputConfig.surfaceGroupId)
+ .setOutputConfigId(outputConfig.outputId);
+ case TYPE_MULTIRES_IMAGEREADER:
+ default:
+ throw new UnsupportedOperationException("Output config type not supported");
+ }
+ }
+
+ @Override
+ public void deInitSession() {
+ try {
+ mISessionProcessor.deInitSession();
+ } catch (RemoteException e) {
+ Log.e(TAG, "deInitSession failed", e);
+ throw new IllegalStateException("deInitSession failed", e);
+ }
+ }
+
+ @Override
+ public void setParameters(Map<CaptureRequest.Key<?>, Object> parameters) {
+ try {
+ mISessionProcessor.setParameters(PlatformApi.createCaptureRequest(parameters));
+ } catch (RemoteException e) {
+ Log.e(TAG, "setParameters failed", e);
+ // still capture normally will invoke setParameters first and then startCapture.
+ // We want to fail the startCapture not the setParameters so that the capture failure
+ // can be propagated to the app.
+ }
+ }
+
+ @Override
+ public int startTrigger(Map<CaptureRequest.Key<?>, Object> triggers, CaptureCallback callback) {
+ try {
+ return mISessionProcessor.startTrigger(PlatformApi.createCaptureRequest(triggers),
+ new CaptureCallbackAdapter(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "startTrigger failed", e);
+ throw new IllegalStateException("startTrigger failed", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSessionStart(RequestProcessorImpl requestProcessor) {
+ try {
+ mISessionProcessor.onCaptureSessionStart(
+ new RequestProcessorAdapter(requestProcessor));
+ } catch (RemoteException e) {
+ Log.e(TAG, "onCaptureSessionStart failed", e);
+ throw new IllegalStateException("onCaptureSessionStart failed", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSessionEnd() {
+ try {
+ mISessionProcessor.onCaptureSessionEnd();
+ } catch (RemoteException e) {
+ Log.e(TAG, "onCaptureSessionEnd failed", e);
+ throw new IllegalStateException("onCaptureSessionEnd failed", e);
+ }
+ }
+
+ @Override
+ public int startRepeating(CaptureCallback callback) {
+ try {
+ return mISessionProcessor.startRepeating(new CaptureCallbackAdapter(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "startRepeating failed", e);
+ // notify the onCaptureFailed callback so that app is notified of the error.
+ callback.onCaptureFailed(0);
+ return 0;
+ }
+ }
+
+ @Override
+ public void stopRepeating() {
+ try {
+ mISessionProcessor.stopRepeating();
+ } catch (RemoteException e) {
+ Log.e(TAG, "stopRepeating failed", e);
+ throw new IllegalStateException("startRepeating failed", e);
+ }
+ }
+
+ @Override
+ public int startCapture(CaptureCallback callback) {
+ try {
+ return mISessionProcessor.startCapture(new CaptureCallbackAdapter(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "startCapture failed", e);
+ // notify the onCaptureFailed callback so that app is notified of the error.
+ callback.onCaptureFailed(0);
+ return 0;
+ }
+ }
+
+ @Override
+ public void abortCapture(int captureSequenceId) {
+ try {
+ mISessionProcessor.abortCapture(captureSequenceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "abortCapture failed", e);
+ throw new IllegalStateException("abortCapture failed", e);
+ }
+ }
+
+ private static class CaptureCallbackAdapter extends ICaptureCallback.Stub {
+ private final SessionProcessorImpl.CaptureCallback mImplCaptureCallback;
+
+ CaptureCallbackAdapter(SessionProcessorImpl.CaptureCallback implCaptureCallback) {
+ mImplCaptureCallback = implCaptureCallback;
+ }
+
+ @Override
+ public void onCaptureStarted(int captureSequenceId, long timeStamp) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureStarted(captureSequenceId, timeStamp);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureProcessStarted(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureProcessStarted(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureFailed(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureFailed(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureSequenceCompleted(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int captureSequenceId) throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureSequenceAborted(captureSequenceId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onCaptureCompleted(long shutterTimestamp, int captureSequenceId,
+ CameraMetadataWrapper cameraMetadataWrapper)
+ throws RemoteException {
+ TotalCaptureResult captureResult = cameraMetadataWrapper.toTotalCaptureResult();
+
+ Map<CaptureResult.Key, Object> resultmap = new HashMap<>();
+ for (CaptureResult.Key key : captureResult.getKeys()) {
+ resultmap.put(key, captureResult.get(key));
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mImplCaptureCallback.onCaptureCompleted(shutterTimestamp, captureSequenceId,
+ resultmap);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java
new file mode 100644
index 00000000..a40a16d0
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/PlatformApi.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+import java.util.Map;
+
+public class PlatformApi {
+ public static CaptureRequest createCaptureRequest(
+ Map<CaptureRequest.Key<?>, Object> parameters) {
+ CameraMetadataNative metadataNative = new CameraMetadataNative();
+ CaptureRequest.Builder builder =
+ new CaptureRequest.Builder(metadataNative, false, -1, "0", null);
+
+ for (CaptureRequest.Key<?> key : parameters.keySet()) {
+ CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
+ builder.set(objKey, parameters.get(objKey));
+ }
+ return builder.build();
+ }
+
+ public static CaptureRequest createCaptureRequest(CameraMetadataNative cameraMetadataNative) {
+ CaptureRequest.Builder builder =
+ new CaptureRequest.Builder(cameraMetadataNative, false, -1, "0", null);
+ return builder.build();
+ }
+
+ public static TotalCaptureResult createTotalCaptureResult(
+ CameraMetadataNative cameraMetadataNative) {
+ return new TotalCaptureResult(cameraMetadataNative, 0);
+ }
+
+ public static CameraMetadataNative createCameraMetadataNative(
+ Map<CaptureRequest.Key<?>, Object> parameters) {
+ CameraMetadataNative metadataNative = new CameraMetadataNative();
+ for (CaptureRequest.Key<?> key : parameters.keySet()) {
+ CaptureRequest.Key<Object> objKey = (CaptureRequest.Key<Object>) key;
+ metadataNative.set(objKey, parameters.get(objKey));
+ }
+ return metadataNative;
+ }
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java
new file mode 100644
index 00000000..3cc1d24c
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/RequestProcessorAdapter.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
+import androidx.camera.extensions.impl.advanced.ImageReferenceImpl;
+import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
+import androidx.camera.extensions.impl.service.CaptureFailureWrapper;
+import androidx.camera.extensions.impl.service.CaptureResultWrapper;
+import androidx.camera.extensions.impl.service.IImageProcessorImpl;
+import androidx.camera.extensions.impl.service.IRequestCallback;
+import androidx.camera.extensions.impl.service.IRequestProcessorImpl;
+import androidx.camera.extensions.impl.service.ImageWrapper;
+import androidx.camera.extensions.impl.service.Request;
+import androidx.camera.extensions.impl.service.TotalCaptureResultWrapper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+class RequestProcessorAdapter extends IRequestProcessorImpl.Stub {
+ private static final String TAG = "RequestProcessorAdapter";
+
+ private RequestProcessorImpl mRequestProcessorImpl;
+ RequestProcessorAdapter(RequestProcessorImpl requestProcessorImpl) {
+ mRequestProcessorImpl = requestProcessorImpl;
+ }
+ @Override
+ public void setImageProcessor(int outputfigId, IImageProcessorImpl imageProcessor)
+ throws RemoteException {
+ mRequestProcessorImpl.setImageProcessor(outputfigId, new ImageProcessorImpl() {
+ @Override
+ public void onNextImageAvailable(int outputConfigId, long timestampNs,
+ ImageReferenceImpl imageReference, String physicalCameraId) {
+ try {
+ imageProcessor.onNextImageAvailable(outputConfigId,
+ new ImageWrapper(imageReference.get()), physicalCameraId);
+ imageReference.decrement();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+ });
+ }
+
+ @Override
+ public int submit(Request request, IRequestCallback requestCallback)
+ throws RemoteException {
+ return submitBurst(Arrays.asList(request), requestCallback);
+ }
+
+ @Override
+ public int submitBurst(List<Request> requests, IRequestCallback requestCallback)
+ throws RemoteException {
+ List<RequestProcessorImpl.Request> implRequests = new ArrayList<>();
+ Map<RequestProcessorImpl.Request, Request> requestsMap = new HashMap<>();
+ for (Request request : requests) {
+ RequestProcessorImpl.Request implRequest = new ImplRequestAdapter(request);
+ implRequests.add(implRequest);
+ requestsMap.put(implRequest, request);
+ }
+ return mRequestProcessorImpl.submit(implRequests,
+ new ImplCaptureCallbackAdapter(requestsMap, requestCallback));
+ }
+
+ @Override
+ public int setRepeating(Request request, IRequestCallback requestCallback)
+ throws RemoteException {
+ Map<RequestProcessorImpl.Request, Request> requestsMap = new HashMap<>();
+ RequestProcessorImpl.Request implRequest = new ImplRequestAdapter(request);
+ requestsMap.put(implRequest, request);
+
+ return mRequestProcessorImpl.setRepeating(implRequest,
+ new ImplCaptureCallbackAdapter(requestsMap, requestCallback));
+ }
+
+ @Override
+ public void abortCaptures() throws RemoteException {
+ mRequestProcessorImpl.abortCaptures();
+ }
+
+ @Override
+ public void stopRepeating() throws RemoteException {
+ mRequestProcessorImpl.stopRepeating();
+ }
+
+ private static class ImplRequestAdapter implements RequestProcessorImpl.Request {
+ private Request mRequest;
+ ImplRequestAdapter(Request request) {
+ mRequest = request;
+ }
+
+ @Override
+ public List<Integer> getTargetOutputConfigIds() {
+ List<Integer> result = new ArrayList<>(mRequest.targetOutputConfigIds.length);
+ for (int id : mRequest.targetOutputConfigIds) {
+ result.add(id);
+ }
+ return result;
+ }
+
+ @Override
+ public Map<CaptureRequest.Key<?>, Object> getParameters() {
+ CaptureRequest captureRequest = mRequest.parameters.toCaptureRequest();
+ Map<CaptureRequest.Key<?>, Object> parameters = new HashMap<>();
+ for (CaptureRequest.Key<?> key : captureRequest.getKeys()) {
+ parameters.put(key, captureRequest.get(key));
+ }
+ return parameters;
+ }
+
+ @Override
+ public Integer getTemplateId() {
+ return mRequest.templateId;
+ }
+ }
+
+ private static class ImplCaptureCallbackAdapter implements RequestProcessorImpl.Callback {
+ private Map<RequestProcessorImpl.Request, Request> mRequestsMap;
+ private IRequestCallback mRequestCallback;
+ ImplCaptureCallbackAdapter(Map<RequestProcessorImpl.Request, Request> requestsMap,
+ IRequestCallback requestCallback) {
+ mRequestCallback = requestCallback;
+ mRequestsMap = requestsMap;
+ }
+
+ private Request getRequest(RequestProcessorImpl.Request implRequest) {
+ return mRequestsMap.get(implRequest);
+ }
+
+ @Override
+ public void onCaptureStarted(RequestProcessorImpl.Request implRequest, long frameNumber,
+ long timestamp) {
+ try {
+ mRequestCallback.onCaptureStarted(getRequest(implRequest).requestId,
+ frameNumber, timestamp);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(RequestProcessorImpl.Request implRequest,
+ CaptureResult partialResult) {
+ try {
+ mRequestCallback.onCaptureProgressed(getRequest(implRequest).requestId,
+ new CaptureResultWrapper(partialResult));
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureCompleted(RequestProcessorImpl.Request implRequest,
+ TotalCaptureResult totalCaptureResult) {
+ try {
+ mRequestCallback.onCaptureCompleted(getRequest(implRequest).requestId,
+ new TotalCaptureResultWrapper(totalCaptureResult));
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureFailed(RequestProcessorImpl.Request implRequest,
+ CaptureFailure captureFailure) {
+ try {
+
+ mRequestCallback.onCaptureFailed(getRequest(implRequest).requestId,
+ new CaptureFailureWrapper(captureFailure));
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureBufferLost(RequestProcessorImpl.Request implRequest, long frameNumber,
+ int outputStreamId) {
+ try {
+ mRequestCallback.onCaptureBufferLost(getRequest(implRequest).requestId,
+ frameNumber, outputStreamId);
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+ try {
+ mRequestCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+
+ @Override
+ public void onCaptureSequenceAborted(int sequenceId) {
+ try {
+ mRequestCallback.onCaptureSequenceAborted(sequenceId);
+ } catch(RemoteException e) {
+ Log.e(TAG, "Can't connect to the binder!", e);
+ }
+ }
+ }
+
+}
diff --git a/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java
new file mode 100644
index 00000000..76de1c92
--- /dev/null
+++ b/camera2/extensions/service_based_sample/oem_library/src/java/androidx/camera/extensions/impl/serviceforward/ServiceManager.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.serviceforward;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.extensions.impl.InitializerImpl;
+import androidx.camera.extensions.impl.service.IAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.service.IImageCaptureExtenderImpl;
+import androidx.camera.extensions.impl.service.IPreviewExtenderImpl;
+import androidx.camera.extensions.impl.service.IExtensionsService;
+import androidx.camera.extensions.impl.service.IOnExtensionsDeinitializedCallback;
+import androidx.camera.extensions.impl.service.IOnExtensionsInitializedCallback;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+public class ServiceManager {
+ private static final String TAG = "ServiceManager";
+ private static final int SERVICE_DELAY_MS = 1000;
+ private static final String SERVICE_PACKAGE_NAME = "com.android.oemextensions";
+ private static final String SERVICE_SERVICE_NAME =
+ "com.android.oemextensions.ExtensionsService";
+
+ private static ServiceManager sServiceManager;
+ private static final Object mLock = new Object();
+
+ public static void init(@Nullable Context context, @NonNull String version,
+ @Nullable InitializerImpl.OnExtensionsInitializedCallback callback,
+ @Nullable Executor executor) {
+ synchronized (mLock) {
+ if (sServiceManager == null) {
+ sServiceManager = new ServiceManager(context, version);
+ }
+ sServiceManager.bindServiceSync(context);
+ }
+
+ try {
+ Executor executorForCallback =
+ (executor != null)? executor: (cmd) -> cmd.run();
+
+ sServiceManager.mExtensionService.initialize(version,
+ new IOnExtensionsInitializedCallback.Stub() {
+ @Override
+ public void onSuccess() throws RemoteException {
+ executorForCallback.execute( () -> {
+ if (callback != null) {
+ callback.onSuccess();
+ }
+ Log.d(TAG, "initialize success!");
+ });
+ }
+
+ @Override
+ public void onFailure(int error) throws RemoteException {
+ executorForCallback.execute( () -> {
+ if (callback != null) {
+ callback.onFailure(error);
+ }
+ Log.d(TAG, "initialize failed! error=" + error);
+ });
+ }
+ });
+ } catch (RemoteException e){
+ throw new IllegalStateException("Failed to connect to extensions service", e);
+ }
+ }
+
+ @NonNull
+ public static ServiceManager getInstance() {
+ return sServiceManager;
+ }
+
+ public ServiceManager(@NonNull Context context, @NonNull String version) {
+ mContext = context;
+ mVersion = version;
+ }
+
+ private final Context mContext;
+ private final String mVersion;
+
+ private ServiceConnection mServiceConnection;
+ private IExtensionsService mExtensionService;
+
+ void bindServiceSync(Context context) {
+ if (mServiceConnection == null) {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder binder) {
+ mExtensionService = IExtensionsService.Stub.asInterface(binder);
+ Log.d(TAG, "service connected");
+ countDownLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ Log.e(TAG, "service disconnected");
+ mExtensionService = null;
+ mServiceConnection = null;
+ }
+ };
+
+ Intent intent = new Intent();
+ intent.setClassName(SERVICE_PACKAGE_NAME, SERVICE_SERVICE_NAME);
+ Log.d(TAG, "bindService start. intent = " + intent);
+ context.bindService(intent, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT |
+ Context.BIND_ABOVE_CLIENT, AsyncTask.THREAD_POOL_EXECUTOR,
+ mServiceConnection);
+
+ try {
+ boolean success = countDownLatch.await(SERVICE_DELAY_MS, TimeUnit.MILLISECONDS);
+ if (!success) {
+ Log.e(TAG, "Timed out while initializing proxy service!");
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while initializing proxy service!");
+ }
+ }
+ }
+
+ public void deinit(@NonNull InitializerImpl.OnExtensionsDeinitializedCallback callback,
+ @NonNull Executor executor) {
+ try {
+ mExtensionService.deInitialize(new IOnExtensionsDeinitializedCallback.Stub() {
+ @Override
+ public void onSuccess() throws RemoteException {
+ executor.execute( () -> {
+ callback.onSuccess();
+ });
+ }
+
+ @Override
+ public void onFailure(int error) throws RemoteException {
+ executor.execute( () -> {
+ callback.onFailure(error);
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed to connect to extensions service", e);
+ }
+ }
+
+ @NonNull
+ public IAdvancedExtenderImpl createAdvancedExtenderImpl(int extensionType) {
+ try {
+ synchronized (mLock) {
+ if (mExtensionService == null) {
+ init(mContext, mVersion, null, null);
+ }
+ }
+ return mExtensionService.initializeAdvancedExtension(extensionType);
+ } catch (RemoteException e) {
+ Log.e(TAG, "initializeAdvancedExtension failed", e);
+ throw new IllegalStateException("initializeAdvancedExtension failed", e);
+ }
+ }
+
+ @NonNull
+ public IImageCaptureExtenderImpl createImageCaptureExtenderImpl(int extensionType) {
+ try {
+ synchronized (mLock) {
+ if (mExtensionService == null) {
+ bindServiceSync(mContext);
+ }
+ }
+ return mExtensionService.initializeImageCaptureExtension(extensionType);
+ } catch (RemoteException e) {
+ Log.e(TAG, "initializeImageCaptureExtender failed", e);
+ throw new IllegalStateException("initializeImageCaptureExtender failed", e);
+ }
+ }
+
+ @NonNull
+ public IPreviewExtenderImpl createPreviewExtenderImpl(int extensionType) {
+ try {
+ synchronized (mLock) {
+ if (mExtensionService == null) {
+ bindServiceSync(mContext);
+ }
+ }
+ return mExtensionService.initializePreviewExtension(extensionType);
+ } catch (RemoteException e) {
+ Log.e(TAG, "initializePreviewExtension failed", e);
+ throw new IllegalStateException("initializePreviewExtension failed", e);
+ }
+ }
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
index ccb0dacf..bd605708 100755
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -95,6 +95,11 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
@Nullable
@Override
public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
@@ -113,4 +118,23 @@ public final class AutoImageCaptureExtenderImpl implements ImageCaptureExtenderI
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
index 100f6658..0c4577a4 100755
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -93,4 +93,9 @@ public final class AutoPreviewExtenderImpl implements PreviewExtenderImpl {
public List<Pair<Integer, Size[]>> getSupportedResolutions() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
index 2d266390..50c80407 100755
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -95,6 +95,11 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
@Nullable
@Override
public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
@@ -112,4 +117,24 @@ public final class BeautyImageCaptureExtenderImpl implements ImageCaptureExtende
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
index bc3e48dd..1f501745 100755
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -93,4 +93,9 @@ public final class BeautyPreviewExtenderImpl implements PreviewExtenderImpl {
public List<Pair<Integer, Size[]>> getSupportedResolutions() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
index 66c5839d..ee777cf9 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -95,6 +95,11 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
@Nullable
@Override
public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
@@ -113,4 +118,23 @@ public final class BokehImageCaptureExtenderImpl implements ImageCaptureExtender
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
index ff588623..1dc5ed79 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -91,4 +91,9 @@ public final class BokehPreviewExtenderImpl implements PreviewExtenderImpl {
public List<Pair<Integer, Size[]>> getSupportedResolutions() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
index 3eee146a..f4719b8b 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java
@@ -21,6 +21,7 @@ import android.graphics.ImageFormat;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.util.Pair;
+import android.util.Size;
import android.view.Surface;
import java.util.Map;
@@ -46,6 +47,29 @@ public interface CaptureProcessorImpl extends ProcessorImpl {
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
/**
+ * Informs the CaptureProcessorImpl where it should write the postview output to.
+ * This will only be invoked once if a valid postview surface was set.
+ *
+ * @param surface A valid {@link ImageFormat#YUV_420_888} {@link Surface}
+ * that the CaptureProcessorImpl should write data into.
+ * @since 1.4
+ */
+ void onPostviewOutputSurface(Surface surface);
+
+ /**
+ * Invoked when the Camera Framework changes the configured output resolution for
+ * still capture and postview.
+ *
+ * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
+ * input for still capture and postview to be at the specified resolutions.
+ *
+ * @param size for the surface for still capture.
+ * @param postviewSize for the surface for postview.
+ * @since 1.4
+ */
+ void onResolutionUpdate(Size size, Size postviewSize);
+
+ /**
* Process a set images captured that were requested.
*
* <p> The result of the processing step should be written to the {@link Surface} that was
@@ -63,4 +87,30 @@ public interface CaptureProcessorImpl extends ProcessorImpl {
*/
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor);
+
+ /**
+ * Process a set images captured that were requested for both postview and
+ * still capture.
+ *
+ * <p> This processing method will be called if a postview was requested, therefore the
+ * processed postview should be written to the
+ * {@link Surface} received by {@link #onPostviewOutputSurface(Surface, int)}.
+ * The final result of the processing step should be written to the {@link Surface} that was
+ * received by {@link #onOutputSurface(Surface, int)}. Since postview should be available
+ * before the capture, it should be processed and written to the surface before
+ * the final capture is processed.
+ *
+ * @param results The map of {@link ImageFormat#YUV_420_888} format images and
+ * metadata to process. The {@link Image} that are contained within
+ * the map will become invalid after this method completes, so no
+ * references to them should be kept.
+ * @param resultCallback Capture result callback to be called once the capture result
+ * values of the processed image are ready.
+ * @param executor The executor to run the callback on. If null then the callback
+ * will run on any arbitrary executor.
+ * @throws RuntimeException if postview feature is not supported
+ * @since 1.4
+ */
+ void processWithPostview(Map<Integer, Pair<Image, TotalCaptureResult>> results,
+ ProcessResultImpl resultCallback, Executor executor);
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
index 2879568f..4a3b01cd 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -80,4 +80,20 @@ public interface ExtenderStateListener {
* @return The request information to customize the session.
*/
CaptureStageImpl onDisableSession();
+
+ /**
+ * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+ * initialized and must return a valid camera session type
+ * {@link android.hardware.camera2.params.SessionConfiguration#getSessionType}
+ * to be used to configure camera capture session. Both the preview and the image capture
+ * extender must return the same session type value for a specific extension type. If there
+ * is inconsistency between the session type values from preview and image extenders, then
+ * the session configuration will fail.
+ *
+ * @since 1.4
+ * @return Camera capture session type. Regular and vendor specific types are supported but
+ * not high speed values. The extension can return -1 in which case the camera capture session
+ * will be configured to use the default regular type.
+ */
+ int onSessionType();
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
index f1191dcf..f3fd2f3b 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -95,6 +95,11 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
@Nullable
@Override
public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
@@ -112,4 +117,24 @@ public final class HdrImageCaptureExtenderImpl implements ImageCaptureExtenderIm
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
index 0eb4a610..af484646 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -93,4 +93,9 @@ public final class HdrPreviewExtenderImpl implements PreviewExtenderImpl {
public List<Pair<Integer, Size[]>> getSupportedResolutions() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
index 88bd105a..70c1804e 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -85,6 +85,21 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
List<Pair<Integer, Size[]>> getSupportedResolutions();
/**
+ * Returns the customized supported postview resolutions for a still capture using
+ * its size.
+ *
+ * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
+ *
+ * <p>The returned resolutions should be subset of the supported sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device.
+ *
+ * @return the customized supported resolutions, or null to support all sizes retrieved from
+ * {@link android.hardware.camera2.params.StreamConfigurationMap}.
+ * @since 1.4
+ */
+ List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize);
+
+ /**
* Returns the estimated capture latency range in milliseconds for the target capture
* resolution.
*
@@ -159,4 +174,44 @@ public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
* @since 1.3
*/
List<CaptureResult.Key> getAvailableCaptureResultKeys();
+
+ /**
+ * Advertise support for {@link ProcessResultImpl#onCaptureProcessProgressed}.
+ *
+ * @return {@code true} in case the process progress callback is supported and is expected to
+ * be triggered, {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isCaptureProcessProgressAvailable();
+
+ /**
+ * Returns the dynamically calculated capture latency pair in milliseconds.
+ *
+ * <p>In contrast to {@link #getEstimatedCaptureLatencyRange} this method is guaranteed to be
+ * called after the camera capture session is initialized and camera preview is enabled.
+ * The measurement is expected to take in to account dynamic parameters such as the current
+ * scene, the state of 3A algorithms, the state of internal HW modules and return a more
+ * accurate assessment of the still capture latency.</p>
+ *
+ * @return pair that includes the estimated input frame/frames camera capture latency as the
+ * first field and the estimated post-processing latency {@link CaptureProcessorImpl#process}
+ * as the second pair field. Both first and second fields will be in milliseconds. The total
+ * still capture latency will be the sum of both the first and second values.
+ * The pair is expected to be null if the dynamic latency estimation is not supported.
+ * If clients have not configured a still capture output, then this method can also return a
+ * null pair.
+ * @since 1.4
+ */
+ Pair<Long, Long> getRealtimeCaptureLatency();
+
+ /**
+ * Indicates whether the extension supports the postview for still capture feature.
+ * If the extension is using HAL processing, false should be returned since the
+ * postview feature is not currently supported for this case.
+ *
+ * @return {@code true} in case postview for still capture is supported
+ * {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isPostviewAvailable();
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
index c8ac9788..6f0eaef9 100755
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -95,6 +95,11 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender
throw new RuntimeException("Stub, replace with implementation.");
}
+ @Override
+ public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
@Nullable
@Override
public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
@@ -112,4 +117,24 @@ public final class NightImageCaptureExtenderImpl implements ImageCaptureExtender
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public Pair<Long, Long> getRealtimeCaptureLatency() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
index a5809f6b..825994f5 100755
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -93,4 +93,9 @@ public final class NightPreviewExtenderImpl implements PreviewExtenderImpl {
public List<Pair<Integer, Size[]>> getSupportedResolutions() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public int onSessionType() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java
index d0e3605d..0e154450 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/ProcessResultImpl.java
@@ -25,7 +25,6 @@ import java.util.List;
/**
* Allows clients to receive information about the capture result values of processed frames.
*
- * @since 1.3
*/
@SuppressLint("UnknownNullness")
public interface ProcessResultImpl {
@@ -40,6 +39,22 @@ public interface ProcessResultImpl {
* must also be passed as part of this callback. Both Camera2 and
* CameraX guarantee that those two settings and results are always
* supported and applied by the corresponding framework.
+ * @since 1.3
*/
void onCaptureCompleted(long shutterTimestamp, List<Pair<CaptureResult.Key, Object>> result);
+
+ /**
+ * Capture progress callback that needs to be called when the process capture is
+ * ongoing and includes the estimated progress of the processing.
+ *
+ * <p>Extensions must ensure that they always call this callback with monotonically increasing
+ * values.</p>
+ *
+ * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the
+ * callback is expected to be called once when processing is done with value 100.</p>
+ *
+ * @param progress Value between 0 and 100.
+ * @since 1.4
+ */
+ void onCaptureProcessProgressed(int progress);
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
index 465bfe88..d13efc85 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AdvancedExtenderImpl.java
@@ -124,6 +124,17 @@ public interface AdvancedExtenderImpl {
Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(String cameraId);
/**
+ * Returns supported output format/size map for postview image. OEM is required to support
+ * both JPEG and YUV_420_888 format output.
+ *
+ * <p>The surface created with this supported format/size could configure
+ * intermediate surfaces(YUV/RAW..) and write the output to the output surface.</p>
+ *
+ * @since 1.4
+ */
+ Map<Integer, List<Size>> getSupportedPostviewResolutions(Size captureSize);
+
+ /**
* Returns supported output sizes for Image Analysis (YUV_420_888 format).
*
* <p>OEM can optionally support a YUV surface for ImageAnalysis along with Preview/ImageCapture
@@ -185,4 +196,24 @@ public interface AdvancedExtenderImpl {
* @since 1.3
*/
List<CaptureResult.Key> getAvailableCaptureResultKeys();
+
+ /**
+ * Advertise support for {@link SessionProcessorImpl#onCaptureProcessProgressed}.
+ *
+ * @return {@code true} in case the process progress callback is supported and is expected to
+ * be triggered, {@code false} otherwise.
+ * @since 1.4
+ */
+ public boolean isCaptureProcessProgressAvailable();
+
+ /**
+ * Indicates whether the extension supports the postview for still capture feature.
+ * If the extension is using HAL processing, false should be returned since the
+ * postview feature is not currently supported for this case.
+ *
+ * @return {@code true} in case postview for still capture is supported
+ * {@code false} otherwise.
+ * @since 1.4
+ */
+ boolean isPostviewAvailable();
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
index 0d3bd4a0..8c3ac11c 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/AutoAdvancedExtenderImpl.java
@@ -69,6 +69,12 @@ public class AutoAdvancedExtenderImpl implements AdvancedExtenderImpl {
}
@Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
public List<Size> getSupportedYuvAnalysisResolutions(
String cameraId) {
throw new RuntimeException("Stub, replace with implementation.");
@@ -88,4 +94,14 @@ public class AutoAdvancedExtenderImpl implements AdvancedExtenderImpl {
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
index 1dec3266..135306c8 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BeautyAdvancedExtenderImpl.java
@@ -69,6 +69,12 @@ public class BeautyAdvancedExtenderImpl implements AdvancedExtenderImpl {
}
@Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
public List<Size> getSupportedYuvAnalysisResolutions(
String cameraId) {
throw new RuntimeException("Stub, replace with implementation.");
@@ -88,4 +94,14 @@ public class BeautyAdvancedExtenderImpl implements AdvancedExtenderImpl {
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
index bc41b4e0..fa4ad0dc 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/BokehAdvancedExtenderImpl.java
@@ -69,6 +69,12 @@ public class BokehAdvancedExtenderImpl implements AdvancedExtenderImpl {
}
@Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
public List<Size> getSupportedYuvAnalysisResolutions(
String cameraId) {
throw new RuntimeException("Stub, replace with implementation.");
@@ -88,4 +94,14 @@ public class BokehAdvancedExtenderImpl implements AdvancedExtenderImpl {
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
index d1217177..850f0e1b 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImpl.java
@@ -43,4 +43,16 @@ public interface Camera2SessionConfigImpl {
* {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters}.
*/
int getSessionTemplateId();
+
+
+ /**
+ * Retrieves the session type to be used when initializing the
+ * {@link android.hardware.camera2.CameraCaptureSession}.
+ *
+ * @since 1.4
+ * @return Camera capture session type. Regular and vendor specific types are supported but
+ * not high speed values. The extension can return -1 in which case the camera capture session
+ * will be configured to use the default regular type.
+ */
+ int getSessionType();
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
index a3011666..dc1feccd 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/Camera2SessionConfigImplBuilder.java
@@ -20,6 +20,7 @@ package androidx.camera.extensions.impl.advanced;
import android.annotation.SuppressLint;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.SessionConfiguration;
import java.util.ArrayList;
import java.util.HashMap;
@@ -32,6 +33,7 @@ import java.util.Map;
@SuppressLint("UnknownNullness")
public class Camera2SessionConfigImplBuilder {
private int mSessionTemplateId = CameraDevice.TEMPLATE_PREVIEW;
+ private int mSessionType = SessionConfiguration.SESSION_REGULAR;
Map<CaptureRequest.Key<?>, Object> mSessionParameters = new HashMap<>();
List<Camera2OutputConfigImpl> mCamera2OutputConfigs = new ArrayList<>();
@@ -86,6 +88,13 @@ public class Camera2SessionConfigImplBuilder {
}
/**
+ * Gets the camera capture session type.
+ */
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
* Builds a {@link Camera2SessionConfigImpl} instance.
*/
public Camera2SessionConfigImpl build() {
@@ -95,6 +104,7 @@ public class Camera2SessionConfigImplBuilder {
private static class Camera2SessionConfigImplImpl implements
Camera2SessionConfigImpl {
int mSessionTemplateId;
+ int mSessionType;
Map<CaptureRequest.Key<?>, Object> mSessionParameters;
List<Camera2OutputConfigImpl> mCamera2OutputConfigs;
@@ -102,6 +112,7 @@ public class Camera2SessionConfigImplBuilder {
mSessionTemplateId = builder.getSessionTemplateId();
mSessionParameters = builder.getSessionParameters();
mCamera2OutputConfigs = builder.getCamera2OutputConfigs();
+ mSessionType = builder.getSessionType();
}
@Override
@@ -118,6 +129,11 @@ public class Camera2SessionConfigImplBuilder {
public int getSessionTemplateId() {
return mSessionTemplateId;
}
+
+ @Override
+ public int getSessionType() {
+ return mSessionType;
+ }
}
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
index 06157dc3..dc5b2b60 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/HdrAdvancedExtenderImpl.java
@@ -70,6 +70,12 @@ public class HdrAdvancedExtenderImpl implements AdvancedExtenderImpl {
}
@Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
public List<Size> getSupportedYuvAnalysisResolutions(
String cameraId) {
throw new RuntimeException("Stub, replace with implementation.");
@@ -89,4 +95,14 @@ public class HdrAdvancedExtenderImpl implements AdvancedExtenderImpl {
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
index ce17c4f7..037e9479 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/ImageProcessorImpl.java
@@ -26,8 +26,7 @@ import android.annotation.SuppressLint;
@SuppressLint("UnknownNullness")
public interface ImageProcessorImpl {
/**
- * The reference count will be decremented when this method returns. If an extension wants
- * to hold onto the image it should increment the reference count in this method and
+ * The reference count will not be decremented when this method returns. Extensions must
* decrement it when the image is no longer needed.
*
* <p>If OEM is not closing(decrement) the image fast enough, the imageReference passed
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
index 97da5c14..5b0ed8ee 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/NightAdvancedExtenderImpl.java
@@ -69,6 +69,12 @@ public class NightAdvancedExtenderImpl implements AdvancedExtenderImpl {
}
@Override
+ public Map<Integer, List<Size>> getSupportedPostviewResolutions(
+ Size captureSize) {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
public List<Size> getSupportedYuvAnalysisResolutions(
String cameraId) {
throw new RuntimeException("Stub, replace with implementation.");
@@ -88,4 +94,14 @@ public class NightAdvancedExtenderImpl implements AdvancedExtenderImpl {
public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
throw new RuntimeException("Stub, replace with implementation.");
}
+
+ @Override
+ public boolean isCaptureProcessProgressAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
+
+ @Override
+ public boolean isPostviewAvailable() {
+ throw new RuntimeException("Stub, replace with implementation.");
+ }
}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java
new file mode 100644
index 00000000..723f0f4e
--- /dev/null
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/OutputSurfaceConfigurationImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.extensions.impl.advanced;
+
+import android.annotation.SuppressLint;
+
+/**
+ * For specifying the output surface configurations for the extension.
+ *
+ * @since 1.4
+ */
+@SuppressLint("UnknownNullness")
+public interface OutputSurfaceConfigurationImpl {
+ public OutputSurfaceImpl getPreviewOutputSurface();
+
+ public OutputSurfaceImpl getImageCaptureOutputSurface();
+
+ public OutputSurfaceImpl getImageAnalysisOutputSurface();
+
+ public OutputSurfaceImpl getPostviewOutputSurface();
+}
diff --git a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
index fabfc2bf..06270812 100644
--- a/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
+++ b/camera2/extensions/stub/src/main/java/androidx/camera/extensions/impl/advanced/SessionProcessorImpl.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
+import android.util.Pair;
import android.view.Surface;
import java.util.Map;
@@ -64,9 +65,59 @@ public interface SessionProcessorImpl {
* preparing a CameraCaptureSession. After initSession() is called, the camera ID,
* cameraCharacteristics and context will not change until deInitSession() has been called.
*
- * <p>CameraX specifies the output surface configurations for preview, image capture and image
- * analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which consists of a
- * list of {@link Camera2OutputConfigImpl} and session parameters. The
+ * <p>CameraX / Camera2 specifies the output surface configurations for preview using
+ * {@link OutputSurfaceConfigurationImpl#getPreviewOutputSurface}, image capture using
+ * {@link OutputSurfaceConfigurationImpl#getImageCaptureOutputSurface}, and image analysis
+ * [optional] using {@link OutputSurfaceConfigurationImpl#getImageAnalysisOutputSurface}.
+ * And OEM returns a {@link Camera2SessionConfigImpl} which consists of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters. The {@link Camera2SessionConfigImpl}
+ * will be used to configure the CameraCaptureSession.
+ *
+ * <p>OEM is responsible for outputting correct camera images output to these output surfaces.
+ * OEM can have the following options to enable the output:
+ * <pre>
+ * (1) Add these output surfaces in CameraCaptureSession directly using
+ * {@link Camera2OutputConfigImplBuilder#newSurfaceConfig(Surface)} }. Processing is done in
+ * HAL.
+ *
+ * (2) Use surface sharing with other surface by calling
+ * {@link Camera2OutputConfigImplBuilder#addSurfaceSharingOutputConfig(Camera2OutputConfigImpl)}
+ * to add the output surface to the other {@link Camera2OutputConfigImpl}.
+ *
+ * (3) Process output from other surfaces (RAW, YUV..) and write the result to the output
+ * surface. The output surface won't be contained in the returned
+ * {@link Camera2SessionConfigImpl}.
+ * </pre>
+ *
+ * <p>{@link Camera2OutputConfigImplBuilder} and {@link Camera2SessionConfigImplBuilder}
+ * implementations are provided in the stub for OEM to construct the
+ * {@link Camera2OutputConfigImpl} and {@link Camera2SessionConfigImpl} instances.
+ *
+ * @param surfaceConfigs contains output surfaces for preview, image capture, and an
+ * optional output config for image analysis (YUV_420_888).
+ * @return a {@link Camera2SessionConfigImpl} consisting of a list of
+ * {@link Camera2OutputConfigImpl} and session parameters which will decide the
+ * {@link android.hardware.camera2.params.SessionConfiguration} for configuring the
+ * CameraCaptureSession. Please note that the OutputConfiguration list may not be part of any
+ * supported or mandatory stream combination BUT OEM must ensure this list will always
+ * produce a valid camera capture session.
+ *
+ * @since 1.4
+ */
+ Camera2SessionConfigImpl initSession(
+ String cameraId,
+ Map<String, CameraCharacteristics> cameraCharacteristicsMap,
+ Context context,
+ OutputSurfaceConfigurationImpl surfaceConfigs);
+
+ /**
+ * Initializes the session for the extension. This is where the OEMs allocate resources for
+ * preparing a CameraCaptureSession. After initSession() is called, the camera ID,
+ * cameraCharacteristics and context will not change until deInitSession() has been called.
+ *
+ * <p>CameraX / Camera 2 specifies the output surface configurations for preview, image capture
+ * and image analysis[optional]. And OEM returns a {@link Camera2SessionConfigImpl} which
+ * consists of a list of {@link Camera2OutputConfigImpl} and session parameters. The
* {@link Camera2SessionConfigImpl} will be used to configure the CameraCaptureSession.
*
* <p>OEM is responsible for outputting correct camera images output to these output surfaces.
@@ -188,11 +239,54 @@ public interface SessionProcessorImpl {
int startCapture(CaptureCallback callback);
/**
+ * Start a multi-frame capture with a postview. {@link #startCapture(CaptureCallback)}
+ * will be used for captures without a postview request.
+ *
+ * Postview will be available before the capture. Upon postview completion,
+ * {@code OnImageAvailableListener#onImageAvailable} will be called on the ImageReader
+ * that creates the postview output surface. When the capture is completed,
+ * {@link CaptureCallback#onCaptureSequenceCompleted} is called and
+ * {@code OnImageAvailableListener#onImageAvailable} will also be called on the ImageReader
+ * that creates the image capture output surface.
+ *
+ * <p>Only one capture can perform at a time. Starting a capture when another capture is
+ * running will cause onCaptureFailed to be called immediately.
+ *
+ * @param callback a callback to report the status.
+ * @return the id of the capture sequence.
+ * @since 1.4
+ */
+ int startCaptureWithPostview(CaptureCallback callback);
+
+ /**
* Abort all capture tasks.
*/
void abortCapture(int captureSequenceId);
/**
+ * Returns the dynamically calculated capture latency pair in milliseconds.
+ *
+ * <p>In contrast to {@link AdvancedExtenderImpl#getEstimatedCaptureLatencyRange} this method is
+ * guaranteed to be called after {@link #onCaptureSessionStart}.
+ * The measurement is expected to take in to account dynamic parameters such as the current
+ * scene, the state of 3A algorithms, the state of internal HW modules and return a more
+ * accurate assessment of the still capture latency.</p>
+ *
+ * @return pair that includes the estimated input frame/frames camera capture latency as the
+ * first field. This is the time between {@link #onCaptureStarted} and
+ * {@link #onCaptureProcessStarted}. The second field value includes the estimated
+ * post-processing latency. This is the time between {@link #onCaptureProcessStarted} until
+ * the processed frame returns back to the client registered surface.
+ * Both first and second values will be in milliseconds. The total still capture latency will be
+ * the sum of both the first and second values of the pair.
+ * The pair is expected to be null if the dynamic latency estimation is not supported.
+ * If clients have not configured a still capture output, then this method can also return a
+ * null pair.
+ * @since 1.4
+ */
+ Pair<Long, Long> getRealtimeCaptureLatency();
+
+ /**
* Callback for notifying the status of {@link #startCapture(CaptureCallback)} and
* {@link #startRepeating(CaptureCallback)}.
*/
@@ -277,5 +371,20 @@ public interface SessionProcessorImpl {
*/
void onCaptureCompleted(long timestamp, int captureSequenceId,
Map<CaptureResult.Key, Object> result);
+
+ /**
+ * Capture progress callback that needs to be called when the process capture is
+ * ongoing and includes the estimated progress of the processing.
+ *
+ * <p>Extensions must ensure that they always call this callback with monotonically
+ * increasing values.</p>
+ *
+ * <p>Extensions are allowed to trigger this callback multiple times but at the minimum the
+ * callback is expected to be called once when processing is done with value 100.</p>
+ *
+ * @param progress Value between 0 and 100.
+ * @since 1.4
+ */
+ void onCaptureProcessProgressed(int progress);
}
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java b/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java
index bc772595..bf9e6b12 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java
@@ -22,6 +22,7 @@ import android.os.SystemClock;
import com.android.ex.camera2.portability.debug.Log;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.LinkedList;
import java.util.Queue;
@@ -30,14 +31,14 @@ public class DispatchThread extends Thread {
private static final long MAX_MESSAGE_QUEUE_LENGTH = 256;
private final Queue<Runnable> mJobQueue;
- private Boolean mIsEnded;
+ private AtomicBoolean mIsEnded;
private Handler mCameraHandler;
private HandlerThread mCameraHandlerThread;
public DispatchThread(Handler cameraHandler, HandlerThread cameraHandlerThread) {
super("Camera Job Dispatch Thread");
mJobQueue = new LinkedList<Runnable>();
- mIsEnded = new Boolean(false);
+ mIsEnded = new AtomicBoolean(false);
mCameraHandler = cameraHandler;
mCameraHandlerThread = cameraHandlerThread;
}
@@ -92,18 +93,14 @@ public class DispatchThread extends Thread {
* Gracefully ends this thread. Will stop after all jobs are processed.
*/
public void end() {
- synchronized (mIsEnded) {
- mIsEnded = true;
- }
+ mIsEnded.set(true);
synchronized(mJobQueue) {
mJobQueue.notifyAll();
}
}
private boolean isEnded() {
- synchronized (mIsEnded) {
- return mIsEnded;
- }
+ return mIsEnded.get();
}
@Override
diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java
index 21014d03..5b5a38d9 100644
--- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java
+++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java
@@ -89,7 +89,7 @@ public class BlockingCameraManager {
}
}
- private final CameraManager mManager;
+ protected final CameraManager mManager;
/**
* Create a new blocking camera manager.
@@ -168,7 +168,7 @@ public class BlockingCameraManager {
* <p>Time out after {@link #OPEN_TIME_OUT_MS} and unblock. Clean up camera if it arrives
* later.</p>
*/
- private class OpenListener extends CameraDevice.StateCallback {
+ protected class OpenListener extends CameraDevice.StateCallback {
private static final int ERROR_UNINITIALIZED = -1;
private final String mCameraId;
@@ -186,9 +186,13 @@ public class BlockingCameraManager {
private boolean mNoReply = true; // Start with no reply until proven otherwise
private boolean mTimedOut = false;
- OpenListener(CameraManager manager, String cameraId,
- CameraDevice.StateCallback listener, Handler handler)
- throws CameraAccessException {
+ protected OpenListener(String cameraId, CameraDevice.StateCallback listener) {
+ mCameraId = cameraId;
+ mProxy = listener;
+ }
+
+ OpenListener(CameraManager manager, String cameraId, CameraDevice.StateCallback listener,
+ Handler handler) throws CameraAccessException {
mCameraId = cameraId;
mProxy = listener;
manager.openCamera(cameraId, this, handler);
@@ -281,7 +285,7 @@ public class BlockingCameraManager {
if (mProxy != null) mProxy.onClosed(camera);
}
- CameraDevice blockUntilOpen() throws BlockingOpenException {
+ public CameraDevice blockUntilOpen() throws BlockingOpenException {
/**
* Block until onOpened, onError, or onDisconnected
*/
diff --git a/common/BUILD b/common/BUILD
index 80893a06..149da996 100644
--- a/common/BUILD
+++ b/common/BUILD
@@ -1,6 +1,6 @@
# TODO(b/198224074): auto-generate this file using bp2build.
load("@rules_android//rules:rules.bzl", "android_library")
-load("//build/make/tools:event_log_tags.bzl", "event_log_tags")
+load("//build/bazel/rules/java:event_log_tags.bzl", "event_log_tags")
event_log_tags(
name = "genlogtags",
diff --git a/framesequence/Android.bp b/framesequence/Android.bp
index 9a6d0f55..8d44f1d2 100644
--- a/framesequence/Android.bp
+++ b/framesequence/Android.bp
@@ -22,7 +22,4 @@ java_library {
name: "android-common-framesequence",
sdk_version: "8",
srcs: ["src/**/*.java"],
- optimize: {
- proguard_flags_files: ["proguard.flags"],
- },
}
diff --git a/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java b/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java
index c67b83c2..36cc784c 100644
--- a/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java
+++ b/framesequence/samples/FrameSequenceSamples/src/com/android/framesequence/samples/SamplesList.java
@@ -41,11 +41,11 @@ public class SamplesList extends ListActivity {
return ret;
}
- @SuppressWarnings("serial")
- static final ArrayList<Map<String,?>> SAMPLES = new ArrayList<Map<String,?>>() {{
- add(makeSample("GIF animation", FrameSequenceTest.class, R.raw.animated_gif));
- add(makeSample("WEBP animation", FrameSequenceTest.class, R.raw.animated_webp));
- }};
+ static final ArrayList<Map<String,?>> SAMPLES = new ArrayList<>();
+ static {
+ SAMPLES.add(makeSample("GIF animation", FrameSequenceTest.class, R.raw.animated_gif));
+ SAMPLES.add(makeSample("WEBP animation", FrameSequenceTest.class, R.raw.animated_webp));
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {