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 package android.hardware.camera2.legacy;
17 
18 import android.hardware.camera2.CaptureRequest;
19 import android.hardware.camera2.utils.SubmitInfo;
20 import android.util.Log;
21 
22 import java.util.ArrayDeque;
23 import java.util.List;
24 
25 /**
26  * A queue of bursts of requests.
27  *
28  * <p>This queue maintains the count of frames that have been produced, and is thread safe.</p>
29  */
30 public class RequestQueue {
31     private static final String TAG = "RequestQueue";
32 
33     public static final long INVALID_FRAME = -1;
34 
35     private BurstHolder mRepeatingRequest = null;
36     private final ArrayDeque<BurstHolder> mRequestQueue = new ArrayDeque<BurstHolder>();
37 
38     private long mCurrentFrameNumber = 0;
39     private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
40     private int mCurrentRequestId = 0;
41     private final List<Long> mJpegSurfaceIds;
42 
43     public final class RequestQueueEntry {
44         private final BurstHolder mBurstHolder;
45         private final Long mFrameNumber;
46         private final boolean mQueueEmpty;
47 
getBurstHolder()48         public BurstHolder getBurstHolder() {
49             return mBurstHolder;
50         }
getFrameNumber()51         public Long getFrameNumber() {
52             return mFrameNumber;
53         }
isQueueEmpty()54         public boolean isQueueEmpty() {
55             return mQueueEmpty;
56         }
57 
RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty)58         public RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty) {
59             mBurstHolder = burstHolder;
60             mFrameNumber = frameNumber;
61             mQueueEmpty = queueEmpty;
62         }
63     }
64 
RequestQueue(List<Long> jpegSurfaceIds)65     public RequestQueue(List<Long> jpegSurfaceIds) {
66         mJpegSurfaceIds = jpegSurfaceIds;
67     }
68 
69     /**
70      * Return and remove the next burst on the queue.
71      *
72      * <p>If a repeating burst is returned, it will not be removed.</p>
73      *
74      * @return an entry containing the next burst, the current frame number, and flag about whether
75      * request queue becomes empty. Null if no burst exists.
76      */
getNext()77     public synchronized RequestQueueEntry getNext() {
78         BurstHolder next = mRequestQueue.poll();
79         boolean queueEmptied = (next != null && mRequestQueue.size() == 0);
80         if (next == null && mRepeatingRequest != null) {
81             next = mRepeatingRequest;
82             mCurrentRepeatingFrameNumber = mCurrentFrameNumber +
83                     next.getNumberOfRequests();
84         }
85 
86         if (next == null) {
87             return null;
88         }
89 
90         RequestQueueEntry ret =  new RequestQueueEntry(next, mCurrentFrameNumber, queueEmptied);
91         mCurrentFrameNumber += next.getNumberOfRequests();
92         return ret;
93     }
94 
95     /**
96      * Cancel a repeating request.
97      *
98      * @param requestId the id of the repeating request to cancel.
99      * @return the last frame to be returned from the HAL for the given repeating request, or
100      *          {@code INVALID_FRAME} if none exists.
101      */
stopRepeating(int requestId)102     public synchronized long stopRepeating(int requestId) {
103         long ret = INVALID_FRAME;
104         if (mRepeatingRequest != null && mRepeatingRequest.getRequestId() == requestId) {
105             mRepeatingRequest = null;
106             ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
107                     mCurrentRepeatingFrameNumber - 1;
108             mCurrentRepeatingFrameNumber = INVALID_FRAME;
109             Log.i(TAG, "Repeating capture request cancelled.");
110         } else {
111             Log.e(TAG, "cancel failed: no repeating request exists for request id: " + requestId);
112         }
113         return ret;
114     }
115 
116     /**
117      * Cancel a repeating request.
118      *
119      * @return the last frame to be returned from the HAL for the given repeating request, or
120      *          {@code INVALID_FRAME} if none exists.
121      */
stopRepeating()122     public synchronized long stopRepeating() {
123         if (mRepeatingRequest == null) {
124             Log.e(TAG, "cancel failed: no repeating request exists.");
125             return INVALID_FRAME;
126         }
127         return stopRepeating(mRepeatingRequest.getRequestId());
128     }
129 
130     /**
131      * Add a the given burst to the queue.
132      *
133      * <p>If the burst is repeating, replace the current repeating burst.</p>
134      *
135      * @param requests the burst of requests to add to the queue.
136      * @param repeating true if the burst is repeating.
137      * @return the submission info, including the new request id, and the last frame number, which
138      *   contains either the frame number of the last frame that will be returned for this request,
139      *   or the frame number of the last frame that will be returned for the current repeating
140      *   request if this burst is set to be repeating.
141      */
submit(CaptureRequest[] requests, boolean repeating)142     public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
143         int requestId = mCurrentRequestId++;
144         BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
145         long lastFrame = INVALID_FRAME;
146         if (burst.isRepeating()) {
147             Log.i(TAG, "Repeating capture request set.");
148             if (mRepeatingRequest != null) {
149                 lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
150                         mCurrentRepeatingFrameNumber - 1;
151             }
152             mCurrentRepeatingFrameNumber = INVALID_FRAME;
153             mRepeatingRequest = burst;
154         } else {
155             mRequestQueue.offer(burst);
156             lastFrame = calculateLastFrame(burst.getRequestId());
157         }
158         SubmitInfo info = new SubmitInfo(requestId, lastFrame);
159         return info;
160     }
161 
calculateLastFrame(int requestId)162     private long calculateLastFrame(int requestId) {
163         long total = mCurrentFrameNumber;
164         for (BurstHolder b : mRequestQueue) {
165             total += b.getNumberOfRequests();
166             if (b.getRequestId() == requestId) {
167                 return total - 1;
168             }
169         }
170         throw new IllegalStateException(
171                 "At least one request must be in the queue to calculate frame number");
172     }
173 
174 }
175