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