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
17package android.hardware.camera2.legacy;
18
19import android.hardware.camera2.CaptureRequest;
20import android.hardware.camera2.impl.CameraMetadataNative;
21import android.util.Log;
22import android.view.Surface;
23
24import java.util.Collection;
25
26import static com.android.internal.util.Preconditions.*;
27
28/**
29 * Semi-immutable container for a single capture request and associated information,
30 * the only mutable characteristic of this container is whether or not is has been
31 * marked as "failed" using {@code #failRequest}.
32 */
33public class RequestHolder {
34    private static final String TAG = "RequestHolder";
35
36    private final boolean mRepeating;
37    private final CaptureRequest mRequest;
38    private final int mRequestId;
39    private final int mSubsequeceId;
40    private final long mFrameNumber;
41    private final int mNumJpegTargets;
42    private final int mNumPreviewTargets;
43    private volatile boolean mFailed = false;
44
45    /**
46     * A builder class for {@link RequestHolder} objects.
47     *
48     * <p>
49     * This allows per-request queries to be cached for repeating {@link CaptureRequest} objects.
50     * </p>
51     */
52    public final static class Builder {
53        private final int mRequestId;
54        private final int mSubsequenceId;
55        private final CaptureRequest mRequest;
56        private final boolean mRepeating;
57        private final int mNumJpegTargets;
58        private final int mNumPreviewTargets;
59        private final Collection<Long> mJpegSurfaceIds;
60
61        /**
62         * Construct a new {@link Builder} to generate {@link RequestHolder} objects.
63         *
64         * @param requestId the ID to set in {@link RequestHolder} objects.
65         * @param subsequenceId the sequence ID to set in {@link RequestHolder} objects.
66         * @param request the original {@link CaptureRequest} to set in {@link RequestHolder}
67         *                objects.
68         * @param repeating {@code true} if the request is repeating.
69         */
70        public Builder(int requestId, int subsequenceId, CaptureRequest request,
71                       boolean repeating, Collection<Long> jpegSurfaceIds) {
72            checkNotNull(request, "request must not be null");
73            mRequestId = requestId;
74            mSubsequenceId = subsequenceId;
75            mRequest = request;
76            mRepeating = repeating;
77            mJpegSurfaceIds = jpegSurfaceIds;
78            mNumJpegTargets = numJpegTargets(mRequest);
79            mNumPreviewTargets = numPreviewTargets(mRequest);
80        }
81
82        /**
83         * Returns true if the given surface requires jpeg buffers.
84         *
85         * @param s a {@link android.view.Surface} to check.
86         * @return true if the surface requires a jpeg buffer.
87         */
88        private boolean jpegType(Surface s)
89                throws LegacyExceptionUtils.BufferQueueAbandonedException {
90            return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
91        }
92
93        /**
94         * Returns true if the given surface requires non-jpeg buffer types.
95         *
96         * <p>
97         * "Jpeg buffer" refers to the buffers returned in the jpeg
98         * {@link android.hardware.Camera.PictureCallback}.  Non-jpeg buffers are created using a tee
99         * of the preview stream drawn to the surface
100         * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
101         * equivalent methods.
102         * </p>
103         * @param s a {@link android.view.Surface} to check.
104         * @return true if the surface requires a non-jpeg buffer type.
105         */
106        private boolean previewType(Surface s)
107                throws LegacyExceptionUtils.BufferQueueAbandonedException {
108            return !jpegType(s);
109        }
110
111        /**
112         * Returns the number of surfaces targeted by the request that require jpeg buffers.
113         */
114        private int numJpegTargets(CaptureRequest request) {
115            int count = 0;
116            for (Surface s : request.getTargets()) {
117                try {
118                    if (jpegType(s)) {
119                        ++count;
120                    }
121                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
122                    Log.d(TAG, "Surface abandoned, skipping...", e);
123                }
124            }
125            return count;
126        }
127
128        /**
129         * Returns the number of surfaces targeted by the request that require non-jpeg buffers.
130         */
131        private int numPreviewTargets(CaptureRequest request) {
132            int count = 0;
133            for (Surface s : request.getTargets()) {
134                try {
135                    if (previewType(s)) {
136                        ++count;
137                    }
138                } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
139                    Log.d(TAG, "Surface abandoned, skipping...", e);
140                }
141            }
142            return count;
143        }
144
145        /**
146         * Build a new {@link RequestHolder} using with parameters generated from this
147         *      {@link Builder}.
148         *
149         * @param frameNumber the {@code framenumber} to generate in the {@link RequestHolder}.
150         * @return a {@link RequestHolder} constructed with the {@link Builder}'s parameters.
151         */
152        public RequestHolder build(long frameNumber) {
153            return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
154                    mNumJpegTargets, mNumPreviewTargets);
155        }
156    }
157
158    private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
159                          boolean repeating, long frameNumber, int numJpegTargets,
160                          int numPreviewTargets) {
161        mRepeating = repeating;
162        mRequest = request;
163        mRequestId = requestId;
164        mSubsequeceId = subsequenceId;
165        mFrameNumber = frameNumber;
166        mNumJpegTargets = numJpegTargets;
167        mNumPreviewTargets = numPreviewTargets;
168    }
169
170    /**
171     * Return the request id for the contained {@link CaptureRequest}.
172     */
173    public int getRequestId() {
174        return mRequestId;
175    }
176
177    /**
178     * Returns true if the contained request is repeating.
179     */
180    public boolean isRepeating() {
181        return mRepeating;
182    }
183
184    /**
185     * Return the subsequence id for this request.
186     */
187    public int getSubsequeceId() {
188        return mSubsequeceId;
189    }
190
191    /**
192     * Returns the frame number for this request.
193     */
194    public long getFrameNumber() {
195        return mFrameNumber;
196    }
197
198    /**
199     * Returns the contained request.
200     */
201    public CaptureRequest getRequest() {
202        return mRequest;
203    }
204
205    /**
206     * Returns a read-only collection of the surfaces targeted by the contained request.
207     */
208    public Collection<Surface> getHolderTargets() {
209        return getRequest().getTargets();
210    }
211
212    /**
213     * Returns true if any of the surfaces targeted by the contained request require jpeg buffers.
214     */
215    public boolean hasJpegTargets() {
216        return mNumJpegTargets > 0;
217    }
218
219    /**
220     * Returns true if any of the surfaces targeted by the contained request require a
221     * non-jpeg buffer type.
222     */
223    public boolean hasPreviewTargets(){
224        return mNumPreviewTargets > 0;
225    }
226
227    /**
228     * Return the number of jpeg-type surfaces targeted by this request.
229     */
230    public int numJpegTargets() {
231        return mNumJpegTargets;
232    }
233
234    /**
235     * Return the number of non-jpeg-type surfaces targeted by this request.
236     */
237    public int numPreviewTargets() {
238        return mNumPreviewTargets;
239    }
240
241    /**
242     * Mark this request as failed.
243     */
244    public void failRequest() {
245        Log.w(TAG, "Capture failed for request: " + getRequestId());
246        mFailed = true;
247    }
248
249    /**
250     * Return {@code true} if this request failed.
251     */
252    public boolean requestFailed() {
253        return mFailed;
254    }
255
256}
257