X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fandroid%2Fcamera%2FEmulatedCameraDevice.cpp;fp=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fandroid%2Fcamera%2FEmulatedCameraDevice.cpp;h=c8e5640861b9e31665576b32c048d44b1cb12775;hb=e26c1ec581be598521517829adba8c8dd23a768f;hp=0000000000000000000000000000000000000000;hpb=6699c1aea74eeb0eb400e6299079f0c7576f716f;p=iec.git diff --git a/src/type3_AndroidCloud/anbox-master/android/camera/EmulatedCameraDevice.cpp b/src/type3_AndroidCloud/anbox-master/android/camera/EmulatedCameraDevice.cpp new file mode 100644 index 0000000..c8e5640 --- /dev/null +++ b/src/type3_AndroidCloud/anbox-master/android/camera/EmulatedCameraDevice.cpp @@ -0,0 +1,413 @@ +/* + * 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. + */ + +/* + * Contains implementation of an abstract class EmulatedCameraDevice that defines + * functionality expected from an emulated physical camera device: + * - Obtaining and setting camera parameters + * - Capturing frames + * - Streaming video + * - etc. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "EmulatedCamera_Device" +#include +#include +#include +#include "EmulatedCameraDevice.h" + +namespace android { + +const float GAMMA_CORRECTION = 2.2f; +EmulatedCameraDevice::EmulatedCameraDevice(EmulatedCamera* camera_hal) + : mObjectLock(), + mCurFrameTimestamp(0), + mCameraHAL(camera_hal), + mCurrentFrame(NULL), + mExposureCompensation(1.0f), + mWhiteBalanceScale(NULL), + mSupportedWhiteBalanceScale(), + mState(ECDS_CONSTRUCTED) +{ +} + +EmulatedCameraDevice::~EmulatedCameraDevice() +{ + ALOGV("EmulatedCameraDevice destructor"); + if (mCurrentFrame != NULL) { + delete[] mCurrentFrame; + } + for (size_t i = 0; i < mSupportedWhiteBalanceScale.size(); ++i) { + if (mSupportedWhiteBalanceScale.valueAt(i) != NULL) { + delete[] mSupportedWhiteBalanceScale.valueAt(i); + } + } +} + +/**************************************************************************** + * Emulated camera device public API + ***************************************************************************/ + +status_t EmulatedCameraDevice::Initialize() +{ + if (isInitialized()) { + ALOGW("%s: Emulated camera device is already initialized: mState = %d", + __FUNCTION__, mState); + return NO_ERROR; + } + + /* Instantiate worker thread object. */ + mWorkerThread = new WorkerThread(this); + if (getWorkerThread() == NULL) { + ALOGE("%s: Unable to instantiate worker thread object", __FUNCTION__); + return ENOMEM; + } + + mState = ECDS_INITIALIZED; + + return NO_ERROR; +} + +status_t EmulatedCameraDevice::startDeliveringFrames(bool one_burst) +{ + ALOGV("%s", __FUNCTION__); + + if (!isStarted()) { + ALOGE("%s: Device is not started", __FUNCTION__); + return EINVAL; + } + + /* Frames will be delivered from the thread routine. */ + const status_t res = startWorkerThread(one_burst); + ALOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__); + return res; +} + +status_t EmulatedCameraDevice::stopDeliveringFrames() +{ + ALOGV("%s", __FUNCTION__); + + if (!isStarted()) { + ALOGW("%s: Device is not started", __FUNCTION__); + return NO_ERROR; + } + + const status_t res = stopWorkerThread(); + ALOGE_IF(res != NO_ERROR, "%s: startWorkerThread failed", __FUNCTION__); + return res; +} + +void EmulatedCameraDevice::setExposureCompensation(const float ev) { + ALOGV("%s", __FUNCTION__); + + if (!isStarted()) { + ALOGW("%s: Fake camera device is not started.", __FUNCTION__); + } + + mExposureCompensation = std::pow(2.0f, ev / GAMMA_CORRECTION); + ALOGV("New exposure compensation is %f", mExposureCompensation); +} + +void EmulatedCameraDevice::initializeWhiteBalanceModes(const char* mode, + const float r_scale, + const float b_scale) { + ALOGV("%s with %s, %f, %f", __FUNCTION__, mode, r_scale, b_scale); + float* value = new float[3]; + value[0] = r_scale; value[1] = 1.0f; value[2] = b_scale; + mSupportedWhiteBalanceScale.add(String8(mode), value); +} + +void EmulatedCameraDevice::setWhiteBalanceMode(const char* mode) { + ALOGV("%s with white balance %s", __FUNCTION__, mode); + mWhiteBalanceScale = + mSupportedWhiteBalanceScale.valueFor(String8(mode)); +} + +/* Computes the pixel value after adjusting the white balance to the current + * one. The input the y, u, v channel of the pixel and the adjusted value will + * be stored in place. The adjustment is done in RGB space. + */ +void EmulatedCameraDevice::changeWhiteBalance(uint8_t& y, + uint8_t& u, + uint8_t& v) const { + float r_scale = mWhiteBalanceScale[0]; + float b_scale = mWhiteBalanceScale[2]; + int r = static_cast(YUV2R(y, u, v)) / r_scale; + int g = YUV2G(y, u, v); + int b = static_cast(YUV2B(y, u, v)) / b_scale; + + y = RGB2Y(r, g, b); + u = RGB2U(r, g, b); + v = RGB2V(r, g, b); +} + +status_t EmulatedCameraDevice::getCurrentPreviewFrame(void* buffer) +{ + if (!isStarted()) { + ALOGE("%s: Device is not started", __FUNCTION__); + return EINVAL; + } + if (mCurrentFrame == NULL || buffer == NULL) { + ALOGE("%s: No framebuffer", __FUNCTION__); + return EINVAL; + } + + /* In emulation the framebuffer is never RGB. */ + switch (mPixelFormat) { + case V4L2_PIX_FMT_YVU420: + YV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight); + return NO_ERROR; + case V4L2_PIX_FMT_YUV420: + YU12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight); + return NO_ERROR; + case V4L2_PIX_FMT_NV21: + NV21ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight); + return NO_ERROR; + case V4L2_PIX_FMT_NV12: + NV12ToRGB32(mCurrentFrame, buffer, mFrameWidth, mFrameHeight); + return NO_ERROR; + + default: + ALOGE("%s: Unknown pixel format %.4s", + __FUNCTION__, reinterpret_cast(&mPixelFormat)); + return EINVAL; + } +} + +/**************************************************************************** + * Emulated camera device private API + ***************************************************************************/ + +status_t EmulatedCameraDevice::commonStartDevice(int width, + int height, + uint32_t pix_fmt) +{ + /* Validate pixel format, and calculate framebuffer size at the same time. */ + switch (pix_fmt) { + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12: + mFrameBufferSize = (width * height * 12) / 8; + break; + + default: + ALOGE("%s: Unknown pixel format %.4s", + __FUNCTION__, reinterpret_cast(&pix_fmt)); + return EINVAL; + } + + /* Cache framebuffer info. */ + mFrameWidth = width; + mFrameHeight = height; + mPixelFormat = pix_fmt; + mTotalPixels = width * height; + + /* Allocate framebuffer. */ + mCurrentFrame = new uint8_t[mFrameBufferSize]; + if (mCurrentFrame == NULL) { + ALOGE("%s: Unable to allocate framebuffer", __FUNCTION__); + return ENOMEM; + } + ALOGV("%s: Allocated %p %zu bytes for %d pixels in %.4s[%dx%d] frame", + __FUNCTION__, mCurrentFrame, mFrameBufferSize, mTotalPixels, + reinterpret_cast(&mPixelFormat), mFrameWidth, mFrameHeight); + return NO_ERROR; +} + +void EmulatedCameraDevice::commonStopDevice() +{ + mFrameWidth = mFrameHeight = mTotalPixels = 0; + mPixelFormat = 0; + + if (mCurrentFrame != NULL) { + delete[] mCurrentFrame; + mCurrentFrame = NULL; + } +} + +/**************************************************************************** + * Worker thread management. + ***************************************************************************/ + +status_t EmulatedCameraDevice::startWorkerThread(bool one_burst) +{ + ALOGV("%s", __FUNCTION__); + + if (!isInitialized()) { + ALOGE("%s: Emulated camera device is not initialized", __FUNCTION__); + return EINVAL; + } + + const status_t res = getWorkerThread()->startThread(one_burst); + ALOGE_IF(res != NO_ERROR, "%s: Unable to start worker thread", __FUNCTION__); + return res; +} + +status_t EmulatedCameraDevice::stopWorkerThread() +{ + ALOGV("%s", __FUNCTION__); + + if (!isInitialized()) { + ALOGE("%s: Emulated camera device is not initialized", __FUNCTION__); + return EINVAL; + } + + const status_t res = getWorkerThread()->stopThread(); + ALOGE_IF(res != NO_ERROR, "%s: Unable to stop worker thread", __FUNCTION__); + return res; +} + +bool EmulatedCameraDevice::inWorkerThread() +{ + /* This will end the thread loop, and will terminate the thread. Derived + * classes must override this method. */ + return false; +} + +/**************************************************************************** + * Worker thread implementation. + ***************************************************************************/ + +status_t EmulatedCameraDevice::WorkerThread::readyToRun() +{ + ALOGV("Starting emulated camera device worker thread..."); + + ALOGW_IF(mThreadControl >= 0 || mControlFD >= 0, + "%s: Thread control FDs are opened", __FUNCTION__); + /* Create a pair of FDs that would be used to control the thread. */ + int thread_fds[2]; + status_t ret; + Mutex::Autolock lock(mCameraDevice->mObjectLock); + if (pipe(thread_fds) == 0) { + mThreadControl = thread_fds[1]; + mControlFD = thread_fds[0]; + ALOGV("Emulated device's worker thread has been started."); + ret = NO_ERROR; + } else { + ALOGE("%s: Unable to create thread control FDs: %d -> %s", + __FUNCTION__, errno, strerror(errno)); + ret = errno; + } + + mSetup.signal(); + return ret; +} + +status_t EmulatedCameraDevice::WorkerThread::stopThread() +{ + ALOGV("Stopping emulated camera device's worker thread..."); + + status_t res = EINVAL; + + // Limit the scope of the Autolock + { + // If thread is running and readyToRun() has not finished running, + // then wait until it is done. + Mutex::Autolock lock(mCameraDevice->mObjectLock); + if (isRunning() && (mThreadControl < 0 || mControlFD < 0)) { + mSetup.wait(mCameraDevice->mObjectLock); + } + } + + if (mThreadControl >= 0) { + /* Send "stop" message to the thread loop. */ + const ControlMessage msg = THREAD_STOP; + const int wres = + TEMP_FAILURE_RETRY(write(mThreadControl, &msg, sizeof(msg))); + if (wres == sizeof(msg)) { + /* Stop the thread, and wait till it's terminated. */ + res = requestExitAndWait(); + if (res == NO_ERROR) { + /* Close control FDs. */ + if (mThreadControl >= 0) { + close(mThreadControl); + mThreadControl = -1; + } + if (mControlFD >= 0) { + close(mControlFD); + mControlFD = -1; + } + ALOGV("Emulated camera device's worker thread has been stopped."); + } else { + ALOGE("%s: requestExitAndWait failed: %d -> %s", + __FUNCTION__, res, strerror(-res)); + } + } else { + ALOGE("%s: Unable to send THREAD_STOP message: %d -> %s", + __FUNCTION__, errno, strerror(errno)); + res = errno ? errno : EINVAL; + } + } else { + ALOGE("%s: Thread control FDs are not opened", __FUNCTION__); + } + + return res; +} + +EmulatedCameraDevice::WorkerThread::SelectRes +EmulatedCameraDevice::WorkerThread::Select(int fd, int timeout) +{ + fd_set fds[1]; + struct timeval tv, *tvp = NULL; + + const int fd_num = (fd >= 0) ? max(fd, mControlFD) + 1 : + mControlFD + 1; + FD_ZERO(fds); + FD_SET(mControlFD, fds); + if (fd >= 0) { + FD_SET(fd, fds); + } + if (timeout) { + tv.tv_sec = timeout / 1000000; + tv.tv_usec = timeout % 1000000; + tvp = &tv; + } + int res = TEMP_FAILURE_RETRY(select(fd_num, fds, NULL, NULL, tvp)); + if (res < 0) { + ALOGE("%s: select returned %d and failed: %d -> %s", + __FUNCTION__, res, errno, strerror(errno)); + return ERROR; + } else if (res == 0) { + /* Timeout. */ + return TIMEOUT; + } else if (FD_ISSET(mControlFD, fds)) { + /* A control event. Lets read the message. */ + ControlMessage msg; + res = TEMP_FAILURE_RETRY(read(mControlFD, &msg, sizeof(msg))); + if (res != sizeof(msg)) { + ALOGE("%s: Unexpected message size %d, or an error %d -> %s", + __FUNCTION__, res, errno, strerror(errno)); + return ERROR; + } + /* THREAD_STOP is the only message expected here. */ + if (msg == THREAD_STOP) { + ALOGV("%s: THREAD_STOP message is received", __FUNCTION__); + return EXIT_THREAD; + } else { + ALOGE("Unknown worker thread message %d", msg); + return ERROR; + } + } else { + /* Must be an FD. */ + ALOGW_IF(fd < 0 || !FD_ISSET(fd, fds), "%s: Undefined 'select' result", + __FUNCTION__); + return READY; + } +} + +}; /* namespace android */