1 /*
<lambda>null2  * Copyright 2023 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.media
18 
19 import android.media.Image
20 import androidx.camera.camera2.pipe.StreamFormat
21 import java.nio.ByteBuffer
22 import kotlin.reflect.KClass
23 
24 /**
25  * An [ImageWrapper] backed by an [Image].
26  *
27  * Note: [Image] is not thread-safe, so all interactions with the underlying properties must be
28  * copied into local fields or guarded by a lock.
29  */
30 public class AndroidImage(private val image: Image) : ImageWrapper {
31     /** A [Plane] backed by an [ImagePlane]. */
32     public class Plane(private val imagePlane: Image.Plane) : ImagePlane {
33         // Copying out the contents of the Image.Plane means that this Plane
34         // implementation can be thread-safe (without requiring any locking)
35         // and can have getters which do not throw a RuntimeException if
36         // the underlying Image is closed.
37         override val pixelStride: Int = imagePlane.pixelStride
38         override val rowStride: Int = imagePlane.rowStride
39         override val buffer: ByteBuffer = imagePlane.buffer
40 
41         @Suppress("UNCHECKED_CAST")
42         override fun <T : Any> unwrapAs(type: KClass<T>): T? =
43             when (type) {
44                 Image.Plane::class -> imagePlane as T
45                 else -> null
46             }
47     }
48 
49     private val lock = Any()
50 
51     @Volatile private var _planes: List<ImagePlane>? = null
52 
53     // Copying out the contents of the Image means that this Image
54     // implementation can be thread-safe (without requiring any locking)
55     // and can have getters which do not throw a RuntimeException if
56     // the underlying Image is closed.
57     override val format: Int = image.format
58     override val width: Int = image.width
59     override val height: Int = image.height
60     override val timestamp: Long = image.timestamp
61 
62     @Suppress("UNCHECKED_CAST")
63     override fun <T : Any> unwrapAs(type: KClass<T>): T? =
64         when (type) {
65             Image::class -> image as T
66             else -> null
67         }
68 
69     override val planes: List<ImagePlane>
70         get() = readPlanes()
71 
72     override fun toString(): String {
73         // Image will be written as "Image-YUV_444_888w640h480-1234567890" with format, width,
74         // height, and timestamp
75         return "Image-${StreamFormat(format).name}-w${width}h$height-$timestamp"
76     }
77 
78     override fun close() {
79         image.close()
80     }
81 
82     /**
83      * Read and cache the result of [Image.getPlanes]. Each [ImagePlane], in turn, reads out and
84      * caches the buffer data for that specific plane.
85      *
86      * @return a list of [ImagePlane]
87      */
88     private fun readPlanes(): List<ImagePlane> {
89         var result = _planes
90         if (result == null) {
91             // Double checked locking for reading planes with a fast volatile read.
92             synchronized(lock) {
93                 result = _planes
94                 if (result == null) {
95                     val imagePlanes = image.planes
96                     val wrappedPlanes =
97                         imagePlanes?.map { imagePlane -> Plane(imagePlane) } ?: emptyList()
98                     _planes = wrappedPlanes
99                     result = wrappedPlanes
100                 }
101             }
102         }
103         return result!!
104     }
105 }
106