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