/* * 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. * *

* This allows per-request queries to be cached for repeating {@link CaptureRequest} objects. *

*/ 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 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 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. * *

* "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. *

* @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 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; } }