546 lines
21 KiB
C++
Executable file
546 lines
21 KiB
C++
Executable file
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
|
|
#define HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H
|
|
|
|
/*
|
|
* Contains declaration of an abstract class EmulatedCameraDevice that defines
|
|
* functionality expected from an emulated physical camera device:
|
|
* - Obtaining and setting camera device parameters
|
|
* - Capturing frames
|
|
* - Streaming video
|
|
* - etc.
|
|
*/
|
|
|
|
#include <utils/threads.h>
|
|
#include <utils/KeyedVector.h>
|
|
#include <utils/String8.h>
|
|
#include "EmulatedCameraCommon.h"
|
|
#include "Converters.h"
|
|
|
|
namespace android {
|
|
|
|
class EmulatedCamera;
|
|
|
|
/* Encapsulates an abstract class EmulatedCameraDevice that defines
|
|
* functionality expected from an emulated physical camera device:
|
|
* - Obtaining and setting camera device parameters
|
|
* - Capturing frames
|
|
* - Streaming video
|
|
* - etc.
|
|
*/
|
|
class EmulatedCameraDevice {
|
|
public:
|
|
/* Constructs EmulatedCameraDevice instance.
|
|
* Param:
|
|
* camera_hal - Emulated camera that implements the camera HAL API, and
|
|
* manages (contains) this object.
|
|
*/
|
|
explicit EmulatedCameraDevice(EmulatedCamera* camera_hal);
|
|
|
|
/* Destructs EmulatedCameraDevice instance. */
|
|
virtual ~EmulatedCameraDevice();
|
|
|
|
/***************************************************************************
|
|
* Emulated camera device abstract interface
|
|
**************************************************************************/
|
|
|
|
public:
|
|
/* Connects to the camera device.
|
|
* This method must be called on an initialized instance of this class.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t connectDevice() = 0;
|
|
|
|
/* Disconnects from the camera device.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status. If this method is
|
|
* called for already disconnected, or uninitialized instance of this class,
|
|
* a successful status must be returned from this method. If this method is
|
|
* called for an instance that is in the "started" state, this method must
|
|
* return a failure.
|
|
*/
|
|
virtual status_t disconnectDevice() = 0;
|
|
|
|
/* Starts the camera device.
|
|
* This method tells the camera device to start capturing frames of the given
|
|
* dimensions for the given pixel format. Note that this method doesn't start
|
|
* the delivery of the captured frames to the emulated camera. Call
|
|
* startDeliveringFrames method to start delivering frames. This method must
|
|
* be called on a connected instance of this class. If it is called on a
|
|
* disconnected instance, this method must return a failure.
|
|
* Param:
|
|
* width, height - Frame dimensions to use when capturing video frames.
|
|
* pix_fmt - Pixel format to use when capturing video frames.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t startDevice(int width, int height, uint32_t pix_fmt) = 0;
|
|
|
|
/* Stops the camera device.
|
|
* This method tells the camera device to stop capturing frames. Note that
|
|
* this method doesn't stop delivering frames to the emulated camera. Always
|
|
* call stopDeliveringFrames prior to calling this method.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status. If this method is
|
|
* called for an object that is not capturing frames, or is disconnected,
|
|
* or is uninitialized, a successful status must be returned from this
|
|
* method.
|
|
*/
|
|
virtual status_t stopDevice() = 0;
|
|
|
|
/***************************************************************************
|
|
* Emulated camera device public API
|
|
**************************************************************************/
|
|
|
|
public:
|
|
/* Initializes EmulatedCameraDevice instance.
|
|
* Derived classes should override this method in order to cache static
|
|
* properties of the physical device (list of supported pixel formats, frame
|
|
* sizes, etc.) If this method is called on an already initialized instance,
|
|
* it must return a successful status.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t Initialize();
|
|
|
|
/* Initializes the white balance modes parameters.
|
|
* The parameters are passed by each individual derived camera API to
|
|
* represent that different camera manufacturers may have different
|
|
* preferences on the white balance parameters. Green channel in the RGB
|
|
* color space is fixed to keep the luminance to be reasonably constant.
|
|
*
|
|
* Param:
|
|
* mode the text describing the current white balance mode
|
|
* r_scale the scale factor for the R channel in RGB space
|
|
* b_scale the scale factor for the B channel in RGB space.
|
|
*/
|
|
void initializeWhiteBalanceModes(const char* mode,
|
|
const float r_scale,
|
|
const float b_scale);
|
|
|
|
/* Starts delivering frames captured from the camera device.
|
|
* This method will start the worker thread that would be pulling frames from
|
|
* the camera device, and will deliver the pulled frames back to the emulated
|
|
* camera via onNextFrameAvailable callback. This method must be called on a
|
|
* connected instance of this class with a started camera device. If it is
|
|
* called on a disconnected instance, or camera device has not been started,
|
|
* this method must return a failure.
|
|
* Param:
|
|
* one_burst - Controls how many frames should be delivered. If this
|
|
* parameter is 'true', only one captured frame will be delivered to the
|
|
* emulated camera. If this parameter is 'false', frames will keep
|
|
* coming until stopDeliveringFrames method is called. Typically, this
|
|
* parameter is set to 'true' only in order to obtain a single frame
|
|
* that will be used as a "picture" in takePicture method of the
|
|
* emulated camera.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t startDeliveringFrames(bool one_burst);
|
|
|
|
/* Stops delivering frames captured from the camera device.
|
|
* This method will stop the worker thread started by startDeliveringFrames.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t stopDeliveringFrames();
|
|
|
|
/* Sets the exposure compensation for the camera device.
|
|
*/
|
|
void setExposureCompensation(const float ev);
|
|
|
|
/* Sets the white balance mode for the device.
|
|
*/
|
|
void setWhiteBalanceMode(const char* mode);
|
|
|
|
/* Gets current framebuffer, converted into preview frame format.
|
|
* This method must be called on a connected instance of this class with a
|
|
* started camera device. If it is called on a disconnected instance, or
|
|
* camera device has not been started, this method must return a failure.
|
|
* Note that this method should be called only after at least one frame has
|
|
* been captured and delivered. Otherwise it will return garbage in the
|
|
* preview frame buffer. Typically, this method shuld be called from
|
|
* onNextFrameAvailable callback.
|
|
* Param:
|
|
* buffer - Buffer, large enough to contain the entire preview frame.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t getCurrentPreviewFrame(void* buffer);
|
|
|
|
/* Gets width of the frame obtained from the physical device.
|
|
* Return:
|
|
* Width of the frame obtained from the physical device. Note that value
|
|
* returned from this method is valid only in case if camera device has been
|
|
* started.
|
|
*/
|
|
inline int getFrameWidth() const
|
|
{
|
|
ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
|
|
return mFrameWidth;
|
|
}
|
|
|
|
/* Gets height of the frame obtained from the physical device.
|
|
* Return:
|
|
* Height of the frame obtained from the physical device. Note that value
|
|
* returned from this method is valid only in case if camera device has been
|
|
* started.
|
|
*/
|
|
inline int getFrameHeight() const
|
|
{
|
|
ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
|
|
return mFrameHeight;
|
|
}
|
|
|
|
/* Gets byte size of the current frame buffer.
|
|
* Return:
|
|
* Byte size of the frame buffer. Note that value returned from this method
|
|
* is valid only in case if camera device has been started.
|
|
*/
|
|
inline size_t getFrameBufferSize() const
|
|
{
|
|
ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
|
|
return mFrameBufferSize;
|
|
}
|
|
|
|
/* Gets number of pixels in the current frame buffer.
|
|
* Return:
|
|
* Number of pixels in the frame buffer. Note that value returned from this
|
|
* method is valid only in case if camera device has been started.
|
|
*/
|
|
inline int getPixelNum() const
|
|
{
|
|
ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
|
|
return mTotalPixels;
|
|
}
|
|
|
|
/* Gets pixel format of the frame that camera device streams to this class.
|
|
* Throughout camera framework, there are three different forms of pixel
|
|
* format representation:
|
|
* - Original format, as reported by the actual camera device. Values for
|
|
* this format are declared in bionic/libc/kernel/common/linux/videodev2.h
|
|
* - String representation as defined in CameraParameters::PIXEL_FORMAT_XXX
|
|
* strings in frameworks/base/include/camera/CameraParameters.h
|
|
* - HAL_PIXEL_FORMAT_XXX format, as defined in system/core/include/system/graphics.h
|
|
* Since emulated camera device gets its data from the actual device, it gets
|
|
* pixel format in the original form. And that's the pixel format
|
|
* representation that will be returned from this method. HAL components will
|
|
* need to translate value returned from this method to the appropriate form.
|
|
* This method must be called only on started instance of this class, since
|
|
* it's applicable only when camera device is ready to stream frames.
|
|
* Param:
|
|
* pix_fmt - Upon success contains the original pixel format.
|
|
* Return:
|
|
* Current framebuffer's pixel format. Note that value returned from this
|
|
* method is valid only in case if camera device has been started.
|
|
*/
|
|
inline uint32_t getOriginalPixelFormat() const
|
|
{
|
|
ALOGE_IF(!isStarted(), "%s: Device is not started", __FUNCTION__);
|
|
return mPixelFormat;
|
|
}
|
|
|
|
/*
|
|
* State checkers.
|
|
*/
|
|
|
|
inline bool isInitialized() const {
|
|
/* Instance is initialized when the worker thread has been successfuly
|
|
* created (but not necessarily started). */
|
|
return mWorkerThread.get() != NULL && mState != ECDS_CONSTRUCTED;
|
|
}
|
|
inline bool isConnected() const {
|
|
/* Instance is connected when its status is either"connected", or
|
|
* "started". */
|
|
return mState == ECDS_CONNECTED || mState == ECDS_STARTED;
|
|
}
|
|
inline bool isStarted() const {
|
|
return mState == ECDS_STARTED;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Emulated camera device private API
|
|
***************************************************************************/
|
|
protected:
|
|
/* Performs common validation and calculation of startDevice parameters.
|
|
* Param:
|
|
* width, height, pix_fmt - Parameters passed to the startDevice method.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t commonStartDevice(int width, int height, uint32_t pix_fmt);
|
|
|
|
/* Performs common cleanup on stopDevice.
|
|
* This method will undo what commonStartDevice had done.
|
|
*/
|
|
virtual void commonStopDevice();
|
|
|
|
/** Computes a luminance value after taking the exposure compensation.
|
|
* value into account.
|
|
*
|
|
* Param:
|
|
* inputY - The input luminance value.
|
|
* Return:
|
|
* The luminance value after adjusting the exposure compensation.
|
|
*/
|
|
inline uint8_t changeExposure(const uint8_t& inputY) const {
|
|
return static_cast<uint8_t>(clamp(static_cast<float>(inputY) *
|
|
mExposureCompensation));
|
|
}
|
|
|
|
/** Computes the pixel value in YUV space after adjusting to the current
|
|
* white balance mode.
|
|
*/
|
|
void changeWhiteBalance(uint8_t& y, uint8_t& u, uint8_t& v) const;
|
|
|
|
/****************************************************************************
|
|
* Worker thread management.
|
|
* Typicaly when emulated camera device starts capturing frames from the
|
|
* actual device, it does that in a worker thread created in StartCapturing,
|
|
* and terminated in StopCapturing. Since this is such a typical scenario,
|
|
* it makes sence to encapsulate worker thread management in the base class
|
|
* for all emulated camera devices.
|
|
***************************************************************************/
|
|
|
|
protected:
|
|
/* Starts the worker thread.
|
|
* Typically, worker thread is started from startDeliveringFrames method of
|
|
* this class.
|
|
* Param:
|
|
* one_burst - Controls how many times thread loop should run. If this
|
|
* parameter is 'true', thread routine will run only once If this
|
|
* parameter is 'false', thread routine will run until stopWorkerThread
|
|
* method is called. See startDeliveringFrames for more info.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t startWorkerThread(bool one_burst);
|
|
|
|
/* Stops the worker thread.
|
|
* Note that this method will always wait for the worker thread to terminate.
|
|
* Typically, worker thread is started from stopDeliveringFrames method of
|
|
* this class.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
virtual status_t stopWorkerThread();
|
|
|
|
/* Implementation of the worker thread routine.
|
|
* In the default implementation of the worker thread routine we simply
|
|
* return 'false' forcing the thread loop to exit, and the thread to
|
|
* terminate. Derived class should override that method to provide there the
|
|
* actual frame delivery.
|
|
* Return:
|
|
* true To continue thread loop (this method will be called again), or false
|
|
* to exit the thread loop and to terminate the thread.
|
|
*/
|
|
virtual bool inWorkerThread();
|
|
|
|
/* Encapsulates a worker thread used by the emulated camera device.
|
|
*/
|
|
friend class WorkerThread;
|
|
class WorkerThread : public Thread {
|
|
|
|
/****************************************************************************
|
|
* Public API
|
|
***************************************************************************/
|
|
|
|
public:
|
|
inline explicit WorkerThread(EmulatedCameraDevice* camera_dev)
|
|
: Thread(true), // Callbacks may involve Java calls.
|
|
mCameraDevice(camera_dev),
|
|
mThreadControl(-1),
|
|
mControlFD(-1)
|
|
{
|
|
}
|
|
|
|
inline ~WorkerThread()
|
|
{
|
|
ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0,
|
|
"%s: Control FDs are opened in the destructor",
|
|
__FUNCTION__);
|
|
if (mThreadControl >= 0) {
|
|
close(mThreadControl);
|
|
}
|
|
if (mControlFD >= 0) {
|
|
close(mControlFD);
|
|
}
|
|
}
|
|
|
|
/* Starts the thread
|
|
* Param:
|
|
* one_burst - Controls how many times thread loop should run. If
|
|
* this parameter is 'true', thread routine will run only once
|
|
* If this parameter is 'false', thread routine will run until
|
|
* stopThread method is called. See startWorkerThread for more
|
|
* info.
|
|
* Return:
|
|
* NO_ERROR on success, or an appropriate error status.
|
|
*/
|
|
inline status_t startThread(bool one_burst)
|
|
{
|
|
mOneBurst = one_burst;
|
|
return run("Camera_startThread", ANDROID_PRIORITY_URGENT_DISPLAY, 0);
|
|
}
|
|
|
|
/* Overriden base class method.
|
|
* It is overriden in order to provide one-time initialization just
|
|
* prior to starting the thread routine.
|
|
*/
|
|
status_t readyToRun();
|
|
|
|
/* Stops the thread. */
|
|
status_t stopThread();
|
|
|
|
/* Values returned from the Select method of this class. */
|
|
enum SelectRes {
|
|
/* A timeout has occurred. */
|
|
TIMEOUT,
|
|
/* Data are available for read on the provided FD. */
|
|
READY,
|
|
/* Thread exit request has been received. */
|
|
EXIT_THREAD,
|
|
/* An error has occurred. */
|
|
ERROR
|
|
};
|
|
|
|
/* Select on an FD event, keeping in mind thread exit message.
|
|
* Param:
|
|
* fd - File descriptor on which to wait for an event. This
|
|
* parameter may be negative. If it is negative this method will
|
|
* only wait on a control message to the thread.
|
|
* timeout - Timeout in microseconds. 0 indicates no timeout (wait
|
|
* forever).
|
|
* Return:
|
|
* See SelectRes enum comments.
|
|
*/
|
|
SelectRes Select(int fd, int timeout);
|
|
|
|
/****************************************************************************
|
|
* Private API
|
|
***************************************************************************/
|
|
|
|
private:
|
|
/* Implements abstract method of the base Thread class. */
|
|
bool threadLoop()
|
|
{
|
|
/* Simply dispatch the call to the containing camera device. */
|
|
if (mCameraDevice->inWorkerThread()) {
|
|
/* Respect "one burst" parameter (see startThread). */
|
|
return !mOneBurst;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Containing camera device object. */
|
|
EmulatedCameraDevice* mCameraDevice;
|
|
|
|
/* FD that is used to send control messages into the thread. */
|
|
int mThreadControl;
|
|
|
|
/* FD that thread uses to receive control messages. */
|
|
int mControlFD;
|
|
|
|
/* Controls number of times the thread loop runs.
|
|
* See startThread for more information. */
|
|
bool mOneBurst;
|
|
|
|
/* Enumerates control messages that can be sent into the thread. */
|
|
enum ControlMessage {
|
|
/* Stop the thread. */
|
|
THREAD_STOP
|
|
};
|
|
|
|
Condition mSetup;
|
|
};
|
|
|
|
/* Worker thread accessor. */
|
|
inline WorkerThread* getWorkerThread() const
|
|
{
|
|
return mWorkerThread.get();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Data members
|
|
***************************************************************************/
|
|
|
|
protected:
|
|
/* Locks this instance for parameters, state, etc. change. */
|
|
Mutex mObjectLock;
|
|
|
|
/* Worker thread that is used in frame capturing. */
|
|
sp<WorkerThread> mWorkerThread;
|
|
|
|
/* Timestamp of the current frame. */
|
|
nsecs_t mCurFrameTimestamp;
|
|
|
|
/* Emulated camera object containing this instance. */
|
|
EmulatedCamera* mCameraHAL;
|
|
|
|
/* Framebuffer containing the current frame. */
|
|
uint8_t* mCurrentFrame;
|
|
|
|
/*
|
|
* Framebuffer properties.
|
|
*/
|
|
|
|
/* Byte size of the framebuffer. */
|
|
size_t mFrameBufferSize;
|
|
|
|
/* Original pixel format (one of the V4L2_PIX_FMT_XXX values, as defined in
|
|
* bionic/libc/kernel/common/linux/videodev2.h */
|
|
uint32_t mPixelFormat;
|
|
|
|
/* Frame width */
|
|
int mFrameWidth;
|
|
|
|
/* Frame height */
|
|
int mFrameHeight;
|
|
|
|
/* Total number of pixels */
|
|
int mTotalPixels;
|
|
|
|
/* Exposure compensation value */
|
|
float mExposureCompensation;
|
|
|
|
float* mWhiteBalanceScale;
|
|
|
|
DefaultKeyedVector<String8, float*> mSupportedWhiteBalanceScale;
|
|
|
|
/* Defines possible states of the emulated camera device object.
|
|
*/
|
|
enum EmulatedCameraDeviceState {
|
|
/* Object has been constructed. */
|
|
ECDS_CONSTRUCTED,
|
|
/* Object has been initialized. */
|
|
ECDS_INITIALIZED,
|
|
/* Object has been connected to the physical device. */
|
|
ECDS_CONNECTED,
|
|
/* Camera device has been started. */
|
|
ECDS_STARTED,
|
|
};
|
|
|
|
/* Object state. */
|
|
EmulatedCameraDeviceState mState;
|
|
};
|
|
|
|
}; /* namespace android */
|
|
|
|
#endif /* HW_EMULATOR_CAMERA_EMULATED_CAMERA_DEVICE_H */
|