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 
17 package android.hardware.camera2.legacy;
18 
19 import android.hardware.camera2.CaptureRequest;
20 import android.util.Log;
21 import android.view.Surface;
22 
23 import java.util.Collection;
24 
25 import 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  */
32 public 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          */
Builder(int requestId, int subsequenceId, CaptureRequest request, boolean repeating, Collection<Long> jpegSurfaceIds)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          */
jpegType(Surface s)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          */
previewType(Surface s)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          */
numJpegTargets(CaptureRequest request)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          */
numPreviewTargets(CaptureRequest request)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          */
build(long frameNumber)154         public RequestHolder build(long frameNumber) {
155             return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
156                     mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
157         }
158     }
159 
RequestHolder(int requestId, int subsequenceId, CaptureRequest request, boolean repeating, long frameNumber, int numJpegTargets, int numPreviewTargets, Collection<Long> jpegSurfaceIds)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      */
getRequestId()176     public int getRequestId() {
177         return mRequestId;
178     }
179 
180     /**
181      * Returns true if the contained request is repeating.
182      */
isRepeating()183     public boolean isRepeating() {
184         return mRepeating;
185     }
186 
187     /**
188      * Return the subsequence id for this request.
189      */
getSubsequeceId()190     public int getSubsequeceId() {
191         return mSubsequeceId;
192     }
193 
194     /**
195      * Returns the frame number for this request.
196      */
getFrameNumber()197     public long getFrameNumber() {
198         return mFrameNumber;
199     }
200 
201     /**
202      * Returns the contained request.
203      */
getRequest()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      */
getHolderTargets()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      */
hasJpegTargets()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      */
hasPreviewTargets()226     public boolean hasPreviewTargets(){
227         return mNumPreviewTargets > 0;
228     }
229 
230     /**
231      * Return the number of jpeg-type surfaces targeted by this request.
232      */
numJpegTargets()233     public int numJpegTargets() {
234         return mNumJpegTargets;
235     }
236 
237     /**
238      * Return the number of non-jpeg-type surfaces targeted by this request.
239      */
numPreviewTargets()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      */
jpegType(Surface s)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      */
failRequest()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      */
requestFailed()266     public boolean requestFailed() {
267         return mFailed;
268     }
269 
270     /**
271      * Mark at least one of this request's output surfaces is abandoned.
272      */
setOutputAbandoned()273     public void setOutputAbandoned() {
274         mOutputAbandoned = true;
275     }
276 
277     /**
278      * Return if any of this request's output surface is abandoned.
279      */
isOutputAbandoned()280     public boolean isOutputAbandoned() {
281         return mOutputAbandoned;
282     }
283 }
284