1 /* 2 * 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.util.Size 20 import android.view.Surface 21 import androidx.annotation.GuardedBy 22 import androidx.camera.camera2.pipe.CameraStream 23 import androidx.camera.camera2.pipe.ImageSourceConfig 24 import androidx.camera.camera2.pipe.OutputId 25 import androidx.camera.camera2.pipe.StreamFormat 26 import androidx.camera.camera2.pipe.StreamId 27 import androidx.camera.camera2.pipe.media.ImageReaderWrapper 28 29 /** 30 * Utility class for creating, tracking, and simulating [FakeImageReader]s. ImageReaders can be 31 * retrieved based on [Surface] or by [StreamId], and supports both single and 32 * MultiResolutionImageReader-like implementations. 33 */ 34 public class FakeImageReaders(private val fakeSurfaces: FakeSurfaces) { 35 private val lock = Any() 36 37 @GuardedBy("lock") private val fakeImageReaders = mutableListOf<FakeImageReader>() 38 getnull39 public operator fun get(surface: Surface): FakeImageReader? { 40 return synchronized(lock) { fakeImageReaders.find { it.surface == surface } } 41 } 42 getnull43 public operator fun get(streamId: StreamId): FakeImageReader? { 44 return synchronized(lock) { fakeImageReaders.find { it.streamId == streamId } } 45 } 46 47 /** Create a [FakeImageReader] based on a single [CameraStream]. */ createnull48 public fun create(cameraStream: CameraStream, capacity: Int): FakeImageReader = 49 create( 50 cameraStream.outputs.first().format, 51 cameraStream.id, 52 cameraStream.outputs.associate { it.id to it.size }, 53 capacity 54 ) 55 56 /** Create a [FakeImageReader] from its properties. */ createnull57 public fun create( 58 format: StreamFormat, 59 streamId: StreamId, 60 outputIdMap: Map<OutputId, Size>, 61 capacity: Int, 62 fakeSurfaces: FakeSurfaces? = null 63 ): FakeImageReader { 64 check(this[streamId] == null) { 65 "Cannot create multiple ImageReader(s) from the same $streamId!" 66 } 67 68 val fakeImageReader = 69 FakeImageReader.create(format, streamId, outputIdMap, capacity, fakeSurfaces) 70 synchronized(lock) { fakeImageReaders.add(fakeImageReader) } 71 return fakeImageReader 72 } 73 74 /** Create a [FakeImageReader] based on a [CameraStream] and an [ImageSourceConfig]. */ createnull75 public fun create( 76 cameraStream: CameraStream, 77 imageSourceConfig: ImageSourceConfig 78 ): ImageReaderWrapper = 79 create( 80 cameraStream.outputs.first().format, 81 cameraStream.id, 82 cameraStream.outputs.associate { it.id to it.size }, 83 imageSourceConfig.capacity, 84 fakeSurfaces 85 ) 86 87 /** [check] that all [FakeImageReader]s are closed. */ checkImageReadersClosednull88 public fun checkImageReadersClosed() { 89 for (fakeImageReader in fakeImageReaders) { 90 check(fakeImageReader.isClosed) { "Failed to close ImageReader: $fakeImageReader" } 91 } 92 } 93 94 /** [check] that all images from all [FakeImageReader]s are closed. */ checkImagesClosednull95 public fun checkImagesClosed() { 96 for (fakeImageReader in fakeImageReaders) { 97 fakeImageReader.checkImagesClosed() 98 } 99 } 100 } 101