blob: b7cdcb7a4a64cdce15e9ae8b4e5ddae139d1a22a
1 | /* |
2 | * Copyright (C) 2011 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 | #ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H |
18 | #define HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H |
19 | |
20 | /* |
21 | * Contains declaration of an abstract class EmulatedCameraDevice that defines |
22 | * functionality expected from an emulated physical camera device: |
23 | * - Obtaining and setting camera device parameters |
24 | * - Capturing frames |
25 | * - Streaming video |
26 | * - etc. |
27 | */ |
28 | |
29 | #include <utils/threads.h> |
30 | #include <utils/KeyedVector.h> |
31 | #include <utils/String8.h> |
32 | #include "EmulatedCameraCommon.h" |
33 | #include "Converters.h" |
34 | |
35 | namespace android { |
36 | |
37 | class EmulatedCamera; |
38 | |
39 | /* Encapsulates an abstract class EmulatedCameraDevice that defines |
40 | * functionality expected from an emulated physical camera device: |
41 | * - Obtaining and setting camera device parameters |
42 | * - Capturing frames |
43 | * - Streaming video |
44 | * - etc. |
45 | */ |
46 | class EmulatedCameraDevice { |
47 | public: |
48 | /* Constructs EmulatedCameraDevice instance. |
49 | * Param: |
50 | * camera_hal - Emulated camera that implements the camera HAL API, and |
51 | * manages (contains) this object. |
52 | */ |
53 | explicit EmulatedCameraDevice(EmulatedCamera* camera_hal); |
54 | |
55 | /* Destructs EmulatedCameraDevice instance. */ |
56 | virtual ~EmulatedCameraDevice(); |
57 | |
58 | /*************************************************************************** |
59 | * Emulated camera device abstract interface |
60 | **************************************************************************/ |
61 | |
62 | public: |
63 | /* Connects to the camera device. |
64 | * This method must be called on an initialized instance of this class. |
65 | * Return: |
66 | * NO_ERROR on success, or an appropriate error status. |
67 | */ |
68 | virtual status_t connectDevice() = 0; |
69 | |
70 | /* Disconnects from the camera device. |
71 | * Return: |
72 | * NO_ERROR on success, or an appropriate error status. If this method is |
73 | * called for already disconnected, or uninitialized instance of this class, |
74 | * a successful status must be returned from this method. If this method is |
75 | * called for an instance that is in the "started" state, this method must |
76 | * return a failure. |
77 | */ |
78 | virtual status_t disconnectDevice() = 0; |
79 | |
80 | /* Starts the camera device. |
81 | * This method tells the camera device to start capturing frames of the given |
82 | * dimensions for the given pixel format. Note that this method doesn't start |
83 | * the delivery of the captured frames to the emulated camera. Call |
84 | * startDeliveringFrames method to start delivering frames. This method must |
85 | * be called on a connected instance of this class. If it is called on a |
86 | * disconnected instance, this method must return a failure. |
87 | * Param: |
88 | * width, height - Frame dimensions to use when capturing video frames. |
89 | * pix_fmt - Pixel format to use when capturing video frames. |
90 | * Return: |
91 | * NO_ERROR on success, or an appropriate error status. |
92 | */ |
93 | virtual status_t startDevice(int width, int height, uint32_t pix_fmt) = 0; |
94 | |
95 | /* Stops the camera device. |
96 | * This method tells the camera device to stop capturing frames. Note that |
97 | * this method doesn't stop delivering frames to the emulated camera. Always |
98 | * call stopDeliveringFrames prior to calling this method. |
99 | * Return: |
100 | * NO_ERROR on success, or an appropriate error status. If this method is |
101 | * called for an object that is not capturing frames, or is disconnected, |
102 | * or is uninitialized, a successful status must be returned from this |
103 | * method. |
104 | */ |
105 | virtual status_t stopDevice() = 0; |
106 | |
107 | /*************************************************************************** |
108 | * Emulated camera device public API |
109 | **************************************************************************/ |
110 | |
111 | public: |
112 | /* Initializes EmulatedCameraDevice instance. |
113 | * Derived classes should override this method in order to cache static |
114 | * properties of the physical device (list of supported pixel formats, frame |
115 | * sizes, etc.) If this method is called on an already initialized instance, |
116 | * it must return a successful status. |
117 | * Return: |
118 | * NO_ERROR on success, or an appropriate error status. |
119 | */ |
120 | virtual status_t Initialize(); |
121 | |
122 | /* Initializes the white balance modes parameters. |
123 | * The parameters are passed by each individual derived camera API to |
124 | * represent that different camera manufacturers may have different |
125 | * preferences on the white balance parameters. Green channel in the RGB |
126 | * color space is fixed to keep the luminance to be reasonably constant. |
127 | * |
128 | * Param: |
129 | * mode the text describing the current white balance mode |
130 | * r_scale the scale factor for the R channel in RGB space |
131 | * b_scale the scale factor for the B channel in RGB space. |
132 | */ |
133 | void initializeWhiteBalanceModes(const char* mode, |
134 | const float r_scale, |
135 | const float b_scale); |
136 | |
137 | /* Starts delivering frames captured from the camera device. |
138 | * This method will start the worker thread that would be pulling frames from |
139 | * the camera device, and will deliver the pulled frames back to the emulated |
140 | * camera via onNextFrameAvailable callback. This method must be called on a |
141 | * connected instance of this class with a started camera device. If it is |
142 | * called on a disconnected instance, or camera device has not been started, |
143 | * this method must return a failure. |
144 | * Param: |
145 | * one_burst - Controls how many frames should be delivered. If this |
146 | * parameter is 'true', only one captured frame will be delivered to the |
147 | * emulated camera. If this parameter is 'false', frames will keep |
148 | * coming until stopDeliveringFrames method is called. Typically, this |
149 | * parameter is set to 'true' only in order to obtain a single frame |
150 | * that will be used as a "picture" in takePicture method of the |
151 | * emulated camera. |
152 | * Return: |
153 | * NO_ERROR on success, or an appropriate error status. |
154 | */ |
155 | virtual status_t startDeliveringFrames(bool one_burst); |
156 | |
157 | /* Stops delivering frames captured from the camera device. |
158 | * This method will stop the worker thread started by startDeliveringFrames. |
159 | * Return: |
160 | * NO_ERROR on success, or an appropriate error status. |
161 | */ |
162 | virtual status_t stopDeliveringFrames(); |
163 | |
164 | /* Sets the exposure compensation for the camera device. |
165 | */ |
166 | void setExposureCompensation(const float ev); |
167 | |
168 | /* Sets the white balance mode for the device. |
169 | */ |
170 | void setWhiteBalanceMode(const char* mode); |
171 | |
172 | /* Gets current framebuffer, converted into preview frame format. |
173 | * This method must be called on a connected instance of this class with a |
174 | * started camera device. If it is called on a disconnected instance, or |
175 | * camera device has not been started, this method must return a failure. |
176 | * Note that this method should be called only after at least one frame has |
177 | * been captured and delivered. Otherwise it will return garbage in the |
178 | * preview frame buffer. Typically, this method shuld be called from |
179 | * onNextFrameAvailable callback. |
180 | * Param: |
181 | * buffer - Buffer, large enough to contain the entire preview frame. |
182 | * Return: |
183 | * NO_ERROR on success, or an appropriate error status. |
184 | */ |
185 | virtual status_t getCurrentPreviewFrame(void* buffer); |
186 | |
187 | /* Gets width of the frame obtained from the physical device. |
188 | * Return: |
189 | * Width of the frame obtained from the physical device. Note that value |
190 | * returned from this method is valid only in case if camera device has been |
191 | * started. |
192 | */ |
193 | inline int getFrameWidth() const |
194 | { |
195 | ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__); |
196 | return mFrameWidth; |
197 | } |
198 | |
199 | /* Gets height of the frame obtained from the physical device. |
200 | * Return: |
201 | * Height of the frame obtained from the physical device. Note that value |
202 | * returned from this method is valid only in case if camera device has been |
203 | * started. |
204 | */ |
205 | inline int getFrameHeight() const |
206 | { |
207 | ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__); |
208 | return mFrameHeight; |
209 | } |
210 | |
211 | /* Gets byte size of the current frame buffer. |
212 | * Return: |
213 | * Byte size of the frame buffer. Note that value returned from this method |
214 | * is valid only in case if camera device has been started. |
215 | */ |
216 | inline size_t getFrameBufferSize() const |
217 | { |
218 | ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__); |
219 | return mFrameBufferSize; |
220 | } |
221 | |
222 | /* Gets number of pixels in the current frame buffer. |
223 | * Return: |
224 | * Number of pixels in the frame buffer. Note that value returned from this |
225 | * method is valid only in case if camera device has been started. |
226 | */ |
227 | inline int getPixelNum() const |
228 | { |
229 | ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__); |
230 | return mTotalPixels; |
231 | } |
232 | |
233 | /* Gets pixel format of the frame that camera device streams to this class. |
234 | * Throughout camera framework, there are three different forms of pixel |
235 | * format representation: |
236 | * - Original format, as reported by the actual camera device. Values for |
237 | * this format are declared in bionic/libc/kernel/common/linux/videodev2.h |
238 | * - String representation as defined in CameraParameters::PIXEL_FORMAT_XXX |
239 | * strings in frameworks/base/include/camera/CameraParameters.h |
240 | * - HAL_PIXEL_FORMAT_XXX format, as defined in system/core/include/system/graphics.h |
241 | * Since emulated camera device gets its data from the actual device, it gets |
242 | * pixel format in the original form. And that's the pixel format |
243 | * representation that will be returned from this method. HAL components will |
244 | * need to translate value returned from this method to the appropriate form. |
245 | * This method must be called only on started instance of this class, since |
246 | * it's applicable only when camera device is ready to stream frames. |
247 | * Param: |
248 | * pix_fmt - Upon success contains the original pixel format. |
249 | * Return: |
250 | * Current framebuffer's pixel format. Note that value returned from this |
251 | * method is valid only in case if camera device has been started. |
252 | */ |
253 | inline uint32_t getOriginalPixelFormat() const |
254 | { |
255 | ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__); |
256 | return mPixelFormat; |
257 | } |
258 | |
259 | /* |
260 | * State checkers. |
261 | */ |
262 | |
263 | inline bool isInitialized() const { |
264 | /* Instance is initialized when the worker thread has been successfuly |
265 | * created (but not necessarily started). */ |
266 | return mWorkerThread.get() != NULL && mState != ECDS_CONSTRUCTED; |
267 | } |
268 | inline bool isConnected() const { |
269 | /* Instance is connected when its status is either"connected", or |
270 | * "started". */ |
271 | return mState == ECDS_CONNECTED || mState == ECDS_STARTED; |
272 | } |
273 | inline bool isStarted() const { |
274 | return mState == ECDS_STARTED; |
275 | } |
276 | |
277 | /**************************************************************************** |
278 | * Emulated camera device private API |
279 | ***************************************************************************/ |
280 | protected: |
281 | /* Performs common validation and calculation of startDevice parameters. |
282 | * Param: |
283 | * width, height, pix_fmt - Parameters passed to the startDevice method. |
284 | * Return: |
285 | * NO_ERROR on success, or an appropriate error status. |
286 | */ |
287 | virtual status_t commonStartDevice(int width, int height, uint32_t pix_fmt); |
288 | |
289 | /* Performs common cleanup on stopDevice. |
290 | * This method will undo what commonStartDevice had done. |
291 | */ |
292 | virtual void commonStopDevice(); |
293 | |
294 | /** Computes a luminance value after taking the exposure compensation. |
295 | * value into account. |
296 | * |
297 | * Param: |
298 | * inputY - The input luminance value. |
299 | * Return: |
300 | * The luminance value after adjusting the exposure compensation. |
301 | */ |
302 | inline uint8_t changeExposure(const uint8_t& inputY) const { |
303 | return static_cast<uint8_t>(clamp(static_cast<float>(inputY) * |
304 | mExposureCompensation)); |
305 | } |
306 | |
307 | /** Computes the pixel value in YUV space after adjusting to the current |
308 | * white balance mode. |
309 | */ |
310 | void changeWhiteBalance(uint8_t& y, uint8_t& u, uint8_t& v) const; |
311 | |
312 | /**************************************************************************** |
313 | * Worker thread management. |
314 | * Typicaly when emulated camera device starts capturing frames from the |
315 | * actual device, it does that in a worker thread created in StartCapturing, |
316 | * and terminated in StopCapturing. Since this is such a typical scenario, |
317 | * it makes sence to encapsulate worker thread management in the base class |
318 | * for all emulated camera devices. |
319 | ***************************************************************************/ |
320 | |
321 | protected: |
322 | /* Starts the worker thread. |
323 | * Typically, worker thread is started from startDeliveringFrames method of |
324 | * this class. |
325 | * Param: |
326 | * one_burst - Controls how many times thread loop should run. If this |
327 | * parameter is 'true', thread routine will run only once If this |
328 | * parameter is 'false', thread routine will run until stopWorkerThread |
329 | * method is called. See startDeliveringFrames for more info. |
330 | * Return: |
331 | * NO_ERROR on success, or an appropriate error status. |
332 | */ |
333 | virtual status_t startWorkerThread(bool one_burst); |
334 | |
335 | /* Stops the worker thread. |
336 | * Note that this method will always wait for the worker thread to terminate. |
337 | * Typically, worker thread is started from stopDeliveringFrames method of |
338 | * this class. |
339 | * Return: |
340 | * NO_ERROR on success, or an appropriate error status. |
341 | */ |
342 | virtual status_t stopWorkerThread(); |
343 | |
344 | /* Implementation of the worker thread routine. |
345 | * In the default implementation of the worker thread routine we simply |
346 | * return 'false' forcing the thread loop to exit, and the thread to |
347 | * terminate. Derived class should override that method to provide there the |
348 | * actual frame delivery. |
349 | * Return: |
350 | * true To continue thread loop (this method will be called again), or false |
351 | * to exit the thread loop and to terminate the thread. |
352 | */ |
353 | virtual bool inWorkerThread(); |
354 | |
355 | /* Encapsulates a worker thread used by the emulated camera device. |
356 | */ |
357 | friend class WorkerThread; |
358 | class WorkerThread : public Thread { |
359 | |
360 | /**************************************************************************** |
361 | * Public API |
362 | ***************************************************************************/ |
363 | |
364 | public: |
365 | inline explicit WorkerThread(EmulatedCameraDevice* camera_dev) |
366 | : Thread(true), // Callbacks may involve Java calls. |
367 | mCameraDevice(camera_dev), |
368 | mThreadControl(-1), |
369 | mControlFD(-1) |
370 | { |
371 | } |
372 | |
373 | inline ~WorkerThread() |
374 | { |
375 | ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0, |
376 | "%s: Control FDs are opened in the destructor", |
377 | __FUNCTION__); |
378 | if (mThreadControl >= 0) { |
379 | close(mThreadControl); |
380 | } |
381 | if (mControlFD >= 0) { |
382 | close(mControlFD); |
383 | } |
384 | } |
385 | |
386 | /* Starts the thread |
387 | * Param: |
388 | * one_burst - Controls how many times thread loop should run. If |
389 | * this parameter is 'true', thread routine will run only once |
390 | * If this parameter is 'false', thread routine will run until |
391 | * stopThread method is called. See startWorkerThread for more |
392 | * info. |
393 | * Return: |
394 | * NO_ERROR on success, or an appropriate error status. |
395 | */ |
396 | inline status_t startThread(bool one_burst) |
397 | { |
398 | mOneBurst = one_burst; |
399 | return run(NULL, ANDROID_PRIORITY_URGENT_DISPLAY, 0); |
400 | } |
401 | |
402 | /* Overriden base class method. |
403 | * It is overriden in order to provide one-time initialization just |
404 | * prior to starting the thread routine. |
405 | */ |
406 | status_t readyToRun(); |
407 | |
408 | /* Stops the thread. */ |
409 | status_t stopThread(); |
410 | |
411 | /* Values returned from the Select method of this class. */ |
412 | enum SelectRes { |
413 | /* A timeout has occurred. */ |
414 | TIMEOUT, |
415 | /* Data are available for read on the provided FD. */ |
416 | READY, |
417 | /* Thread exit request has been received. */ |
418 | EXIT_THREAD, |
419 | /* An error has occurred. */ |
420 | ERROR |
421 | }; |
422 | |
423 | /* Select on an FD event, keeping in mind thread exit message. |
424 | * Param: |
425 | * fd - File descriptor on which to wait for an event. This |
426 | * parameter may be negative. If it is negative this method will |
427 | * only wait on a control message to the thread. |
428 | * timeout - Timeout in microseconds. 0 indicates no timeout (wait |
429 | * forever). |
430 | * Return: |
431 | * See SelectRes enum comments. |
432 | */ |
433 | SelectRes Select(int fd, int timeout); |
434 | |
435 | /**************************************************************************** |
436 | * Private API |
437 | ***************************************************************************/ |
438 | |
439 | private: |
440 | /* Implements abstract method of the base Thread class. */ |
441 | bool threadLoop() |
442 | { |
443 | /* Simply dispatch the call to the containing camera device. */ |
444 | if (mCameraDevice->inWorkerThread()) { |
445 | /* Respect "one burst" parameter (see startThread). */ |
446 | return !mOneBurst; |
447 | } else { |
448 | return false; |
449 | } |
450 | } |
451 | |
452 | /* Containing camera device object. */ |
453 | EmulatedCameraDevice* mCameraDevice; |
454 | |
455 | /* FD that is used to send control messages into the thread. */ |
456 | int mThreadControl; |
457 | |
458 | /* FD that thread uses to receive control messages. */ |
459 | int mControlFD; |
460 | |
461 | /* Controls number of times the thread loop runs. |
462 | * See startThread for more information. */ |
463 | bool mOneBurst; |
464 | |
465 | /* Enumerates control messages that can be sent into the thread. */ |
466 | enum ControlMessage { |
467 | /* Stop the thread. */ |
468 | THREAD_STOP |
469 | }; |
470 | }; |
471 | |
472 | /* Worker thread accessor. */ |
473 | inline WorkerThread* getWorkerThread() const |
474 | { |
475 | return mWorkerThread.get(); |
476 | } |
477 | |
478 | /**************************************************************************** |
479 | * Data members |
480 | ***************************************************************************/ |
481 | |
482 | protected: |
483 | /* Locks this instance for parameters, state, etc. change. */ |
484 | Mutex mObjectLock; |
485 | |
486 | /* Worker thread that is used in frame capturing. */ |
487 | sp<WorkerThread> mWorkerThread; |
488 | |
489 | /* Timestamp of the current frame. */ |
490 | nsecs_t mCurFrameTimestamp; |
491 | |
492 | /* Emulated camera object containing this instance. */ |
493 | EmulatedCamera* mCameraHAL; |
494 | |
495 | /* Framebuffer containing the current frame. */ |
496 | uint8_t* mCurrentFrame; |
497 | |
498 | /* |
499 | * Framebuffer properties. |
500 | */ |
501 | |
502 | /* Byte size of the framebuffer. */ |
503 | size_t mFrameBufferSize; |
504 | |
505 | /* Original pixel format (one of the V4L2_PIX_FMT_XXX values, as defined in |
506 | * bionic/libc/kernel/common/linux/videodev2.h */ |
507 | uint32_t mPixelFormat; |
508 | |
509 | /* Frame width */ |
510 | int mFrameWidth; |
511 | |
512 | /* Frame height */ |
513 | int mFrameHeight; |
514 | |
515 | /* Total number of pixels */ |
516 | int mTotalPixels; |
517 | |
518 | /* Exposure compensation value */ |
519 | float mExposureCompensation; |
520 | |
521 | float* mWhiteBalanceScale; |
522 | |
523 | DefaultKeyedVector<String8, float*> mSupportedWhiteBalanceScale; |
524 | |
525 | /* Defines possible states of the emulated camera device object. |
526 | */ |
527 | enum EmulatedCameraDeviceState { |
528 | /* Object has been constructed. */ |
529 | ECDS_CONSTRUCTED, |
530 | /* Object has been initialized. */ |
531 | ECDS_INITIALIZED, |
532 | /* Object has been connected to the physical device. */ |
533 | ECDS_CONNECTED, |
534 | /* Camera device has been started. */ |
535 | ECDS_STARTED, |
536 | }; |
537 | |
538 | /* Object state. */ |
539 | EmulatedCameraDeviceState mState; |
540 | }; |
541 | |
542 | }; /* namespace android */ |
543 | |
544 | #endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H */ |
545 |