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      */
getFrameWidth()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      */
getFrameHeight()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      */
getFrameBufferSize()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      */
getPixelNum()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      */
getOriginalPixelFormat()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 
isInitialized()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     }
isConnected()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     }
isStarted()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      */
changeExposure(const uint8_t & inputY)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:
WorkerThread(EmulatedCameraDevice * camera_dev)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 
~WorkerThread()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              */
startThread(bool one_burst)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. */
threadLoop()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. */
getWorkerThread()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