blob: 64c532bfb9c674076c83263f99b9f9eaa37af8e8 [file] [log] [blame]
Ruben Brunkfeb50af2014-05-09 19:58:49 -07001/*
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.graphics.SurfaceTexture;
Ruben Brunk4aed87a2014-09-21 18:35:31 -070020import android.hardware.camera2.impl.CameraDeviceImpl;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070021import android.os.ConditionVariable;
22import android.os.Handler;
23import android.os.Message;
24import android.util.Log;
25import android.view.Surface;
26
27import java.util.Collection;
28
Ruben Brunk91838de2014-07-16 17:24:17 -070029import static com.android.internal.util.Preconditions.*;
30
Ruben Brunkfeb50af2014-05-09 19:58:49 -070031/**
32 * GLThreadManager handles the thread used for rendering into the configured output surfaces.
33 */
34public class GLThreadManager {
35 private final String TAG;
36 private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
37
38 private static final int MSG_NEW_CONFIGURATION = 1;
39 private static final int MSG_NEW_FRAME = 2;
40 private static final int MSG_CLEANUP = 3;
41 private static final int MSG_DROP_FRAMES = 4;
42 private static final int MSG_ALLOW_FRAMES = 5;
43
Ruben Brunk91838de2014-07-16 17:24:17 -070044 private CaptureCollector mCaptureCollector;
45
Ruben Brunk4aed87a2014-09-21 18:35:31 -070046 private final CameraDeviceState mDeviceState;
47
Ruben Brunkfeb50af2014-05-09 19:58:49 -070048 private final SurfaceTextureRenderer mTextureRenderer;
49
50 private final RequestHandlerThread mGLHandlerThread;
51
52 private final RequestThreadManager.FpsCounter mPrevCounter =
53 new RequestThreadManager.FpsCounter("GL Preview Producer");
54
55 /**
56 * Container object for Configure messages.
57 */
58 private static class ConfigureHolder {
59 public final ConditionVariable condition;
60 public final Collection<Surface> surfaces;
Ruben Brunk91838de2014-07-16 17:24:17 -070061 public final CaptureCollector collector;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070062
Ruben Brunk91838de2014-07-16 17:24:17 -070063 public ConfigureHolder(ConditionVariable condition, Collection<Surface> surfaces,
64 CaptureCollector collector) {
Ruben Brunkfeb50af2014-05-09 19:58:49 -070065 this.condition = condition;
66 this.surfaces = surfaces;
Ruben Brunk91838de2014-07-16 17:24:17 -070067 this.collector = collector;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070068 }
69 }
70
71 private final Handler.Callback mGLHandlerCb = new Handler.Callback() {
72 private boolean mCleanup = false;
73 private boolean mConfigured = false;
74 private boolean mDroppingFrames = false;
75
76 @SuppressWarnings("unchecked")
77 @Override
78 public boolean handleMessage(Message msg) {
79 if (mCleanup) {
80 return true;
81 }
Ruben Brunk4aed87a2014-09-21 18:35:31 -070082 try {
83 switch (msg.what) {
84 case MSG_NEW_CONFIGURATION:
85 ConfigureHolder configure = (ConfigureHolder) msg.obj;
86 mTextureRenderer.cleanupEGLContext();
87 mTextureRenderer.configureSurfaces(configure.surfaces);
88 mCaptureCollector = checkNotNull(configure.collector);
89 configure.condition.open();
90 mConfigured = true;
Ruben Brunkfeb50af2014-05-09 19:58:49 -070091 break;
Ruben Brunk4aed87a2014-09-21 18:35:31 -070092 case MSG_NEW_FRAME:
93 if (mDroppingFrames) {
94 Log.w(TAG, "Ignoring frame.");
95 break;
96 }
97 if (DEBUG) {
98 mPrevCounter.countAndLog();
99 }
100 if (!mConfigured) {
101 Log.e(TAG, "Dropping frame, EGL context not configured!");
102 }
103 mTextureRenderer.drawIntoSurfaces(mCaptureCollector);
104 break;
105 case MSG_CLEANUP:
106 mTextureRenderer.cleanupEGLContext();
107 mCleanup = true;
108 mConfigured = false;
109 break;
110 case MSG_DROP_FRAMES:
111 mDroppingFrames = true;
112 break;
113 case MSG_ALLOW_FRAMES:
114 mDroppingFrames = false;
115 break;
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700116 case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
117 // OK: Ignore message.
118 break;
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700119 default:
120 Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
121 break;
122 }
123 } catch (Exception e) {
124 Log.e(TAG, "Received exception on GL render thread: ", e);
125 mDeviceState.setError(CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700126 }
127 return true;
128 }
129 };
130
131 /**
132 * Create a new GL thread and renderer.
133 *
134 * @param cameraId the camera id for this thread.
Ruben Brunkb68dd5c2014-09-04 21:23:42 -0700135 * @param facing direction the camera is facing.
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700136 * @param state {@link CameraDeviceState} to use for error handling.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700137 */
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700138 public GLThreadManager(int cameraId, int facing, CameraDeviceState state) {
Ruben Brunkb68dd5c2014-09-04 21:23:42 -0700139 mTextureRenderer = new SurfaceTextureRenderer(facing);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700140 TAG = String.format("CameraDeviceGLThread-%d", cameraId);
141 mGLHandlerThread = new RequestHandlerThread(TAG, mGLHandlerCb);
Ruben Brunk4aed87a2014-09-21 18:35:31 -0700142 mDeviceState = state;
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700143 }
144
145 /**
146 * Start the thread.
147 *
148 * <p>
149 * This must be called before queueing new frames.
150 * </p>
151 */
152 public void start() {
153 mGLHandlerThread.start();
154 }
155
156 /**
157 * Wait until the thread has started.
158 */
159 public void waitUntilStarted() {
160 mGLHandlerThread.waitUntilStarted();
161 }
162
163 /**
164 * Quit the thread.
165 *
166 * <p>
167 * No further methods can be called after this.
168 * </p>
169 */
170 public void quit() {
171 Handler handler = mGLHandlerThread.getHandler();
172 handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
173 mGLHandlerThread.quitSafely();
Ruben Brunkd85e1a62014-06-11 10:35:45 -0700174 try {
175 mGLHandlerThread.join();
176 } catch (InterruptedException e) {
177 Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
178 mGLHandlerThread.getName(), mGLHandlerThread.getId()));
179 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700180 }
181
182 /**
Ruben Brunk91838de2014-07-16 17:24:17 -0700183 * Queue a new call to draw into the surfaces specified in the next available preview
184 * request from the {@link CaptureCollector} passed to
185 * {@link #setConfigurationAndWait(java.util.Collection, CaptureCollector)};
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700186 */
Ruben Brunk91838de2014-07-16 17:24:17 -0700187 public void queueNewFrame() {
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700188 Handler handler = mGLHandlerThread.getHandler();
189
190 /**
191 * Avoid queuing more than one new frame. If we are not consuming faster than frames
192 * are produced, drop frames rather than allowing the queue to back up.
193 */
194 if (!handler.hasMessages(MSG_NEW_FRAME)) {
Ruben Brunk91838de2014-07-16 17:24:17 -0700195 handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME));
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700196 } else {
197 Log.e(TAG, "GLThread dropping frame. Not consuming frames quickly enough!");
198 }
199 }
200
201 /**
202 * Configure the GL renderer for the given set of output surfaces, and block until
203 * this configuration has been applied.
204 *
205 * @param surfaces a collection of {@link android.view.Surface}s to configure.
Ruben Brunk91838de2014-07-16 17:24:17 -0700206 * @param collector a {@link CaptureCollector} to retrieve requests from.
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700207 */
Ruben Brunk91838de2014-07-16 17:24:17 -0700208 public void setConfigurationAndWait(Collection<Surface> surfaces, CaptureCollector collector) {
209 checkNotNull(collector, "collector must not be null");
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700210 Handler handler = mGLHandlerThread.getHandler();
211
212 final ConditionVariable condition = new ConditionVariable(/*closed*/false);
Ruben Brunk91838de2014-07-16 17:24:17 -0700213 ConfigureHolder configure = new ConfigureHolder(condition, surfaces, collector);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700214
215 Message m = handler.obtainMessage(MSG_NEW_CONFIGURATION, /*arg1*/0, /*arg2*/0, configure);
216 handler.sendMessage(m);
217
218 // Block until configuration applied.
219 condition.block();
220 }
221
222 /**
223 * Get the underlying surface to produce frames from.
224 *
225 * <p>
226 * This returns the surface that is drawn into the set of surfaces passed in for each frame.
227 * This method should only be called after a call to
228 * {@link #setConfigurationAndWait(java.util.Collection)}. Calling this before the first call
229 * to {@link #setConfigurationAndWait(java.util.Collection)}, after {@link #quit()}, or
230 * concurrently to one of these calls may result in an invalid
231 * {@link android.graphics.SurfaceTexture} being returned.
232 * </p>
233 *
234 * @return an {@link android.graphics.SurfaceTexture} to draw to.
235 */
236 public SurfaceTexture getCurrentSurfaceTexture() {
237 return mTextureRenderer.getSurfaceTexture();
238 }
239
240 /**
241 * Ignore any subsequent calls to {@link #queueNewFrame(java.util.Collection)}.
242 */
243 public void ignoreNewFrames() {
244 mGLHandlerThread.getHandler().sendEmptyMessage(MSG_DROP_FRAMES);
245 }
246
247 /**
248 * Wait until no messages are queued.
249 */
250 public void waitUntilIdle() {
251 mGLHandlerThread.waitUntilIdle();
252 }
253
254 /**
255 * Re-enable drawing new frames after a call to {@link #ignoreNewFrames()}.
256 */
257 public void allowNewFrames() {
258 mGLHandlerThread.getHandler().sendEmptyMessage(MSG_ALLOW_FRAMES);
259 }
260}