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