blob: fb444022c6dbef5a6a8221eeaa8e1d2e9255a252 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.legacy;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.SubmitInfo;
import android.util.Log;
import java.util.ArrayDeque;
import java.util.List;
/**
* A queue of bursts of requests.
*
* <p>This queue maintains the count of frames that have been produced, and is thread safe.</p>
*/
public class RequestQueue {
private static final String TAG = "RequestQueue";
public static final long INVALID_FRAME = -1;
private BurstHolder mRepeatingRequest = null;
private final ArrayDeque<BurstHolder> mRequestQueue = new ArrayDeque<BurstHolder>();
private long mCurrentFrameNumber = 0;
private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
private int mCurrentRequestId = 0;
private final List<Long> mJpegSurfaceIds;
public final class RequestQueueEntry {
private final BurstHolder mBurstHolder;
private final Long mFrameNumber;
private final boolean mQueueEmpty;
public BurstHolder getBurstHolder() {
return mBurstHolder;
}
public Long getFrameNumber() {
return mFrameNumber;
}
public boolean isQueueEmpty() {
return mQueueEmpty;
}
public RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty) {
mBurstHolder = burstHolder;
mFrameNumber = frameNumber;
mQueueEmpty = queueEmpty;
}
}
public RequestQueue(List<Long> jpegSurfaceIds) {
mJpegSurfaceIds = jpegSurfaceIds;
}
/**
* Return and remove the next burst on the queue.
*
* <p>If a repeating burst is returned, it will not be removed.</p>
*
* @return an entry containing the next burst, the current frame number, and flag about whether
* request queue becomes empty. Null if no burst exists.
*/
public synchronized RequestQueueEntry getNext() {
BurstHolder next = mRequestQueue.poll();
boolean queueEmptied = (next != null && mRequestQueue.size() == 0);
if (next == null && mRepeatingRequest != null) {
next = mRepeatingRequest;
mCurrentRepeatingFrameNumber = mCurrentFrameNumber +
next.getNumberOfRequests();
}
if (next == null) {
return null;
}
RequestQueueEntry ret = new RequestQueueEntry(next, mCurrentFrameNumber, queueEmptied);
mCurrentFrameNumber += next.getNumberOfRequests();
return ret;
}
/**
* Cancel a repeating request.
*
* @param requestId the id of the repeating request to cancel.
* @return the last frame to be returned from the HAL for the given repeating request, or
* {@code INVALID_FRAME} if none exists.
*/
public synchronized long stopRepeating(int requestId) {
long ret = INVALID_FRAME;
if (mRepeatingRequest != null && mRepeatingRequest.getRequestId() == requestId) {
mRepeatingRequest = null;
ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
mCurrentRepeatingFrameNumber - 1;
mCurrentRepeatingFrameNumber = INVALID_FRAME;
Log.i(TAG, "Repeating capture request cancelled.");
} else {
Log.e(TAG, "cancel failed: no repeating request exists for request id: " + requestId);
}
return ret;
}
/**
* Cancel a repeating request.
*
* @return the last frame to be returned from the HAL for the given repeating request, or
* {@code INVALID_FRAME} if none exists.
*/
public synchronized long stopRepeating() {
if (mRepeatingRequest == null) {
Log.e(TAG, "cancel failed: no repeating request exists.");
return INVALID_FRAME;
}
return stopRepeating(mRepeatingRequest.getRequestId());
}
/**
* Add a the given burst to the queue.
*
* <p>If the burst is repeating, replace the current repeating burst.</p>
*
* @param requests the burst of requests to add to the queue.
* @param repeating true if the burst is repeating.
* @return the submission info, including the new request id, and the last frame number, which
* contains either the frame number of the last frame that will be returned for this request,
* or the frame number of the last frame that will be returned for the current repeating
* request if this burst is set to be repeating.
*/
public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
int requestId = mCurrentRequestId++;
BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
long lastFrame = INVALID_FRAME;
if (burst.isRepeating()) {
Log.i(TAG, "Repeating capture request set.");
if (mRepeatingRequest != null) {
lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
mCurrentRepeatingFrameNumber - 1;
}
mCurrentRepeatingFrameNumber = INVALID_FRAME;
mRepeatingRequest = burst;
} else {
mRequestQueue.offer(burst);
lastFrame = calculateLastFrame(burst.getRequestId());
}
SubmitInfo info = new SubmitInfo(requestId, lastFrame);
return info;
}
private long calculateLastFrame(int requestId) {
long total = mCurrentFrameNumber;
for (BurstHolder b : mRequestQueue) {
total += b.getNumberOfRequests();
if (b.getRequestId() == requestId) {
return total - 1;
}
}
throw new IllegalStateException(
"At least one request must be in the queue to calculate frame number");
}
}