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