/*
* 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.util.Log;
import android.view.Surface;
import java.util.Collection;
import static com.android.internal.util.Preconditions.*;
/**
* Semi-immutable container for a single capture request and associated information,
* the only mutable characteristic of this container is whether or not is has been
* marked as "failed" using {@code #failRequest}.
*/
public class RequestHolder {
private static final String TAG = "RequestHolder";
private final boolean mRepeating;
private final CaptureRequest mRequest;
private final int mRequestId;
private final int mSubsequeceId;
private final long mFrameNumber;
private final int mNumJpegTargets;
private final int mNumPreviewTargets;
private volatile boolean mFailed = false;
/**
* A builder class for {@link RequestHolder} objects.
*
* <p>
* This allows per-request queries to be cached for repeating {@link CaptureRequest} objects.
* </p>
*/
public final static class Builder {
private final int mRequestId;
private final int mSubsequenceId;
private final CaptureRequest mRequest;
private final boolean mRepeating;
private final int mNumJpegTargets;
private final int mNumPreviewTargets;
private final Collection<Long> mJpegSurfaceIds;
/**
* Construct a new {@link Builder} to generate {@link RequestHolder} objects.
*
* @param requestId the ID to set in {@link RequestHolder} objects.
* @param subsequenceId the sequence ID to set in {@link RequestHolder} objects.
* @param request the original {@link CaptureRequest} to set in {@link RequestHolder}
* objects.
* @param repeating {@code true} if the request is repeating.
*/
public Builder(int requestId, int subsequenceId, CaptureRequest request,
boolean repeating, Collection<Long> jpegSurfaceIds) {
checkNotNull(request, "request must not be null");
mRequestId = requestId;
mSubsequenceId = subsequenceId;
mRequest = request;
mRepeating = repeating;
mJpegSurfaceIds = jpegSurfaceIds;
mNumJpegTargets = numJpegTargets(mRequest);
mNumPreviewTargets = numPreviewTargets(mRequest);
}
/**
* Returns true if the given surface requires jpeg buffers.
*
* @param s a {@link android.view.Surface} to check.
* @return true if the surface requires a jpeg buffer.
*/
private boolean jpegType(Surface s)
throws LegacyExceptionUtils.BufferQueueAbandonedException {
return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
}
/**
* Returns true if the given surface requires non-jpeg buffer types.
*
* <p>
* "Jpeg buffer" refers to the buffers returned in the jpeg
* {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee
* of the preview stream drawn to the surface
* set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
* equivalent methods.
* </p>
* @param s a {@link android.view.Surface} to check.
* @return true if the surface requires a non-jpeg buffer type.
*/
private boolean previewType(Surface s)
throws LegacyExceptionUtils.BufferQueueAbandonedException {
return !jpegType(s);
}
/**
* Returns the number of surfaces targeted by the request that require jpeg buffers.
*/
private int numJpegTargets(CaptureRequest request) {
int count = 0;
for (Surface s : request.getTargets()) {
try {
if (jpegType(s)) {
++count;
}
} catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
Log.d(TAG, "Surface abandoned, skipping...", e);
}
}
return count;
}
/**
* Returns the number of surfaces targeted by the request that require non-jpeg buffers.
*/
private int numPreviewTargets(CaptureRequest request) {
int count = 0;
for (Surface s : request.getTargets()) {
try {
if (previewType(s)) {
++count;
}
} catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
Log.d(TAG, "Surface abandoned, skipping...", e);
}
}
return count;
}
/**
* Build a new {@link RequestHolder} using with parameters generated from this
* {@link Builder}.
*
* @param frameNumber the {@code framenumber} to generate in the {@link RequestHolder}.
* @return a {@link RequestHolder} constructed with the {@link Builder}'s parameters.
*/
public RequestHolder build(long frameNumber) {
return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
mNumJpegTargets, mNumPreviewTargets);
}
}
private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
boolean repeating, long frameNumber, int numJpegTargets,
int numPreviewTargets) {
mRepeating = repeating;
mRequest = request;
mRequestId = requestId;
mSubsequeceId = subsequenceId;
mFrameNumber = frameNumber;
mNumJpegTargets = numJpegTargets;
mNumPreviewTargets = numPreviewTargets;
}
/**
* Return the request id for the contained {@link CaptureRequest}.
*/
public int getRequestId() {
return mRequestId;
}
/**
* Returns true if the contained request is repeating.
*/
public boolean isRepeating() {
return mRepeating;
}
/**
* Return the subsequence id for this request.
*/
public int getSubsequeceId() {
return mSubsequeceId;
}
/**
* Returns the frame number for this request.
*/
public long getFrameNumber() {
return mFrameNumber;
}
/**
* Returns the contained request.
*/
public CaptureRequest getRequest() {
return mRequest;
}
/**
* Returns a read-only collection of the surfaces targeted by the contained request.
*/
public Collection<Surface> getHolderTargets() {
return getRequest().getTargets();
}
/**
* Returns true if any of the surfaces targeted by the contained request require jpeg buffers.
*/
public boolean hasJpegTargets() {
return mNumJpegTargets > 0;
}
/**
* Returns true if any of the surfaces targeted by the contained request require a
* non-jpeg buffer type.
*/
public boolean hasPreviewTargets(){
return mNumPreviewTargets > 0;
}
/**
* Return the number of jpeg-type surfaces targeted by this request.
*/
public int numJpegTargets() {
return mNumJpegTargets;
}
/**
* Return the number of non-jpeg-type surfaces targeted by this request.
*/
public int numPreviewTargets() {
return mNumPreviewTargets;
}
/**
* Mark this request as failed.
*/
public void failRequest() {
Log.w(TAG, "Capture failed for request: " + getRequestId());
mFailed = true;
}
/**
* Return {@code true} if this request failed.
*/
public boolean requestFailed() {
return mFailed;
}
}