1 /* 2 * Copyright (C) 2019 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 android.hardware.camera2.impl; 18 19 import android.hardware.camera2.CameraCaptureSession; 20 import android.hardware.camera2.CaptureRequest; 21 import android.hardware.camera2.CaptureResult; 22 import android.util.Log; 23 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.Iterator; 27 import java.util.LinkedList; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.TreeMap; 31 32 /** 33 * This class tracks the last frame number for submitted requests. 34 */ 35 public class FrameNumberTracker { 36 private static final String TAG = "FrameNumberTracker"; 37 38 /** the completed frame number for each type of capture results */ 39 private long[] mCompletedFrameNumber = new long[CaptureRequest.REQUEST_TYPE_COUNT]; 40 41 /** the frame numbers that don't belong to each type of capture results and are yet to be seen 42 * through an updateTracker() call. Each list holds a list of frame numbers that should appear 43 * with request types other than that, to which the list corresponds. 44 */ 45 private final LinkedList<Long>[] mPendingFrameNumbersWithOtherType = 46 new LinkedList[CaptureRequest.REQUEST_TYPE_COUNT]; 47 48 /** the frame numbers that belong to each type of capture results which should appear, but 49 * haven't yet.*/ 50 private final LinkedList<Long>[] mPendingFrameNumbers = 51 new LinkedList[CaptureRequest.REQUEST_TYPE_COUNT]; 52 53 /** frame number -> request type */ 54 private final TreeMap<Long, Integer> mFutureErrorMap = new TreeMap<Long, Integer>(); 55 /** Map frame numbers to list of partial results */ 56 private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>(); 57 FrameNumberTracker()58 public FrameNumberTracker() { 59 for (int i = 0; i < CaptureRequest.REQUEST_TYPE_COUNT; i++) { 60 mCompletedFrameNumber[i] = CameraCaptureSession.CaptureCallback.NO_FRAMES_CAPTURED; 61 mPendingFrameNumbersWithOtherType[i] = new LinkedList<Long>(); 62 mPendingFrameNumbers[i] = new LinkedList<Long>(); 63 } 64 } 65 update()66 private void update() { 67 Iterator<Map.Entry<Long, Integer>> iter = mFutureErrorMap.entrySet().iterator(); 68 while (iter.hasNext()) { 69 Map.Entry<Long, Integer> pair = iter.next(); 70 long errorFrameNumber = pair.getKey(); 71 int requestType = pair.getValue(); 72 Boolean removeError = false; 73 if (errorFrameNumber == mCompletedFrameNumber[requestType] + 1) { 74 removeError = true; 75 } 76 // The error frame number could have also either been in the pending list or one of the 77 // 'other' pending lists. 78 if (!mPendingFrameNumbers[requestType].isEmpty()) { 79 if (errorFrameNumber == mPendingFrameNumbers[requestType].element()) { 80 mPendingFrameNumbers[requestType].remove(); 81 removeError = true; 82 } 83 } else { 84 for (int i = 1; i < CaptureRequest.REQUEST_TYPE_COUNT; i++) { 85 int otherType = (requestType + i) % CaptureRequest.REQUEST_TYPE_COUNT; 86 if (!mPendingFrameNumbersWithOtherType[otherType].isEmpty() && errorFrameNumber 87 == mPendingFrameNumbersWithOtherType[otherType].element()) { 88 mPendingFrameNumbersWithOtherType[otherType].remove(); 89 removeError = true; 90 break; 91 } 92 } 93 94 if (!removeError) { 95 // Check for the case where we might have an error after a frame number gap 96 // caused by other types of capture requests 97 int otherType1 = (requestType + 1) % CaptureRequest.REQUEST_TYPE_COUNT; 98 int otherType2 = (requestType + 2) % CaptureRequest.REQUEST_TYPE_COUNT; 99 if (mPendingFrameNumbersWithOtherType[otherType1].isEmpty() && 100 mPendingFrameNumbersWithOtherType[otherType2].isEmpty()) { 101 long errorGapNumber = Math.max(mCompletedFrameNumber[otherType1], 102 mCompletedFrameNumber[otherType2]) + 1; 103 if ((errorGapNumber > mCompletedFrameNumber[requestType] + 1) && 104 (errorGapNumber == errorFrameNumber)) { 105 removeError = true; 106 } 107 } 108 } 109 } 110 if (removeError) { 111 mCompletedFrameNumber[requestType] = errorFrameNumber; 112 mPartialResults.remove(errorFrameNumber); 113 iter.remove(); 114 } 115 } 116 } 117 118 /** 119 * This function is called every time when a result or an error is received. 120 * @param frameNumber the frame number corresponding to the result or error 121 * @param isError true if it is an error, false if it is not an error 122 * @param requestType the type of capture request: Reprocess, ZslStill, or Regular. 123 */ updateTracker(long frameNumber, boolean isError, int requestType)124 public void updateTracker(long frameNumber, boolean isError, int requestType) { 125 if (isError) { 126 mFutureErrorMap.put(frameNumber, requestType); 127 } else { 128 try { 129 updateCompletedFrameNumber(frameNumber, requestType); 130 } catch (IllegalArgumentException e) { 131 Log.e(TAG, e.getMessage()); 132 } 133 } 134 update(); 135 } 136 137 /** 138 * This function is called every time a result has been completed. 139 * 140 * <p>It keeps a track of all the partial results already created for a particular 141 * frame number.</p> 142 * 143 * @param frameNumber the frame number corresponding to the result 144 * @param result the total or partial result 145 * @param partial {@true} if the result is partial, {@code false} if total 146 * @param requestType the type of capture request: Reprocess, ZslStill, or Regular. 147 */ updateTracker(long frameNumber, CaptureResult result, boolean partial, int requestType)148 public void updateTracker(long frameNumber, CaptureResult result, boolean partial, 149 int requestType) { 150 if (!partial) { 151 // Update the total result's frame status as being successful 152 updateTracker(frameNumber, /*isError*/false, requestType); 153 // Don't keep a list of total results, we don't need to track them 154 return; 155 } 156 157 if (result == null) { 158 // Do not record blank results; this also means there will be no total result 159 // so it doesn't matter that the partials were not recorded 160 return; 161 } 162 163 // Partial results must be aggregated in-order for that frame number 164 List<CaptureResult> partials = mPartialResults.get(frameNumber); 165 if (partials == null) { 166 partials = new ArrayList<>(); 167 mPartialResults.put(frameNumber, partials); 168 } 169 170 partials.add(result); 171 } 172 173 /** 174 * Attempt to pop off all of the partial results seen so far for the {@code frameNumber}. 175 * 176 * <p>Once popped-off, the partial results are forgotten (unless {@code updateTracker} 177 * is called again with new partials for that frame number).</p> 178 * 179 * @param frameNumber the frame number corresponding to the result 180 * @return a list of partial results for that frame with at least 1 element, 181 * or {@code null} if there were no partials recorded for that frame 182 */ popPartialResults(long frameNumber)183 public List<CaptureResult> popPartialResults(long frameNumber) { 184 return mPartialResults.remove(frameNumber); 185 } 186 getCompletedFrameNumber()187 public long getCompletedFrameNumber() { 188 return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_REGULAR]; 189 } 190 getCompletedReprocessFrameNumber()191 public long getCompletedReprocessFrameNumber() { 192 return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_REPROCESS]; 193 } 194 getCompletedZslStillFrameNumber()195 public long getCompletedZslStillFrameNumber() { 196 return mCompletedFrameNumber[CaptureRequest.REQUEST_TYPE_ZSL_STILL]; 197 } 198 199 /** 200 * Update the completed frame number for results of 3 categories 201 * (Regular/Reprocess/ZslStill). 202 * 203 * It validates that all previous frames of the same category have arrived. 204 * 205 * If there is a gap since previous frame number of the same category, assume the frames in 206 * the gap are other categories and store them in the pending frame number queue to check 207 * against when frames of those categories arrive. 208 */ updateCompletedFrameNumber(long frameNumber, int requestType)209 private void updateCompletedFrameNumber(long frameNumber, 210 int requestType) throws IllegalArgumentException { 211 if (frameNumber <= mCompletedFrameNumber[requestType]) { 212 throw new IllegalArgumentException("frame number " + frameNumber + " is a repeat"); 213 } 214 215 // Assume there are only 3 different types of capture requests. 216 int otherType1 = (requestType + 1) % CaptureRequest.REQUEST_TYPE_COUNT; 217 int otherType2 = (requestType + 2) % CaptureRequest.REQUEST_TYPE_COUNT; 218 long maxOtherFrameNumberSeen = 219 Math.max(mCompletedFrameNumber[otherType1], mCompletedFrameNumber[otherType2]); 220 if (frameNumber < maxOtherFrameNumberSeen) { 221 // if frame number is smaller than completed frame numbers of other categories, 222 // it must be: 223 // - the head of mPendingFrameNumbers for this category, or 224 // - in one of other mPendingFrameNumbersWithOtherType 225 if (!mPendingFrameNumbers[requestType].isEmpty()) { 226 // frame number must be head of current type of mPendingFrameNumbers if 227 // mPendingFrameNumbers isn't empty. 228 Long pendingFrameNumberSameType = mPendingFrameNumbers[requestType].element(); 229 if (frameNumber == pendingFrameNumberSameType) { 230 // frame number matches the head of the pending frame number queue. 231 // Do this before the inequality checks since this is likely to be the common 232 // case. 233 mPendingFrameNumbers[requestType].remove(); 234 } else if (frameNumber < pendingFrameNumberSameType) { 235 throw new IllegalArgumentException("frame number " + frameNumber 236 + " is a repeat"); 237 } else { 238 throw new IllegalArgumentException("frame number " + frameNumber 239 + " comes out of order. Expecting " 240 + pendingFrameNumberSameType); 241 } 242 } else { 243 // frame number must be in one of the other mPendingFrameNumbersWithOtherType. 244 int index1 = mPendingFrameNumbersWithOtherType[otherType1].indexOf(frameNumber); 245 int index2 = mPendingFrameNumbersWithOtherType[otherType2].indexOf(frameNumber); 246 boolean inSkippedOther1 = index1 != -1; 247 boolean inSkippedOther2 = index2 != -1; 248 if (!(inSkippedOther1 ^ inSkippedOther2)) { 249 throw new IllegalArgumentException("frame number " + frameNumber 250 + " is a repeat or invalid"); 251 } 252 253 // We know the category of frame numbers in pendingFrameNumbersWithOtherType leading 254 // up to the current frame number. The destination is the type which isn't the 255 // requestType* and isn't the src. Move them into the correct pendingFrameNumbers. 256 // * : This is since frameNumber is the first frame of requestType that we've 257 // received in the 'others' list, since for each request type frames come in order. 258 // All the frames before frameNumber are of the same type. They're not of 259 // 'requestType', neither of the type of the 'others' list they were found in. The 260 // remaining option is the 3rd type. 261 LinkedList<Long> srcList, dstList; 262 int index; 263 if (inSkippedOther1) { 264 srcList = mPendingFrameNumbersWithOtherType[otherType1]; 265 dstList = mPendingFrameNumbers[otherType2]; 266 index = index1; 267 } else { 268 srcList = mPendingFrameNumbersWithOtherType[otherType2]; 269 dstList = mPendingFrameNumbers[otherType1]; 270 index = index2; 271 } 272 for (int i = 0; i < index; i++) { 273 dstList.add(srcList.removeFirst()); 274 } 275 276 // Remove current frame number from pendingFrameNumbersWithOtherType 277 srcList.remove(); 278 } 279 } else { 280 // there is a gap of unseen frame numbers which should belong to the other 281 // 2 categories. Put all the pending frame numbers in the queue. 282 for (long i = 283 Math.max(maxOtherFrameNumberSeen, mCompletedFrameNumber[requestType]) + 1; 284 i < frameNumber; i++) { 285 mPendingFrameNumbersWithOtherType[requestType].add(i); 286 } 287 } 288 289 mCompletedFrameNumber[requestType] = frameNumber; 290 } 291 } 292 293