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.graph 18 19 import androidx.camera.camera2.pipe.FrameInfo 20 import androidx.camera.camera2.pipe.FrameNumber 21 import androidx.camera.camera2.pipe.Request 22 import androidx.camera.camera2.pipe.RequestMetadata 23 import androidx.camera.camera2.pipe.core.Log 24 import kotlinx.atomicfu.atomic 25 import kotlinx.atomicfu.update 26 import kotlinx.atomicfu.updateAndGet 27 28 /** 29 * On some devices, we need to wait for 10 frames to complete before we can guarantee the success of 30 * single capture requests. This is a quirk identified as part of b/287020251 and reported in 31 * b/289284907. 32 * 33 * During initialization, setting the graphLoop will disableCaptureProcessing until after the 34 * required number of frames have been completed. 35 */ 36 internal class CaptureLimiter(private val requestsUntilActive: Long) : 37 Request.Listener, GraphLoop.Listener { 38 init { 39 require(requestsUntilActive > 0) 40 } 41 42 private val frameCount = atomic(0L) 43 private var _graphLoop: GraphLoop? = null 44 var graphLoop: GraphLoop 45 get() = _graphLoop!! 46 set(value) { <lambda>null47 check(_graphLoop == null) { "GraphLoop has already been set!" } 48 _graphLoop = value 49 value.captureProcessingEnabled = false <lambda>null50 Log.warn { 51 "Capture processing has been disabled for $value until $requestsUntilActive " + 52 "frames have been completed." 53 } 54 } 55 onCompletenull56 override fun onComplete( 57 requestMetadata: RequestMetadata, 58 frameNumber: FrameNumber, 59 result: FrameInfo 60 ) { 61 val count = frameCount.updateAndGet { if (it == -1L) -1 else it + 1 } 62 if (count == requestsUntilActive) { 63 Log.warn { "Capture processing is now enabled for $_graphLoop after $count frames." } 64 graphLoop.captureProcessingEnabled = true 65 } 66 } 67 onStopRepeatingnull68 override fun onStopRepeating() { 69 // Ignored 70 } 71 onGraphStoppednull72 override fun onGraphStopped() { 73 // If the cameraGraph is stopped, reset the counter 74 frameCount.update { if (it == -1L) -1 else 0 } 75 graphLoop.captureProcessingEnabled = false 76 Log.warn { 77 "Capture processing has been disabled for $graphLoop until $requestsUntilActive " + 78 "frames have been completed." 79 } 80 } 81 onGraphShutdownnull82 override fun onGraphShutdown() { 83 frameCount.value = -1 84 graphLoop.captureProcessingEnabled = false 85 } 86 } 87