1284 lines
44 KiB
1284 lines
44 KiB
/*
|
|
* 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 <stdio.h>
|
|
#include "EmulatedCamera.h"
|
|
//#include "EmulatedFakeCameraDevice.h"
|
|
#include "Converters.h"
|
|
|
|
/* Defines whether we should trace parameter changes. */
|
|
#define DEBUG_PARAM 1
|
|
|
|
namespace android {
|
|
|
|
static const char* kValidFocusModes[] = {
|
|
CameraParameters::FOCUS_MODE_AUTO,
|
|
CameraParameters::FOCUS_MODE_INFINITY,
|
|
CameraParameters::FOCUS_MODE_MACRO,
|
|
CameraParameters::FOCUS_MODE_FIXED,
|
|
CameraParameters::FOCUS_MODE_EDOF,
|
|
CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO,
|
|
CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
|
|
};
|
|
|
|
#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 */
|
|
|
|
/*
|
|
* Check if a given string |value| equals at least one of the strings in |list|
|
|
*/
|
|
template<size_t N>
|
|
static bool IsValueInList(const char* value, const char* const (&list)[N])
|
|
{
|
|
for (size_t i = 0; i < N; ++i) {
|
|
if (strcmp(value, list[i]) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool StringsEqual(const char* str1, const char* str2) {
|
|
if (str1 == nullptr && str2 == nullptr) {
|
|
return true;
|
|
}
|
|
if (str1 == nullptr || str2 == nullptr) {
|
|
return false;
|
|
}
|
|
return strcmp(str1, str2) == 0;
|
|
}
|
|
|
|
static bool GetFourCcFormatFromCameraParam(const char* fmt_str,
|
|
uint32_t* fmt_val) {
|
|
if (strcmp(fmt_str, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
|
|
// Despite the name above this is a YVU format, specifically YV12
|
|
*fmt_val = V4L2_PIX_FMT_YVU420;
|
|
return true;
|
|
} else if (strcmp(fmt_str, CameraParameters::PIXEL_FORMAT_RGBA8888) == 0) {
|
|
*fmt_val = V4L2_PIX_FMT_RGB32;
|
|
return true;
|
|
} else if (strcmp(fmt_str, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
|
|
*fmt_val = V4L2_PIX_FMT_NV21;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
EmulatedCamera::EmulatedCamera(int cameraId,
|
|
struct hw_module_t* module,
|
|
GraphicBufferMapper* gbm)
|
|
: EmulatedBaseCamera(cameraId,
|
|
HARDWARE_DEVICE_API_VERSION(1, 0),
|
|
&common,
|
|
module),
|
|
mPreviewWindow(gbm),
|
|
mCallbackNotifier()
|
|
{
|
|
/* camera_device v1 fields. */
|
|
common.close = EmulatedCamera::close;
|
|
ops = &mDeviceOps;
|
|
priv = this;
|
|
}
|
|
|
|
EmulatedCamera::~EmulatedCamera()
|
|
{
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public API
|
|
***************************************************************************/
|
|
|
|
status_t EmulatedCamera::Initialize()
|
|
{
|
|
/* 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_RECORDING_HINT,
|
|
CameraParameters::FALSE);
|
|
mParameters.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, "320x240,0x0");
|
|
|
|
mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, "320");
|
|
mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, "240");
|
|
mParameters.set(CameraParameters::KEY_JPEG_QUALITY, "90");
|
|
// Camera values for a Logitech B910 HD Webcam
|
|
// Focal length: 4.90 mm (from specs)
|
|
// Horizontal view angle: 61 degrees for 4:3 sizes,
|
|
// 70 degrees for 16:9 sizes (empirical)
|
|
// Vertical view angle: 45.8 degrees (= 61 * 3 / 4)
|
|
// (The Mac has only "4:3" image sizes; the correct angle
|
|
// is 51.0 degrees. [MacBook Pro (Retina, 15-inch, Mid 2014)])
|
|
mParameters.set(CameraParameters::KEY_FOCAL_LENGTH, "4.90");
|
|
mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "61.0");
|
|
mParameters.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, "45.8");
|
|
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 rely 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, "(30000,30000)");
|
|
mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "30000,30000");
|
|
mParameters.setPreviewFrameRate(30);
|
|
|
|
/* 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);
|
|
|
|
/* Set suported antibanding values */
|
|
mParameters.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
|
|
CameraParameters::ANTIBANDING_AUTO);
|
|
mParameters.set(CameraParameters::KEY_ANTIBANDING,
|
|
CameraParameters::ANTIBANDING_AUTO);
|
|
|
|
/* Set control effect mode
|
|
* Bug: 30862244
|
|
* */
|
|
mParameters.set(CameraParameters::KEY_SUPPORTED_EFFECTS,
|
|
CameraParameters::EFFECT_NONE);
|
|
mParameters.set(CameraParameters::KEY_EFFECT,
|
|
CameraParameters::EFFECT_NONE);
|
|
|
|
/* Set focus distances for "near,optimal,far" */
|
|
mParameters.set(CameraParameters::KEY_FOCUS_DISTANCES,
|
|
"Infinity,Infinity,Infinity");
|
|
|
|
/* Not supported features
|
|
*/
|
|
mParameters.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
|
|
CameraParameters::FOCUS_MODE_FIXED);
|
|
mParameters.set(CameraParameters::KEY_FOCUS_MODE,
|
|
CameraParameters::FOCUS_MODE_FIXED);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void EmulatedCamera::onNextFrameAvailable(nsecs_t timestamp,
|
|
EmulatedCameraDevice* camera_dev)
|
|
{
|
|
/* Notify the preview window first. */
|
|
mPreviewWindow.onNextFrameAvailable(timestamp, camera_dev);
|
|
|
|
/* Notify callback notifier next. */
|
|
mCallbackNotifier.onNextFrameAvailable(timestamp, camera_dev);
|
|
}
|
|
|
|
void EmulatedCamera::onCameraDeviceError(int err)
|
|
{
|
|
/* Errors are reported through the callback notifier */
|
|
mCallbackNotifier.onCameraDeviceError(err);
|
|
}
|
|
|
|
void EmulatedCamera::setTakingPicture(bool takingPicture) {
|
|
mCallbackNotifier.setTakingPicture(takingPicture);
|
|
}
|
|
/****************************************************************************
|
|
* 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;
|
|
}
|
|
|
|
return EmulatedBaseCamera::getCameraInfo(info);
|
|
}
|
|
|
|
void EmulatedCamera::autoFocusComplete() {
|
|
mCallbackNotifier.autoFocusComplete();
|
|
}
|
|
|
|
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()
|
|
{
|
|
/* The camera client will not pass on calls to set the preview window to
|
|
* NULL if the preview is not enabled. If preview is not enabled the camera
|
|
* client will instead simply destroy the preview window without notifying
|
|
* the HAL. Later on when preview is enabled again that means the HAL will
|
|
* attempt to use the old, destroyed window which will cause a crash.
|
|
* Instead we need to clear the preview window here, the client will set
|
|
* a preview window when needed. The preview window is cleared here instead
|
|
* of inside doStopPreview to prevent the window from being cleared when
|
|
* restarting the preview because of a parameter change. */
|
|
mPreviewWindow.setPreviewWindow(nullptr, 0);
|
|
|
|
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()
|
|
{
|
|
/* This callback should return a negative errno, hence all the negations */
|
|
if (!mPreviewWindow.isPreviewEnabled()) {
|
|
ALOGE("%s: start recording without preview enabled",
|
|
__FUNCTION__);
|
|
return INVALID_OPERATION;
|
|
}
|
|
int frameRate = mParameters.getPreviewFrameRate();
|
|
status_t res = mCallbackNotifier.enableVideoRecording(frameRate);
|
|
if (res != NO_ERROR) {
|
|
ALOGE("%s: CallbackNotifier failed to enable video recording",
|
|
__FUNCTION__);
|
|
stopRecording();
|
|
return -res;
|
|
}
|
|
EmulatedCameraDevice* const camera_dev = getCameraDevice();
|
|
if (camera_dev == nullptr || !camera_dev->isStarted()) {
|
|
// No need for restarts, the next preview start will use correct params
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// If the camera is running we might have to restart it to accomodate
|
|
// whatever pixel format and frame size the caller wants.
|
|
uint32_t conf_fmt = 0;
|
|
res = getConfiguredPixelFormat(&conf_fmt);
|
|
if (res != NO_ERROR) {
|
|
stopRecording();
|
|
return -res;
|
|
}
|
|
uint32_t cur_fmt = camera_dev->getOriginalPixelFormat();
|
|
int conf_width = -1, conf_height = -1;
|
|
res = getConfiguredFrameSize(&conf_width, &conf_height);
|
|
if (res != NO_ERROR) {
|
|
stopRecording();
|
|
return -res;
|
|
}
|
|
int cur_width = camera_dev->getFrameWidth();
|
|
int cur_height = camera_dev->getFrameHeight();
|
|
|
|
if (cur_fmt != conf_fmt ||
|
|
cur_width != conf_width ||
|
|
cur_height != conf_height) {
|
|
// We need to perform a restart to use the new format or size and it
|
|
// has to be an asynchronous restart or this might block if the camera
|
|
// thread is currently delivering a frame.
|
|
if (!camera_dev->requestRestart(conf_width, conf_height, conf_fmt,
|
|
false /* takingPicture */,
|
|
false /* oneBurst */)) {
|
|
ALOGE("%s: Could not restart preview with new pixel format",
|
|
__FUNCTION__);
|
|
stopRecording();
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
ALOGD("go all the way to the end");
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void EmulatedCamera::stopRecording()
|
|
{
|
|
mCallbackNotifier.disableVideoRecording();
|
|
}
|
|
|
|
int EmulatedCamera::isRecordingEnabled()
|
|
{
|
|
return mCallbackNotifier.isVideoRecordingEnabled();
|
|
}
|
|
|
|
void EmulatedCamera::releaseRecordingFrame(const void* opaque)
|
|
{
|
|
mCallbackNotifier.releaseRecordingFrame(opaque);
|
|
}
|
|
|
|
status_t EmulatedCamera::setAutoFocus()
|
|
{
|
|
// Make sure to check that a preview is in progress. Otherwise this will
|
|
// silently fail because no callback will be called until the preview starts
|
|
// which might be never.
|
|
if (!isPreviewEnabled()) {
|
|
return EINVAL;
|
|
}
|
|
EmulatedCameraDevice* const camera_dev = getCameraDevice();
|
|
if (camera_dev && camera_dev->isStarted()) {
|
|
return camera_dev->setAutoFocus();
|
|
}
|
|
return EINVAL;
|
|
}
|
|
|
|
status_t EmulatedCamera::cancelAutoFocus()
|
|
{
|
|
// In this case we don't check if a preview is in progress or not. Unlike
|
|
// setAutoFocus this call will not silently fail without the check. If an
|
|
// auto-focus request is somehow pending without having preview enabled this
|
|
// will correctly cancel that pending auto-focus which seems reasonable.
|
|
EmulatedCameraDevice* const camera_dev = getCameraDevice();
|
|
if (camera_dev && camera_dev->isStarted()) {
|
|
return camera_dev->cancelAutoFocus();
|
|
}
|
|
return EINVAL;
|
|
}
|
|
|
|
status_t EmulatedCamera::takePicture()
|
|
{
|
|
ALOGV("%s", __FUNCTION__);
|
|
|
|
int width, height;
|
|
uint32_t org_fmt;
|
|
|
|
/* Collect frame info for the picture. */
|
|
mParameters.getPictureSize(&width, &height);
|
|
const char* pix_fmt = mParameters.getPictureFormat();
|
|
if (!GetFourCcFormatFromCameraParam(pix_fmt, &org_fmt)) {
|
|
// Also check for JPEG here, the function above does not do this since
|
|
// this is very specific to this use case.
|
|
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.
|
|
*/
|
|
|
|
EmulatedCameraDevice* const camera_dev = getCameraDevice();
|
|
mCallbackNotifier.setJpegQuality(jpeg_quality);
|
|
mCallbackNotifier.setCameraParameters(mParameters);
|
|
|
|
ALOGD("Starting camera for picture: %.4s(%s)[%dx%d]",
|
|
reinterpret_cast<const char*>(&org_fmt), pix_fmt, width, height);
|
|
if (mPreviewWindow.isPreviewEnabled()) {
|
|
mPreviewWindow.stopPreview();
|
|
/* If the camera preview is enabled we need to perform an asynchronous
|
|
* restart. A blocking restart could deadlock this thread as it's
|
|
* currently holding the camera client lock and the frame delivery could
|
|
* be stuck on waiting for that lock. If this was synchronous then this
|
|
* thread would in turn get stuck on waiting for the delivery thread. */
|
|
if (!camera_dev->requestRestart(width, height, org_fmt,
|
|
true /* takingPicture */,
|
|
true /* oneBurst */)) {
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
} else {
|
|
ALOGE("%s: preview has not been enabled", __FUNCTION__);
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
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);
|
|
bool restartPreview = false;
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
}
|
|
int old_frame_rate = mParameters.getPreviewFrameRate();
|
|
int new_frame_rate = new_param.getPreviewFrameRate();
|
|
if (old_frame_rate != new_frame_rate) {
|
|
getCameraDevice()->setPreviewFrameRate(new_frame_rate);
|
|
}
|
|
|
|
// Validate KEY_PREVIEW_FPS_RANGE i.e., "preview-fps-range"
|
|
const char* preview_fps_range = new_param.get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
|
|
if (preview_fps_range) {
|
|
char tmp[1024];
|
|
snprintf(tmp, sizeof(tmp), "%s", preview_fps_range);
|
|
int low=-1, high=-1;
|
|
if (sscanf(tmp, "%d,%d", &low, &high) != 2) {
|
|
ALOGE("incorrect preview-fps-range %s", tmp);
|
|
return BAD_VALUE;
|
|
}
|
|
if (low < 0 || high < 0) {
|
|
ALOGE("negative preview_fps_range in %s", tmp);
|
|
return BAD_VALUE;
|
|
}
|
|
if (low > high) {
|
|
ALOGE("invalid preview_fps_range in %s", tmp);
|
|
return BAD_VALUE;
|
|
}
|
|
}
|
|
|
|
// Validate focus mode
|
|
const char* focus_mode = new_param.get(CameraParameters::KEY_FOCUS_MODE);
|
|
if (focus_mode && !IsValueInList(focus_mode, kValidFocusModes)) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// Validate preview size, if there is no preview size the initial values of
|
|
// the integers below will be preserved thus intentionally failing the test
|
|
int new_preview_width = -1, new_preview_height = -1;
|
|
new_param.getPreviewSize(&new_preview_width, &new_preview_height);
|
|
if (new_preview_width < 0 || new_preview_height < 0) {
|
|
return BAD_VALUE;
|
|
}
|
|
// If the preview size has changed we have to restart the preview to make
|
|
// sure we provide frames of the correct size. The receiver assumes the
|
|
// frame size is correct and will copy all data provided into a buffer whose
|
|
// size is determined by the preview size without checks, potentially
|
|
// causing buffer overruns or underruns if there is a size mismatch.
|
|
int old_preview_width = -1, old_preview_height = -1;
|
|
mParameters.getPreviewSize(&old_preview_width, &old_preview_height);
|
|
if (old_preview_width != new_preview_width ||
|
|
old_preview_height != new_preview_height) {
|
|
restartPreview = true;
|
|
}
|
|
|
|
// For the same reasons as with the preview size we have to look for changes
|
|
// in video size and restart the preview if the size has changed.
|
|
int old_video_width = -1, old_video_height = -1;
|
|
int new_video_width = -1, new_video_height = -1;
|
|
mParameters.getVideoSize(&old_video_width, &old_video_height);
|
|
new_param.getVideoSize(&new_video_width, &new_video_height);
|
|
if (old_video_width != new_video_width ||
|
|
old_video_height != new_video_height) {
|
|
restartPreview = true;
|
|
}
|
|
// Restart the preview if the pixel format changes to make sure we serve
|
|
// the selected encoding to the client.
|
|
const char* old_format = mParameters.getPreviewFormat();
|
|
const char* new_format = new_param.getPreviewFormat();
|
|
if (!StringsEqual(old_format, new_format)) {
|
|
restartPreview = true;
|
|
}
|
|
|
|
const char* old_hint =
|
|
mParameters.get(CameraParameters::KEY_RECORDING_HINT);
|
|
const char* new_hint = new_param.get(CameraParameters::KEY_RECORDING_HINT);
|
|
if (!StringsEqual(old_hint, new_hint)) {
|
|
// The recording hint changed, this indicates we transitioned from
|
|
// recording to non-recording or the other way around. We need to look
|
|
// at a new pixel format for this and that requires a restart.
|
|
restartPreview = true;
|
|
}
|
|
|
|
mParameters = new_param;
|
|
|
|
// Now that the parameters have been assigned check if the preview needs to
|
|
// be restarted. If necessary this will then use the new parameters to set
|
|
// up the preview as requested by the caller.
|
|
if (restartPreview && isPreviewEnabled()) {
|
|
status_t status = doStopPreview();
|
|
if (status != NO_ERROR) {
|
|
ALOGE("%s: Stopping preview failed: %d", __FUNCTION__, status);
|
|
return status;
|
|
}
|
|
status = doStartPreview();
|
|
if (status != NO_ERROR) {
|
|
ALOGE("%s: Starting preview failed: %d", __FUNCTION__, status);
|
|
return status;
|
|
}
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* A variable indicating "no params" / error on the exit from
|
|
* EmulatedCamera::getParameters(). */
|
|
static char lNoParam = '\0';
|
|
char* EmulatedCamera::getParameters()
|
|
{
|
|
// Read the image size and set the camera's Field of View.
|
|
// These values are valid for a Logitech B910 HD Webcam.
|
|
int width=0, height=0;
|
|
mParameters.getPictureSize(&width, &height);
|
|
if (height > 0) {
|
|
if (((double)width / height) < 1.55) {
|
|
// Closer to 4:3 (1.33), set the FOV to 61.0 degrees
|
|
mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "61.0");
|
|
} else {
|
|
// Closer to 16:9 (1.77), set the FOV to 70.0 degrees
|
|
mParameters.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, "70.0");
|
|
}
|
|
}
|
|
|
|
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:
|
|
// We do not support hardware face detection so we need to indicate
|
|
// that any attempt to start/stop face detection is invalid
|
|
return BAD_VALUE;
|
|
}
|
|
/* TODO: Future enhancements. */
|
|
return 0;
|
|
}
|
|
|
|
void EmulatedCamera::releaseCamera()
|
|
{
|
|
ALOGV("%s", __FUNCTION__);
|
|
|
|
cleanupCamera();
|
|
}
|
|
|
|
status_t EmulatedCamera::dumpCamera(int fd)
|
|
{
|
|
ALOGV("%s", __FUNCTION__);
|
|
|
|
/* TODO: Future enhancements. */
|
|
dprintf(fd, "dump camera unimplemented\n");
|
|
return 0;
|
|
}
|
|
|
|
status_t EmulatedCamera::getConfiguredPixelFormat(uint32_t* pixelFormat) const {
|
|
const char* pix_fmt = nullptr;
|
|
const char* recordingHint =
|
|
mParameters.get(CameraParameters::KEY_RECORDING_HINT);
|
|
bool recordingHintOn = recordingHint && strcmp(recordingHint,
|
|
CameraParameters::TRUE) == 0;
|
|
bool recordingEnabled = mCallbackNotifier.isVideoRecordingEnabled();
|
|
if (recordingHintOn || recordingEnabled) {
|
|
// We're recording a video, use the video pixel format
|
|
pix_fmt = mParameters.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT);
|
|
}
|
|
if (pix_fmt == nullptr) {
|
|
pix_fmt = mParameters.getPreviewFormat();
|
|
}
|
|
if (pix_fmt == nullptr) {
|
|
ALOGE("%s: Unable to obtain configured pixel format", __FUNCTION__);
|
|
return EINVAL;
|
|
}
|
|
/* Convert framework's pixel format to the FOURCC one. */
|
|
if (!GetFourCcFormatFromCameraParam(pix_fmt, pixelFormat)) {
|
|
ALOGE("%s: Unsupported pixel format %s", __FUNCTION__, pix_fmt);
|
|
return EINVAL;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t EmulatedCamera::getConfiguredFrameSize(int* outWidth,
|
|
int* outHeight) const {
|
|
int width = -1, height = -1;
|
|
if (mParameters.get(CameraParameters::KEY_VIDEO_SIZE) != nullptr) {
|
|
mParameters.getVideoSize(&width, &height);
|
|
} else {
|
|
mParameters.getPreviewSize(&width, &height);
|
|
}
|
|
if (width < 0 || height < 0) {
|
|
ALOGE("%s: No frame size configured for camera", __FUNCTION__);
|
|
return EINVAL;
|
|
}
|
|
// Only modify the out parameters once we know we succeeded
|
|
*outWidth = width;
|
|
*outHeight = height;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
/* Lets see what should we use for frame width, and height. */
|
|
int width, height;
|
|
res = getConfiguredFrameSize(&width, &height);
|
|
if (res != NO_ERROR) {
|
|
mPreviewWindow.stopPreview();
|
|
return res;
|
|
}
|
|
|
|
uint32_t org_fmt = 0;
|
|
res = getConfiguredPixelFormat(&org_fmt);
|
|
if (res != NO_ERROR) {
|
|
mPreviewWindow.stopPreview();
|
|
return res;
|
|
}
|
|
|
|
camera_dev->setPreviewFrameRate(mParameters.getPreviewFrameRate());
|
|
ALOGD("Starting camera: %dx%d -> %.4s",
|
|
width, height, reinterpret_cast<const char*>(&org_fmt));
|
|
res = camera_dev->startDevice(width, height, org_fmt);
|
|
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();
|
|
|
|
/* Re-init the camera settings in case settings were changed */
|
|
Initialize();
|
|
|
|
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 */
|