diff options
Diffstat (limited to 'guest/hals/camera/EmulatedCamera.cpp')
-rw-r--r-- | guest/hals/camera/EmulatedCamera.cpp | 1034 |
1 files changed, 1034 insertions, 0 deletions
diff --git a/guest/hals/camera/EmulatedCamera.cpp b/guest/hals/camera/EmulatedCamera.cpp new file mode 100644 index 000000000..e48d5795c --- /dev/null +++ b/guest/hals/camera/EmulatedCamera.cpp @@ -0,0 +1,1034 @@ +/* + * 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 a class EmulatedCamera that encapsulates + * functionality common to all emulated cameras ("fake", "webcam", "video file", + * etc.). Instances of this class (for each emulated camera) are created during + * the construction of the EmulatedCameraFactory instance. This class serves as + * an entry point for all camera API calls that defined by camera_device_ops_t + * API. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "EmulatedCamera_Camera" +#include <log/log.h> +#include "EmulatedCamera.h" +//#include "EmulatedFakeCameraDevice.h" +#include "Converters.h" + +/* Defines whether we should trace parameter changes. */ +#define DEBUG_PARAM 1 + +namespace android { +namespace { +const char* kSupportedFlashModes[] = { + CameraParameters::FLASH_MODE_OFF, CameraParameters::FLASH_MODE_AUTO, + CameraParameters::FLASH_MODE_ON, CameraParameters::FLASH_MODE_RED_EYE, + CameraParameters::FLASH_MODE_TORCH, NULL}; + +std::string BuildParameterValue(const char** value_array) { + std::string result; + + for (int index = 0; value_array[index] != NULL; ++index) { + if (index) result.append(","); + result.append(value_array[index]); + } + return result; +} + +bool CheckParameterValue(const char* value, const char** supported_values) { + for (int index = 0; supported_values[index] != NULL; ++index) { + if (!strcmp(value, supported_values[index])) return true; + } + return false; +} + +} // namespace + +#if DEBUG_PARAM +/* Calculates and logs parameter changes. + * Param: + * current - Current set of camera parameters. + * new_par - String representation of new parameters. + */ +static void PrintParamDiff(const CameraParameters& current, + const char* new_par); +#else +#define PrintParamDiff(current, new_par) (void(0)) +#endif /* DEBUG_PARAM */ + +EmulatedCamera::EmulatedCamera(int cameraId, struct hw_module_t* module) + : EmulatedBaseCamera(cameraId, HARDWARE_DEVICE_API_VERSION(1, 0), &common, + module), + mPreviewWindow(), + mCallbackNotifier() { + /* camera_device v1 fields. */ + common.close = EmulatedCamera::close; + ops = &mDeviceOps; + priv = this; +} + +EmulatedCamera::~EmulatedCamera() {} + +/**************************************************************************** + * Public API + ***************************************************************************/ + +status_t EmulatedCamera::Initialize(const cvd::CameraDefinition&) { + /* Preview formats supported by this HAL. */ + char preview_formats[1024]; + snprintf(preview_formats, sizeof(preview_formats), "%s,%s,%s", + CameraParameters::PIXEL_FORMAT_YUV420SP, + CameraParameters::PIXEL_FORMAT_YUV420P, + CameraParameters::PIXEL_FORMAT_RGBA8888); + + /* + * Fake required parameters. + */ + + mParameters.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, + "320x240,0x0"); + + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "512"); + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "384"); + mParameters.set(CameraParameters::KEY_JPEG_QUALITY, "90"); + mParameters.set(CameraParameters::KEY_FOCAL_LENGTH, "4.31"); + mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "54.8"); + mParameters.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "42.5"); + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "90"); + + /* Preview format settings used here are related to panoramic view only. It's + * not related to the preview window that works only with RGB frames, which + * is explicitly stated when set_buffers_geometry is called on the preview + * window object. */ + mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, + preview_formats); + mParameters.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP); + + /* We don't relay on the actual frame rates supported by the camera device, + * since we will emulate them through timeouts in the emulated camera device + * worker thread. */ + mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, + "30,24,20,15,10,5"); + mParameters.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, + "(5000,30000),(15000,15000),(30000,30000)"); + mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "5000,30000"); + mParameters.setPreviewFrameRate(30000); + + /* Only PIXEL_FORMAT_YUV420P is accepted by video framework in emulator! */ + mParameters.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, + CameraParameters::PIXEL_FORMAT_YUV420P); + mParameters.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, + CameraParameters::PIXEL_FORMAT_JPEG); + mParameters.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG); + + /* Set exposure compensation. */ + mParameters.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, "6"); + mParameters.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, "-6"); + mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, "0.5"); + mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, "0"); + + /* Sets the white balance modes and the device-dependent scale factors. */ + char supported_white_balance[1024]; + snprintf(supported_white_balance, sizeof(supported_white_balance), + "%s,%s,%s,%s", CameraParameters::WHITE_BALANCE_AUTO, + CameraParameters::WHITE_BALANCE_INCANDESCENT, + CameraParameters::WHITE_BALANCE_DAYLIGHT, + CameraParameters::WHITE_BALANCE_TWILIGHT); + mParameters.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, + supported_white_balance); + mParameters.set(CameraParameters::KEY_WHITE_BALANCE, + CameraParameters::WHITE_BALANCE_AUTO); + getCameraDevice()->initializeWhiteBalanceModes( + CameraParameters::WHITE_BALANCE_AUTO, 1.0f, 1.0f); + getCameraDevice()->initializeWhiteBalanceModes( + CameraParameters::WHITE_BALANCE_INCANDESCENT, 1.38f, 0.60f); + getCameraDevice()->initializeWhiteBalanceModes( + CameraParameters::WHITE_BALANCE_DAYLIGHT, 1.09f, 0.92f); + getCameraDevice()->initializeWhiteBalanceModes( + CameraParameters::WHITE_BALANCE_TWILIGHT, 0.92f, 1.22f); + getCameraDevice()->setWhiteBalanceMode(CameraParameters::WHITE_BALANCE_AUTO); + + /* + * Not supported features + */ + mParameters.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, + CameraParameters::FOCUS_MODE_FIXED); + mParameters.set(CameraParameters::KEY_FOCUS_MODE, + CameraParameters::FOCUS_MODE_FIXED); + mParameters.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, + BuildParameterValue(kSupportedFlashModes).c_str()); + mParameters.set(CameraParameters::KEY_FLASH_MODE, + CameraParameters::FLASH_MODE_OFF); + mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES, "0.1,0.1,0.1"); + mParameters.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW, "0"); + mParameters.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW, "0"); + mParameters.set(CameraParameters::KEY_ZOOM_RATIOS, "100"); + mParameters.set(CameraParameters::KEY_ZOOM_SUPPORTED, + CameraParameters::FALSE); + mParameters.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, + CameraParameters::FALSE); + mParameters.set(CameraParameters::KEY_ZOOM, "0"); + mParameters.set(CameraParameters::KEY_MAX_ZOOM, "0"); + + return NO_ERROR; +} + +void EmulatedCamera::onNextFrameAvailable(const void* frame, nsecs_t timestamp, + EmulatedCameraDevice* camera_dev) { + /* Notify the preview window first. */ + mPreviewWindow.onNextFrameAvailable(frame, timestamp, camera_dev); + + /* Notify callback notifier next. */ + mCallbackNotifier.onNextFrameAvailable(frame, timestamp, camera_dev); +} + +void EmulatedCamera::onCameraDeviceError(int err) { + /* Errors are reported through the callback notifier */ + mCallbackNotifier.onCameraDeviceError(err); +} + +void EmulatedCamera::onCameraFocusAcquired() { + mCallbackNotifier.onCameraFocusAcquired(); +} + +/**************************************************************************** + * Camera API implementation. + ***************************************************************************/ + +status_t EmulatedCamera::connectCamera(hw_device_t** device) { + ALOGV("%s", __FUNCTION__); + + status_t res = EINVAL; + EmulatedCameraDevice* const camera_dev = getCameraDevice(); + ALOGE_IF(camera_dev == NULL, "%s: No camera device instance.", __FUNCTION__); + + if (camera_dev != NULL) { + /* Connect to the camera device. */ + res = getCameraDevice()->connectDevice(); + if (res == NO_ERROR) { + *device = &common; + } + } + + return -res; +} + +status_t EmulatedCamera::closeCamera() { + ALOGV("%s", __FUNCTION__); + + return cleanupCamera(); +} + +status_t EmulatedCamera::getCameraInfo(struct camera_info* info) { + ALOGV("%s", __FUNCTION__); + + const char* valstr = NULL; + + valstr = mParameters.get(EmulatedCamera::FACING_KEY); + if (valstr != NULL) { + if (strcmp(valstr, EmulatedCamera::FACING_FRONT) == 0) { + info->facing = CAMERA_FACING_FRONT; + } else if (strcmp(valstr, EmulatedCamera::FACING_BACK) == 0) { + info->facing = CAMERA_FACING_BACK; + } + } else { + info->facing = CAMERA_FACING_BACK; + } + + valstr = mParameters.get(EmulatedCamera::ORIENTATION_KEY); + if (valstr != NULL) { + info->orientation = atoi(valstr); + } else { + info->orientation = 0; + } + + info->resource_cost = 100; + info->conflicting_devices = NULL; + info->conflicting_devices_length = 0; + + return EmulatedBaseCamera::getCameraInfo(info); +} + +const CameraParameters* EmulatedCamera::getCameraParameters() { + return &mParameters; +} + +status_t EmulatedCamera::setPreviewWindow(struct preview_stream_ops* window) { + /* Callback should return a negative errno. */ + return -mPreviewWindow.setPreviewWindow(window, + mParameters.getPreviewFrameRate()); +} + +void EmulatedCamera::setCallbacks( + camera_notify_callback notify_cb, camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, void* user) { + mCallbackNotifier.setCallbacks(notify_cb, data_cb, data_cb_timestamp, + get_memory, user); +} + +void EmulatedCamera::enableMsgType(int32_t msg_type) { + mCallbackNotifier.enableMessage(msg_type); +} + +void EmulatedCamera::disableMsgType(int32_t msg_type) { + mCallbackNotifier.disableMessage(msg_type); +} + +int EmulatedCamera::isMsgTypeEnabled(int32_t msg_type) { + return mCallbackNotifier.isMessageEnabled(msg_type); +} + +status_t EmulatedCamera::startPreview() { + /* Callback should return a negative errno. */ + return -doStartPreview(); +} + +void EmulatedCamera::stopPreview() { doStopPreview(); } + +int EmulatedCamera::isPreviewEnabled() { + return mPreviewWindow.isPreviewEnabled(); +} + +status_t EmulatedCamera::storeMetaDataInBuffers(int enable) { + /* Callback should return a negative errno. */ + return -mCallbackNotifier.storeMetaDataInBuffers(enable); +} + +status_t EmulatedCamera::startRecording() { + /* Callback should return a negative errno. */ + return -mCallbackNotifier.enableVideoRecording( + mParameters.getPreviewFrameRate()); +} + +void EmulatedCamera::stopRecording() { + mCallbackNotifier.disableVideoRecording(); +} + +int EmulatedCamera::isRecordingEnabled() { + return mCallbackNotifier.isVideoRecordingEnabled(); +} + +void EmulatedCamera::releaseRecordingFrame(const void* opaque) { + mCallbackNotifier.releaseRecordingFrame(opaque); +} + +status_t EmulatedCamera::setAutoFocus() { + ALOGV("%s", __FUNCTION__); + + /* Trigger auto-focus. Focus response cannot be sent directly from here. */ + getCameraDevice()->startAutoFocus(); + + /* TODO: Future enhancements. */ + return NO_ERROR; +} + +status_t EmulatedCamera::cancelAutoFocus() { + ALOGV("%s", __FUNCTION__); + + /* TODO: Future enhancements. */ + return NO_ERROR; +} + +status_t EmulatedCamera::takePicture() { + ALOGV("%s", __FUNCTION__); + + status_t res; + int width, height; + uint32_t org_fmt; + + /* Collect frame info for the picture. */ + mParameters.getPictureSize(&width, &height); + const char* pix_fmt = mParameters.getPictureFormat(); + if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) { + org_fmt = V4L2_PIX_FMT_YUV420; + } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) { + org_fmt = V4L2_PIX_FMT_RGB32; + } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + org_fmt = V4L2_PIX_FMT_NV21; + } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_JPEG) == 0) { + /* We only have JPEG converted for NV21 format. */ + org_fmt = V4L2_PIX_FMT_NV21; + } else { + ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt); + return EINVAL; + } + /* Get JPEG quality. */ + int jpeg_quality = mParameters.getInt(CameraParameters::KEY_JPEG_QUALITY); + if (jpeg_quality <= 0) { + jpeg_quality = 90; /* Fall back to default. */ + } + + /* + * Make sure preview is not running, and device is stopped before taking + * picture. + */ + + const bool preview_on = mPreviewWindow.isPreviewEnabled(); + if (preview_on) { + doStopPreview(); + } + + /* Camera device should have been stopped when the shutter message has been + * enabled. */ + EmulatedCameraDevice* const camera_dev = getCameraDevice(); + if (camera_dev->isStarted()) { + ALOGW("%s: Camera device is started", __FUNCTION__); + camera_dev->stopDeliveringFrames(); + camera_dev->stopDevice(); + } + + /* Compute target FPS rate. + * Pretend to simulate generation of (max_fps_rate) */ + int min_fps_rate, max_fps_rate; + mParameters.getPreviewFpsRange(&min_fps_rate, &max_fps_rate); + + /* + * Take the picture now. + */ + + /* Start camera device for the picture frame. */ + ALOGD("Starting camera for picture: %.4s(%s)[%dx%d]", + reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height); + res = camera_dev->startDevice(width, height, org_fmt, max_fps_rate); + if (res != NO_ERROR) { + if (preview_on) { + doStartPreview(); + } + return res; + } + + /* Deliver one frame only. */ + mCallbackNotifier.setJpegQuality(jpeg_quality); + mCallbackNotifier.setTakingPicture(true); + res = camera_dev->startDeliveringFrames(true); + if (res != NO_ERROR) { + mCallbackNotifier.setTakingPicture(false); + if (preview_on) { + doStartPreview(); + } + } + return res; +} + +status_t EmulatedCamera::cancelPicture() { + ALOGV("%s", __FUNCTION__); + + return NO_ERROR; +} + +status_t EmulatedCamera::setParameters(const char* parms) { + ALOGV("%s", __FUNCTION__); + PrintParamDiff(mParameters, parms); + + CameraParameters new_param; + String8 str8_param(parms); + new_param.unflatten(str8_param); + + /* + * Check if requested dimensions are valid. + */ + if (!CheckParameterValue(new_param.get(CameraParameters::KEY_FLASH_MODE), + kSupportedFlashModes)) { + ALOGE("%s: Unsupported flash mode: %s", __FUNCTION__, + new_param.get(CameraParameters::KEY_FLASH_MODE)); + return -EINVAL; + } + if (strcmp(new_param.get(CameraParameters::KEY_FOCUS_MODE), + CameraParameters::FOCUS_MODE_FIXED)) { + ALOGE("%s: Unsupported flash mode: %s", __FUNCTION__, + new_param.get(CameraParameters::KEY_FOCUS_MODE)); + return -EINVAL; + } + + int preview_width, preview_height; + new_param.getPreviewSize(&preview_width, &preview_height); + if (preview_width <= 0 || preview_height <= 0) return -EINVAL; + + /* + * Check for new exposure compensation parameter. + */ + int new_exposure_compensation = + new_param.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + const int min_exposure_compensation = + new_param.getInt(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION); + const int max_exposure_compensation = + new_param.getInt(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION); + + // Checks if the exposure compensation change is supported. + if ((min_exposure_compensation != 0) || (max_exposure_compensation != 0)) { + if (new_exposure_compensation > max_exposure_compensation) { + new_exposure_compensation = max_exposure_compensation; + } + if (new_exposure_compensation < min_exposure_compensation) { + new_exposure_compensation = min_exposure_compensation; + } + + const int current_exposure_compensation = + mParameters.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + if (current_exposure_compensation != new_exposure_compensation) { + const float exposure_value = + new_exposure_compensation * + new_param.getFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP); + + getCameraDevice()->setExposureCompensation(exposure_value); + } + } + + const char* new_white_balance = + new_param.get(CameraParameters::KEY_WHITE_BALANCE); + const char* supported_white_balance = + new_param.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE); + + if ((supported_white_balance != NULL) && (new_white_balance != NULL) && + (strstr(supported_white_balance, new_white_balance) != NULL)) { + const char* current_white_balance = + mParameters.get(CameraParameters::KEY_WHITE_BALANCE); + if ((current_white_balance == NULL) || + (strcmp(current_white_balance, new_white_balance) != 0)) { + ALOGV("Setting white balance to %s", new_white_balance); + getCameraDevice()->setWhiteBalanceMode(new_white_balance); + } + } + + mParameters = new_param; + + return NO_ERROR; +} + +/* A dumb variable indicating "no params" / error on the exit from + * EmulatedCamera::getParameters(). */ +static char lNoParam = '\0'; +char* EmulatedCamera::getParameters() { + String8 params(mParameters.flatten()); + char* ret_str = + reinterpret_cast<char*>(malloc(sizeof(char) * (params.length() + 1))); + memset(ret_str, 0, params.length() + 1); + if (ret_str != NULL) { + strncpy(ret_str, params.string(), params.length() + 1); + return ret_str; + } else { + ALOGE("%s: Unable to allocate string for %s", __FUNCTION__, + params.string()); + /* Apparently, we can't return NULL fron this routine. */ + return &lNoParam; + } +} + +void EmulatedCamera::putParameters(char* params) { + /* This method simply frees parameters allocated in getParameters(). */ + if (params != NULL && params != &lNoParam) { + free(params); + } +} + +status_t EmulatedCamera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) { + ALOGV("%s: cmd = %d, arg1 = %d, arg2 = %d", __FUNCTION__, cmd, arg1, arg2); + + switch (cmd) { + case CAMERA_CMD_START_FACE_DETECTION: + case CAMERA_CMD_STOP_FACE_DETECTION: + return -EINVAL; + } + + /* TODO: Future enhancements. */ + return 0; +} + +void EmulatedCamera::releaseCamera() { + ALOGV("%s", __FUNCTION__); + + cleanupCamera(); +} + +status_t EmulatedCamera::dumpCamera(int /*fd*/) { + ALOGV("%s", __FUNCTION__); + + /* TODO: Future enhancements. */ + return -EINVAL; +} + +/**************************************************************************** + * Preview management. + ***************************************************************************/ + +status_t EmulatedCamera::doStartPreview() { + ALOGV("%s", __FUNCTION__); + + EmulatedCameraDevice* camera_dev = getCameraDevice(); + if (camera_dev->isStarted()) { + camera_dev->stopDeliveringFrames(); + camera_dev->stopDevice(); + } + + status_t res = mPreviewWindow.startPreview(); + if (res != NO_ERROR) { + return res; + } + + /* Make sure camera device is connected. */ + if (!camera_dev->isConnected()) { + res = camera_dev->connectDevice(); + if (res != NO_ERROR) { + mPreviewWindow.stopPreview(); + return res; + } + } + + int width, height; + /* Lets see what should we use for frame width, and height. */ + if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != NULL) { + mParameters.getVideoSize(&width, &height); + } else { + mParameters.getPreviewSize(&width, &height); + } + /* Lets see what should we use for the frame pixel format. Note that there + * are two parameters that define pixel formats for frames sent to the + * application via notification callbacks: + * - KEY_VIDEO_FRAME_FORMAT, that is used when recording video, and + * - KEY_PREVIEW_FORMAT, that is used for preview frame notification. + * We choose one or the other, depending on "recording-hint" property set by + * the framework that indicating intention: video, or preview. */ + const char* pix_fmt = NULL; + const char* is_video = mParameters.get(EmulatedCamera::RECORDING_HINT_KEY); + if (is_video == NULL) { + is_video = CameraParameters::FALSE; + } + if (strcmp(is_video, CameraParameters::TRUE) == 0) { + /* Video recording is requested. Lets see if video frame format is set. */ + pix_fmt = mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT); + } + /* If this was not video recording, or video frame format is not set, lets + * use preview pixel format for the main framebuffer. */ + if (pix_fmt == NULL) { + pix_fmt = mParameters.getPreviewFormat(); + } + if (pix_fmt == NULL) { + ALOGE("%s: Unable to obtain video format", __FUNCTION__); + mPreviewWindow.stopPreview(); + return EINVAL; + } + + /* Convert framework's pixel format to the FOURCC one. */ + uint32_t org_fmt; + if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) { + org_fmt = V4L2_PIX_FMT_YUV420; + } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) { + org_fmt = V4L2_PIX_FMT_RGB32; + } else if (strcmp(pix_fmt, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + org_fmt = V4L2_PIX_FMT_NV21; + } else { + ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt); + mPreviewWindow.stopPreview(); + return EINVAL; + } + + /* Fetch the desired frame rate. */ + int min_fps_rate, max_fps_rate; + mParameters.getPreviewFpsRange(&min_fps_rate, &max_fps_rate); + + ALOGD("Starting camera: %dx%d -> %.4s(%s)", width, height, + reinterpret_cast<const char*>(&org_fmt), pix_fmt); + res = camera_dev->startDevice(width, height, org_fmt, max_fps_rate); + if (res != NO_ERROR) { + mPreviewWindow.stopPreview(); + return res; + } + + res = camera_dev->startDeliveringFrames(false); + if (res != NO_ERROR) { + camera_dev->stopDevice(); + mPreviewWindow.stopPreview(); + } + + return res; +} + +status_t EmulatedCamera::doStopPreview() { + ALOGV("%s", __FUNCTION__); + + status_t res = NO_ERROR; + if (mPreviewWindow.isPreviewEnabled()) { + /* Stop the camera. */ + if (getCameraDevice()->isStarted()) { + getCameraDevice()->stopDeliveringFrames(); + res = getCameraDevice()->stopDevice(); + } + + if (res == NO_ERROR) { + /* Disable preview as well. */ + mPreviewWindow.stopPreview(); + } + } + + return NO_ERROR; +} + +/**************************************************************************** + * Private API. + ***************************************************************************/ + +status_t EmulatedCamera::cleanupCamera() { + status_t res = NO_ERROR; + + /* If preview is running - stop it. */ + res = doStopPreview(); + if (res != NO_ERROR) { + return -res; + } + + /* Stop and disconnect the camera device. */ + EmulatedCameraDevice* const camera_dev = getCameraDevice(); + if (camera_dev != NULL) { + if (camera_dev->isStarted()) { + camera_dev->stopDeliveringFrames(); + res = camera_dev->stopDevice(); + if (res != NO_ERROR) { + return -res; + } + } + if (camera_dev->isConnected()) { + res = camera_dev->disconnectDevice(); + if (res != NO_ERROR) { + return -res; + } + } + } + + mCallbackNotifier.cleanupCBNotifier(); + + return NO_ERROR; +} + +/**************************************************************************** + * Camera API callbacks as defined by camera_device_ops structure. + * + * Callbacks here simply dispatch the calls to an appropriate method inside + * EmulatedCamera instance, defined by the 'dev' parameter. + ***************************************************************************/ + +int EmulatedCamera::set_preview_window(struct camera_device* dev, + struct preview_stream_ops* window) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->setPreviewWindow(window); +} + +void EmulatedCamera::set_callbacks( + struct camera_device* dev, camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, void* user) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user); +} + +void EmulatedCamera::enable_msg_type(struct camera_device* dev, + int32_t msg_type) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->enableMsgType(msg_type); +} + +void EmulatedCamera::disable_msg_type(struct camera_device* dev, + int32_t msg_type) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->disableMsgType(msg_type); +} + +int EmulatedCamera::msg_type_enabled(struct camera_device* dev, + int32_t msg_type) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->isMsgTypeEnabled(msg_type); +} + +int EmulatedCamera::start_preview(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->startPreview(); +} + +void EmulatedCamera::stop_preview(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->stopPreview(); +} + +int EmulatedCamera::preview_enabled(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->isPreviewEnabled(); +} + +int EmulatedCamera::store_meta_data_in_buffers(struct camera_device* dev, + int enable) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->storeMetaDataInBuffers(enable); +} + +int EmulatedCamera::start_recording(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->startRecording(); +} + +void EmulatedCamera::stop_recording(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->stopRecording(); +} + +int EmulatedCamera::recording_enabled(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->isRecordingEnabled(); +} + +void EmulatedCamera::release_recording_frame(struct camera_device* dev, + const void* opaque) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->releaseRecordingFrame(opaque); +} + +int EmulatedCamera::auto_focus(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->setAutoFocus(); +} + +int EmulatedCamera::cancel_auto_focus(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->cancelAutoFocus(); +} + +int EmulatedCamera::take_picture(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->takePicture(); +} + +int EmulatedCamera::cancel_picture(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->cancelPicture(); +} + +int EmulatedCamera::set_parameters(struct camera_device* dev, + const char* parms) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->setParameters(parms); +} + +char* EmulatedCamera::get_parameters(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return NULL; + } + return ec->getParameters(); +} + +void EmulatedCamera::put_parameters(struct camera_device* dev, char* params) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->putParameters(params); +} + +int EmulatedCamera::send_command(struct camera_device* dev, int32_t cmd, + int32_t arg1, int32_t arg2) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->sendCommand(cmd, arg1, arg2); +} + +void EmulatedCamera::release(struct camera_device* dev) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return; + } + ec->releaseCamera(); +} + +int EmulatedCamera::dump(struct camera_device* dev, int fd) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>(dev->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->dumpCamera(fd); +} + +int EmulatedCamera::close(struct hw_device_t* device) { + EmulatedCamera* ec = reinterpret_cast<EmulatedCamera*>( + reinterpret_cast<struct camera_device*>(device)->priv); + if (ec == NULL) { + ALOGE("%s: Unexpected NULL camera device", __FUNCTION__); + return -EINVAL; + } + return ec->closeCamera(); +} + +/**************************************************************************** + * Static initializer for the camera callback API + ****************************************************************************/ + +camera_device_ops_t EmulatedCamera::mDeviceOps = { + EmulatedCamera::set_preview_window, + EmulatedCamera::set_callbacks, + EmulatedCamera::enable_msg_type, + EmulatedCamera::disable_msg_type, + EmulatedCamera::msg_type_enabled, + EmulatedCamera::start_preview, + EmulatedCamera::stop_preview, + EmulatedCamera::preview_enabled, + EmulatedCamera::store_meta_data_in_buffers, + EmulatedCamera::start_recording, + EmulatedCamera::stop_recording, + EmulatedCamera::recording_enabled, + EmulatedCamera::release_recording_frame, + EmulatedCamera::auto_focus, + EmulatedCamera::cancel_auto_focus, + EmulatedCamera::take_picture, + EmulatedCamera::cancel_picture, + EmulatedCamera::set_parameters, + EmulatedCamera::get_parameters, + EmulatedCamera::put_parameters, + EmulatedCamera::send_command, + EmulatedCamera::release, + EmulatedCamera::dump}; + +/**************************************************************************** + * Common keys + ***************************************************************************/ + +const char EmulatedCamera::FACING_KEY[] = "prop-facing"; +const char EmulatedCamera::ORIENTATION_KEY[] = "prop-orientation"; +const char EmulatedCamera::RECORDING_HINT_KEY[] = "recording-hint"; + +/**************************************************************************** + * Common string values + ***************************************************************************/ + +const char EmulatedCamera::FACING_BACK[] = "back"; +const char EmulatedCamera::FACING_FRONT[] = "front"; + +/**************************************************************************** + * Parameter debugging helpers + ***************************************************************************/ + +#if DEBUG_PARAM +static void PrintParamDiff(const CameraParameters& current, + const char* new_par) { + char tmp[2048]; + const char* wrk = new_par; + + /* Divided with ';' */ + const char* next = strchr(wrk, ';'); + while (next != NULL) { + snprintf(tmp, sizeof(tmp), "%.*s", (int)(intptr_t)(next - wrk), wrk); + /* in the form key=value */ + char* val = strchr(tmp, '='); + if (val != NULL) { + *val = '\0'; + val++; + const char* in_current = current.get(tmp); + if (in_current != NULL) { + if (strcmp(in_current, val)) { + ALOGD("=== Value changed: %s: %s -> %s", tmp, in_current, val); + } + } else { + ALOGD("+++ New parameter: %s=%s", tmp, val); + } + } else { + ALOGW("No value separator in %s", tmp); + } + wrk = next + 1; + next = strchr(wrk, ';'); + } +} +#endif /* DEBUG_PARAM */ + +}; /* namespace android */ |