1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.camera.camera2.pipe.config
18 
19 import android.content.Context
20 import androidx.camera.camera2.pipe.CameraBackend
21 import androidx.camera.camera2.pipe.CameraBackends
22 import androidx.camera.camera2.pipe.CameraContext
23 import androidx.camera.camera2.pipe.CameraController
24 import androidx.camera.camera2.pipe.CameraGraph
25 import androidx.camera.camera2.pipe.CameraGraphId
26 import androidx.camera.camera2.pipe.CameraMetadata
27 import androidx.camera.camera2.pipe.CameraSurfaceManager
28 import androidx.camera.camera2.pipe.Request
29 import androidx.camera.camera2.pipe.StreamGraph
30 import androidx.camera.camera2.pipe.SurfaceTracker
31 import androidx.camera.camera2.pipe.core.Threads
32 import androidx.camera.camera2.pipe.graph.CameraGraphImpl
33 import androidx.camera.camera2.pipe.graph.GraphListener
34 import androidx.camera.camera2.pipe.graph.GraphProcessor
35 import androidx.camera.camera2.pipe.graph.GraphProcessorImpl
36 import androidx.camera.camera2.pipe.graph.Listener3A
37 import androidx.camera.camera2.pipe.graph.StreamGraphImpl
38 import androidx.camera.camera2.pipe.graph.SurfaceGraph
39 import androidx.camera.camera2.pipe.internal.CameraGraphParametersImpl
40 import androidx.camera.camera2.pipe.internal.FrameCaptureQueue
41 import androidx.camera.camera2.pipe.internal.FrameDistributor
42 import androidx.camera.camera2.pipe.internal.ImageSourceMap
43 import dagger.Binds
44 import dagger.Module
45 import dagger.Provides
46 import dagger.Subcomponent
47 import javax.inject.Provider
48 import javax.inject.Qualifier
49 import javax.inject.Scope
50 import kotlinx.coroutines.CoroutineName
51 import kotlinx.coroutines.CoroutineScope
52 
53 @Scope internal annotation class CameraGraphScope
54 
55 @Qualifier internal annotation class ForCameraGraph
56 
57 @Qualifier internal annotation class CameraGraphContext
58 
59 @CameraGraphScope
60 @Subcomponent(
61     modules =
62         [
63             SharedCameraGraphModules::class,
64             InternalCameraGraphModules::class,
65             CameraGraphConfigModule::class,
66         ]
67 )
68 internal interface CameraGraphComponent {
cameraGraphnull69     fun cameraGraph(): CameraGraph
70 
71     @Subcomponent.Builder
72     interface Builder {
73         fun cameraGraphConfigModule(config: CameraGraphConfigModule): Builder
74 
75         fun build(): CameraGraphComponent
76     }
77 }
78 
79 @Module
80 internal class CameraGraphConfigModule(private val config: CameraGraph.Config) {
provideCameraGraphConfignull81     @Provides fun provideCameraGraphConfig(): CameraGraph.Config = config
82 }
83 
84 @Module
85 internal abstract class SharedCameraGraphModules {
86     @Binds abstract fun bindCameraGraph(cameraGraph: CameraGraphImpl): CameraGraph
87 
88     @Binds abstract fun bindGraphProcessor(graphProcessor: GraphProcessorImpl): GraphProcessor
89 
90     @Binds abstract fun bindGraphListener(graphProcessor: GraphProcessorImpl): GraphListener
91 
92     @Binds
93     @CameraGraphContext
94     abstract fun bindCameraGraphContext(@CameraPipeContext cameraPipeContext: Context): Context
95 
96     @Binds abstract fun bindStreamGraph(streamGraph: StreamGraphImpl): StreamGraph
97 
98     @CameraGraphScope
99     @Binds
100     abstract fun bindSurfaceTracker(surfaceGraph: SurfaceGraph): SurfaceTracker
101 
102     @Binds
103     abstract fun bindCameraGraphParameters(
104         parameters: CameraGraphParametersImpl
105     ): CameraGraph.Parameters
106 
107     companion object {
108         @CameraGraphScope
109         @Provides
110         fun provideCameraGraphId(): CameraGraphId {
111             return CameraGraphId.nextId()
112         }
113 
114         @CameraGraphScope
115         @Provides
116         @ForCameraGraph
117         fun provideCameraGraphCoroutineScope(threads: Threads): CoroutineScope {
118             return CoroutineScope(threads.lightweightDispatcher.plus(CoroutineName("CXCP-Graph")))
119         }
120 
121         @CameraGraphScope
122         @Provides
123         @ForCameraGraph
124         fun provideRequestListeners(
125             graphConfig: CameraGraph.Config,
126             listener3A: Listener3A,
127             frameDistributor: FrameDistributor
128         ): List<@JvmSuppressWildcards Request.Listener> {
129             val listeners = mutableListOf<Request.Listener>(listener3A)
130 
131             // Order slightly matters, add internal listeners first, and external listeners second.
132             listeners.add(listener3A)
133 
134             // FrameDistributor is responsible for all image grouping and distribution.
135             listeners.add(frameDistributor)
136 
137             // Listeners in CameraGraph.Config can de defined outside of the CameraPipe library,
138             // and since we iterate thought the listeners in order and invoke them, it appears
139             // beneficial to add the internal listeners first and then the graph config listeners.
140             listeners.addAll(graphConfig.defaultListeners)
141             return listeners
142         }
143 
144         @CameraGraphScope
145         @Provides
146         fun provideSurfaceGraph(
147             streamGraphImpl: StreamGraphImpl,
148             cameraController: Provider<CameraController>,
149             cameraSurfaceManager: CameraSurfaceManager,
150             imageSourceMap: ImageSourceMap
151         ): SurfaceGraph {
152             return SurfaceGraph(
153                 streamGraphImpl,
154                 cameraController,
155                 cameraSurfaceManager,
156                 imageSourceMap.imageSources
157             )
158         }
159 
160         @CameraGraphScope
161         @Provides
162         fun provideFrameDistributor(
163             imageSourceMap: ImageSourceMap,
164             frameCaptureQueue: FrameCaptureQueue
165         ): FrameDistributor {
166             return FrameDistributor(imageSourceMap.imageSources, frameCaptureQueue) {}
167         }
168     }
169 }
170 
171 @Module
172 internal abstract class InternalCameraGraphModules {
173     companion object {
174         @CameraGraphScope
175         @Provides
provideCameraBackendnull176         fun provideCameraBackend(
177             cameraBackends: CameraBackends,
178             graphConfig: CameraGraph.Config,
179             cameraContext: CameraContext
180         ): CameraBackend {
181             val customCameraBackend = graphConfig.customCameraBackend
182             if (customCameraBackend != null) {
183                 return customCameraBackend.create(cameraContext)
184             }
185 
186             val cameraBackendId = graphConfig.cameraBackendId
187             if (cameraBackendId != null) {
188                 return checkNotNull(cameraBackends[cameraBackendId]) {
189                     "Failed to initialize $cameraBackendId from $graphConfig"
190                 }
191             }
192             return cameraBackends.default
193         }
194 
195         @CameraGraphScope
196         @Provides
provideCameraMetadatanull197         fun provideCameraMetadata(
198             graphConfig: CameraGraph.Config,
199             cameraBackend: CameraBackend
200         ): CameraMetadata {
201             // TODO: It might be a good idea to cache and go through caches for some of these calls
202             //   instead of reading it directly from the backend.
203             return checkNotNull(cameraBackend.awaitCameraMetadata(graphConfig.camera)) {
204                 "Failed to load metadata for ${graphConfig.camera}!"
205             }
206         }
207 
208         @CameraGraphScope
209         @Provides
provideCameraControllernull210         fun provideCameraController(
211             graphId: CameraGraphId,
212             graphConfig: CameraGraph.Config,
213             cameraBackend: CameraBackend,
214             cameraContext: CameraContext,
215             graphProcessor: GraphProcessorImpl,
216             streamGraph: StreamGraph,
217             surfaceTracker: SurfaceTracker,
218         ): CameraController {
219             return cameraBackend.createCameraController(
220                 cameraContext,
221                 graphId,
222                 graphConfig,
223                 graphProcessor,
224                 streamGraph,
225                 surfaceTracker,
226             )
227         }
228     }
229 }
230