1 /*
<lambda>null2  * Copyright 2024 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.testing
18 
19 import android.content.Context
20 import android.os.Build
21 import android.util.Size
22 import androidx.camera.camera2.pipe.CameraGraph
23 import androidx.camera.camera2.pipe.CameraStream
24 import androidx.camera.camera2.pipe.Frame.Companion.isFrameInfoAvailable
25 import androidx.camera.camera2.pipe.GraphState.GraphStateStarted
26 import androidx.camera.camera2.pipe.GraphState.GraphStateStarting
27 import androidx.camera.camera2.pipe.GraphState.GraphStateStopped
28 import androidx.camera.camera2.pipe.ImageSourceConfig
29 import androidx.camera.camera2.pipe.OutputStatus
30 import androidx.camera.camera2.pipe.Request
31 import androidx.camera.camera2.pipe.StreamFormat
32 import androidx.test.core.app.ApplicationProvider
33 import com.google.common.truth.Truth.assertThat
34 import kotlinx.coroutines.ExperimentalCoroutinesApi
35 import kotlinx.coroutines.launch
36 import kotlinx.coroutines.test.TestScope
37 import kotlinx.coroutines.test.advanceUntilIdle
38 import kotlinx.coroutines.test.runTest
39 import org.junit.Test
40 import org.junit.runner.RunWith
41 import org.robolectric.annotation.Config
42 
43 @OptIn(ExperimentalCoroutinesApi::class)
44 @RunWith(RobolectricCameraPipeTestRunner::class)
45 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
46 class FrameCaptureTests {
47     private val testScope = TestScope()
48     private val testContext = ApplicationProvider.getApplicationContext() as Context
49     private val cameraPipeSimulator = CameraPipeSimulator.create(testScope, testContext)
50     private val cameraId = cameraPipeSimulator.cameras().awaitCameraIds()!!.first()
51     private val cameraMetadata = cameraPipeSimulator.cameras().awaitCameraMetadata(cameraId)!!
52 
53     private val viewfinderStreamConfig =
54         CameraStream.Config.create(Size(640, 480), StreamFormat.UNKNOWN)
55 
56     private val jpegStreamConfig =
57         CameraStream.Config.create(
58             Size(640, 480),
59             StreamFormat.YUV_420_888,
60             imageSourceConfig = ImageSourceConfig(capacity = 10)
61         )
62 
63     private val graphConfig =
64         CameraGraph.Config(
65             camera = cameraMetadata.camera,
66             streams = listOf(viewfinderStreamConfig, jpegStreamConfig)
67         )
68 
69     private val cameraGraphSimulator = cameraPipeSimulator.createCameraGraphSimulator(graphConfig)
70     private val cameraGraph: CameraGraph = cameraGraphSimulator
71 
72     private val viewfinderStream = cameraGraph.streams[viewfinderStreamConfig]!!
73     private val jpegStream = cameraGraph.streams[jpegStreamConfig]!!
74 
75     private suspend fun startCameraGraph() {
76         assertThat(cameraGraph.graphState.value).isEqualTo(GraphStateStopped)
77 
78         cameraGraph.start() // Tell the cameraGraph to start
79         assertThat(cameraGraph.graphState.value).isEqualTo(GraphStateStarting)
80 
81         cameraGraphSimulator.initializeSurfaces()
82         cameraGraphSimulator.simulateCameraStarted() // Simulate the camera starting successfully
83         assertThat(cameraGraph.graphState.value).isEqualTo(GraphStateStarted)
84     }
85 
86     @Test
87     fun frameCaptureCanBeSimulated() =
88         testScope.runTest {
89             startCameraGraph()
90 
91             // Capture an image using the cameraGraph
92             val frameCapture =
93                 cameraGraph.useSession { session ->
94                     session.capture(Request(streams = listOf(jpegStream.id)))
95                 }
96             advanceUntilIdle()
97 
98             // Verify a capture sequence with all of the frame interactions
99             val frameCaptureJob = launch {
100                 // TODO: Should awaitFrame be called awaitFrameStarted?
101                 // TODO: Should there be an awaitComplete() function?
102                 val frame = frameCapture.awaitFrame()
103                 assertThat(frame).isNotNull()
104 
105                 assertThat(frame!!.frameId.value).isGreaterThan(0)
106                 assertThat(frame.frameTimestamp.value).isGreaterThan(0)
107 
108                 val image = frame.awaitImage(jpegStream.id)
109                 assertThat(frame.imageStatus(jpegStream.id)).isEqualTo(OutputStatus.AVAILABLE)
110                 assertThat(frame.imageStatus(viewfinderStream.id))
111                     .isEqualTo(OutputStatus.UNAVAILABLE)
112                 assertThat(image).isNotNull()
113                 assertThat(image!!.timestamp).isEqualTo(frame.frameTimestamp.value)
114 
115                 image.close()
116 
117                 assertThat(frame.imageStatus(jpegStream.id)).isEqualTo(OutputStatus.AVAILABLE)
118                 assertThat(frame.imageStatus(viewfinderStream.id))
119                     .isEqualTo(OutputStatus.UNAVAILABLE)
120 
121                 println("frame.awaitFrameInfo()")
122                 val frameInfo = frame.awaitFrameInfo()
123 
124                 assertThat(frame.isFrameInfoAvailable).isTrue()
125                 assertThat(frameInfo).isNotNull()
126                 assertThat(frameInfo!!.frameNumber).isEqualTo(frame.frameNumber)
127 
128                 println("frame.close()")
129                 frame.close()
130 
131                 assertThat(frame.imageStatus(jpegStream.id)).isEqualTo(OutputStatus.UNAVAILABLE)
132                 assertThat(frame.imageStatus(viewfinderStream.id))
133                     .isEqualTo(OutputStatus.UNAVAILABLE)
134                 assertThat(frame.isFrameInfoAvailable).isFalse()
135             }
136 
137             // Simulate camera interactions:
138             // TODO: simulateFrameStarted?
139             val frameSimulator = cameraGraphSimulator.simulateNextFrame()
140             frameSimulator.simulateImage(jpegStream.id)
141             frameSimulator.simulateComplete(emptyMap())
142 
143             // TODO: should this have a way to check to make sure all frames are closed?
144             // cameraGraph?
145 
146             advanceUntilIdle()
147             assertThat(frameCaptureJob.isCompleted) // Ensure verification is complete
148             cameraGraphSimulator.close()
149         }
150 }
151