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