1 /* 2 * Copyright (C) 2014 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 package android.hardware.camera2.legacy; 17 18 import android.hardware.camera2.CaptureRequest; 19 import android.hardware.camera2.utils.SubmitInfo; 20 import android.util.Log; 21 22 import java.util.ArrayDeque; 23 import java.util.List; 24 25 /** 26 * A queue of bursts of requests. 27 * 28 * <p>This queue maintains the count of frames that have been produced, and is thread safe.</p> 29 */ 30 public class RequestQueue { 31 private static final String TAG = "RequestQueue"; 32 33 public static final long INVALID_FRAME = -1; 34 35 private BurstHolder mRepeatingRequest = null; 36 private final ArrayDeque<BurstHolder> mRequestQueue = new ArrayDeque<BurstHolder>(); 37 38 private long mCurrentFrameNumber = 0; 39 private long mCurrentRepeatingFrameNumber = INVALID_FRAME; 40 private int mCurrentRequestId = 0; 41 private final List<Long> mJpegSurfaceIds; 42 43 public final class RequestQueueEntry { 44 private final BurstHolder mBurstHolder; 45 private final Long mFrameNumber; 46 private final boolean mQueueEmpty; 47 getBurstHolder()48 public BurstHolder getBurstHolder() { 49 return mBurstHolder; 50 } getFrameNumber()51 public Long getFrameNumber() { 52 return mFrameNumber; 53 } isQueueEmpty()54 public boolean isQueueEmpty() { 55 return mQueueEmpty; 56 } 57 RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty)58 public RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty) { 59 mBurstHolder = burstHolder; 60 mFrameNumber = frameNumber; 61 mQueueEmpty = queueEmpty; 62 } 63 } 64 RequestQueue(List<Long> jpegSurfaceIds)65 public RequestQueue(List<Long> jpegSurfaceIds) { 66 mJpegSurfaceIds = jpegSurfaceIds; 67 } 68 69 /** 70 * Return and remove the next burst on the queue. 71 * 72 * <p>If a repeating burst is returned, it will not be removed.</p> 73 * 74 * @return an entry containing the next burst, the current frame number, and flag about whether 75 * request queue becomes empty. Null if no burst exists. 76 */ getNext()77 public synchronized RequestQueueEntry getNext() { 78 BurstHolder next = mRequestQueue.poll(); 79 boolean queueEmptied = (next != null && mRequestQueue.size() == 0); 80 if (next == null && mRepeatingRequest != null) { 81 next = mRepeatingRequest; 82 mCurrentRepeatingFrameNumber = mCurrentFrameNumber + 83 next.getNumberOfRequests(); 84 } 85 86 if (next == null) { 87 return null; 88 } 89 90 RequestQueueEntry ret = new RequestQueueEntry(next, mCurrentFrameNumber, queueEmptied); 91 mCurrentFrameNumber += next.getNumberOfRequests(); 92 return ret; 93 } 94 95 /** 96 * Cancel a repeating request. 97 * 98 * @param requestId the id of the repeating request to cancel. 99 * @return the last frame to be returned from the HAL for the given repeating request, or 100 * {@code INVALID_FRAME} if none exists. 101 */ stopRepeating(int requestId)102 public synchronized long stopRepeating(int requestId) { 103 long ret = INVALID_FRAME; 104 if (mRepeatingRequest != null && mRepeatingRequest.getRequestId() == requestId) { 105 mRepeatingRequest = null; 106 ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME : 107 mCurrentRepeatingFrameNumber - 1; 108 mCurrentRepeatingFrameNumber = INVALID_FRAME; 109 Log.i(TAG, "Repeating capture request cancelled."); 110 } else { 111 Log.e(TAG, "cancel failed: no repeating request exists for request id: " + requestId); 112 } 113 return ret; 114 } 115 116 /** 117 * Cancel a repeating request. 118 * 119 * @return the last frame to be returned from the HAL for the given repeating request, or 120 * {@code INVALID_FRAME} if none exists. 121 */ stopRepeating()122 public synchronized long stopRepeating() { 123 if (mRepeatingRequest == null) { 124 Log.e(TAG, "cancel failed: no repeating request exists."); 125 return INVALID_FRAME; 126 } 127 return stopRepeating(mRepeatingRequest.getRequestId()); 128 } 129 130 /** 131 * Add a the given burst to the queue. 132 * 133 * <p>If the burst is repeating, replace the current repeating burst.</p> 134 * 135 * @param requests the burst of requests to add to the queue. 136 * @param repeating true if the burst is repeating. 137 * @return the submission info, including the new request id, and the last frame number, which 138 * contains either the frame number of the last frame that will be returned for this request, 139 * or the frame number of the last frame that will be returned for the current repeating 140 * request if this burst is set to be repeating. 141 */ submit(CaptureRequest[] requests, boolean repeating)142 public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) { 143 int requestId = mCurrentRequestId++; 144 BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds); 145 long lastFrame = INVALID_FRAME; 146 if (burst.isRepeating()) { 147 Log.i(TAG, "Repeating capture request set."); 148 if (mRepeatingRequest != null) { 149 lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME : 150 mCurrentRepeatingFrameNumber - 1; 151 } 152 mCurrentRepeatingFrameNumber = INVALID_FRAME; 153 mRepeatingRequest = burst; 154 } else { 155 mRequestQueue.offer(burst); 156 lastFrame = calculateLastFrame(burst.getRequestId()); 157 } 158 SubmitInfo info = new SubmitInfo(requestId, lastFrame); 159 return info; 160 } 161 calculateLastFrame(int requestId)162 private long calculateLastFrame(int requestId) { 163 long total = mCurrentFrameNumber; 164 for (BurstHolder b : mRequestQueue) { 165 total += b.getNumberOfRequests(); 166 if (b.getRequestId() == requestId) { 167 return total - 1; 168 } 169 } 170 throw new IllegalStateException( 171 "At least one request must be in the queue to calculate frame number"); 172 } 173 174 } 175