/* ** ** Copyright 2008, The Android Open Source Project ** Copyright 2010, Samsung Electronics Co. LTD ** ** 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. */ /*! * \file ExynosCameraHWInterface.h * \brief source file for Android Camera HAL * \author thun.hwang(thun.hwang@samsung.com) * \date 2010/06/03 * * <b>Revision History: </b> * - 2011/12/31 : thun.hwang(thun.hwang@samsung.com) \n * Initial version * * - 2012/02/01 : Sangwoo, Park(sw5771.park@samsung.com) \n * Adjust Android Standard features * * - 2012/03/14 : sangwoo.park(sw5771.park@samsung.com) \n * Change file, class name to ExynosXXX. * */ #include <sys/types.h> #include <sys/stat.h> //#define LOG_NDEBUG 0 #define LOG_TAG "ExynosCameraHWInterface" #include <utils/Log.h> #include "ExynosCameraHWInterface.h" #include "exynos_format.h" #define VIDEO_COMMENT_MARKER_H (0xFFBE) #define VIDEO_COMMENT_MARKER_L (0xFFBF) #define VIDEO_COMMENT_MARKER_LENGTH (4) #define JPEG_EOI_MARKER (0xFFD9) #define HIBYTE(x) (((x) >> 8) & 0xFF) #define LOBYTE(x) ((x) & 0xFF) /*TODO: This values will be changed */ #define BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR "0.10,1.20,Infinity" #define FRONT_CAMERA_FOCUS_DISTANCES_STR "0.20,0.25,Infinity" #define BACK_CAMERA_MACRO_FOCUS_DISTANCES_STR "0.10,0.20,Infinity" #define BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR "0.10,1.20,Infinity" #define BACK_CAMERA_FOCUS_DISTANCE_INFINITY "Infinity" #define FRONT_CAMERA_FOCUS_DISTANCE_INFINITY "Infinity" // This hack does two things: // -- it sets preview to NV21 (YUV420SP) // -- it sets gralloc to YV12 // // The reason being: the samsung encoder understands only yuv420sp, and gralloc // does yv12 and rgb565. So what we do is we break up the interleaved UV in // separate V and U planes, which makes preview look good, and enabled the // encoder as well. // // FIXME: Samsung needs to enable support for proper yv12 coming out of the // camera, and to fix their video encoder to work with yv12. // FIXME: It also seems like either Samsung's YUV420SP (NV21) or img's YV12 has // the color planes switched. We need to figure which side is doing it // wrong and have the respective party fix it. namespace android { static const int INITIAL_SKIP_FRAME = 8; static const int EFFECT_SKIP_FRAME = 1; gralloc_module_t const* ExynosCameraHWInterface::m_grallocHal; ExynosCameraHWInterface::ExynosCameraHWInterface(int cameraId, camera_device_t *dev) : m_captureInProgress(false), m_skipFrame(0), m_notifyCb(0), m_dataCb(0), m_dataCbTimestamp(0), m_callbackCookie(0), m_msgEnabled(0), m_faceDetected(false), m_halDevice(dev), m_numOfAvailableVideoBuf(0) { ALOGV("DEBUG(%s):", __func__); int ret = 0; m_previewWindow = NULL; m_secCamera = ExynosCamera::createInstance(); for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { m_previewHeap[i] = NULL; m_previewBufHandle[i] = NULL; m_previewStride[i] = 0; m_avaliblePreviewBufHandle[i] = false; m_flagGrallocLocked[i] = false; m_matchedGrallocIndex[i] = -1; m_grallocVirtAddr[i] = NULL; } m_minUndequeuedBufs = 0; #ifndef USE_3DNR_DMAOUT m_cntVideoBuf = 0; #endif m_oldPictureBufQueueHead = NULL; m_getMemoryCb = NULL; m_exynosPreviewCSC = NULL; m_exynosPictureCSC = NULL; m_exynosVideoCSC = NULL; m_frameMetadata.number_of_faces = 0; m_frameMetadata.faces = m_faces; for (int i = 0; i < NUM_OF_VIDEO_BUF; i++) { m_videoHeap[i] = NULL; m_resizedVideoHeap[i] = NULL; } m_ion_client = ion_client_create(); for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) m_pictureHeap[i] = NULL; m_rawHeap = NULL; m_exitAutoFocusThread = false; m_exitPreviewThread = false; m_exitVideoThread = false; /* whether the PreviewThread is active in preview or stopped. we * create the thread but it is initially in stopped state. */ m_previewRunning = false; m_videoRunning = false; m_pictureRunning = false; #ifndef USE_3DNR_DMAOUT m_videoStart = false; #endif m_previewStartDeferred = false; m_recordingHint = false; if (!m_grallocHal) { ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const hw_module_t **)&m_grallocHal); if (ret) ALOGE("ERR(%s):Fail on loading gralloc HAL", __func__); } if (m_secCamera->create(cameraId) == false) { ALOGE("ERR(%s):Fail on m_secCamera->create(%d)", __func__, cameraId); return; } m_initDefaultParameters(cameraId); CSC_METHOD cscMethod = CSC_METHOD_HW; m_exynosPreviewCSC = csc_init(cscMethod); if (m_exynosPreviewCSC == NULL) ALOGE("ERR(%s):csc_init() fail", __func__); m_exynosPictureCSC = csc_init(cscMethod); if (m_exynosPictureCSC == NULL) ALOGE("ERR(%s):csc_init() fail", __func__); m_exynosVideoCSC = csc_init(cscMethod); if (m_exynosVideoCSC == NULL) ALOGE("ERR(%s):csc_init() fail", __func__); m_previewThread = new PreviewThread(this); m_videoThread = new VideoThread(this); m_autoFocusThread = new AutoFocusThread(this); m_pictureThread = new PictureThread(this); } ExynosCameraHWInterface::~ExynosCameraHWInterface() { close(m_ion_client); this->release(); } status_t ExynosCameraHWInterface::setPreviewWindow(preview_stream_ops *w) { m_previewWindow = w; ALOGV("DEBUG(%s):m_previewWindow %p", __func__, m_previewWindow); if (m_previewWindow == NULL) { ALOGV("DEBUG(%s):preview window is NULL!", __func__); return OK; } m_previewLock.lock(); if (m_previewRunning == true && m_previewStartDeferred == false) { ALOGV("DEBUG(%s):stop preview (window change)", __func__); m_stopPreviewInternal(); } if (m_previewWindow->get_min_undequeued_buffer_count(m_previewWindow, &m_minUndequeuedBufs) != 0) { ALOGE("ERR(%s):could not retrieve min undequeued buffer count", __func__); return INVALID_OPERATION; } if (NUM_OF_PREVIEW_BUF <= m_minUndequeuedBufs) { ALOGE("ERR(%s):min undequeued buffer count %d is too high (expecting at most %d)", __func__, m_minUndequeuedBufs, NUM_OF_PREVIEW_BUF - 1); } if (m_previewWindow->set_buffer_count(m_previewWindow, NUM_OF_PREVIEW_BUF) != 0) { ALOGE("ERR(%s):could not set buffer count", __func__); return INVALID_OPERATION; } int previewW, previewH; int hal_pixel_format = HAL_PIXEL_FORMAT_YV12; m_params.getPreviewSize(&previewW, &previewH); const char *str_preview_format = m_params.getPreviewFormat(); ALOGV("DEBUG(%s):str preview format %s width : %d height : %d ", __func__, str_preview_format, previewW, previewH); if (!strcmp(str_preview_format, CameraParameters::PIXEL_FORMAT_RGB565)) { hal_pixel_format = HAL_PIXEL_FORMAT_RGB_565; } else if (!strcmp(str_preview_format, CameraParameters::PIXEL_FORMAT_RGBA8888)) { hal_pixel_format = HAL_PIXEL_FORMAT_RGBA_8888; } else if (!strcmp(str_preview_format, CameraParameters::PIXEL_FORMAT_YUV420SP)) { hal_pixel_format = HAL_PIXEL_FORMAT_YCrCb_420_SP; } else if (!strcmp(str_preview_format, CameraParameters::PIXEL_FORMAT_YUV420P)) hal_pixel_format = HAL_PIXEL_FORMAT_YV12; if (m_previewWindow->set_usage(m_previewWindow, GRALLOC_USAGE_SW_WRITE_OFTEN | #ifdef USE_EGL #else GRALLOC_USAGE_HWC_HWOVERLAY | #endif GRALLOC_USAGE_HW_ION) != 0) { ALOGE("ERR(%s):could not set usage on gralloc buffer", __func__); return INVALID_OPERATION; } if (m_previewWindow->set_buffers_geometry(m_previewWindow, previewW, previewH, hal_pixel_format) != 0) { ALOGE("ERR(%s):could not set buffers geometry to %s", __func__, str_preview_format); return INVALID_OPERATION; } if (m_previewRunning == true && m_previewStartDeferred == true) { ALOGV("DEBUG(%s):start/resume preview", __func__); if (m_startPreviewInternal() == true) { m_previewStartDeferred = false; m_previewCondition.signal(); } } m_previewLock.unlock(); return OK; } void ExynosCameraHWInterface::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) { m_notifyCb = notify_cb; m_dataCb = data_cb; m_dataCbTimestamp = data_cb_timestamp; m_getMemoryCb = get_memory; m_callbackCookie = user; } void ExynosCameraHWInterface::enableMsgType(int32_t msgType) { ALOGV("DEBUG(%s):msgType = 0x%x, m_msgEnabled before = 0x%x", __func__, msgType, m_msgEnabled); m_msgEnabled |= msgType; m_previewLock.lock(); if ( msgType & CAMERA_MSG_PREVIEW_FRAME && m_previewRunning == true && m_previewStartDeferred == true) { ALOGV("DEBUG(%s):starting deferred preview", __func__); if (m_startPreviewInternal() == true) { m_previewStartDeferred = false; m_previewCondition.signal(); } } m_previewLock.unlock(); ALOGV("DEBUG(%s):m_msgEnabled = 0x%x", __func__, m_msgEnabled); } void ExynosCameraHWInterface::disableMsgType(int32_t msgType) { ALOGV("DEBUG(%s):msgType = 0x%x, m_msgEnabled before = 0x%x", __func__, msgType, m_msgEnabled); m_msgEnabled &= ~msgType; ALOGV("DEBUG(%s):m_msgEnabled = 0x%x", __func__, m_msgEnabled); } bool ExynosCameraHWInterface::msgTypeEnabled(int32_t msgType) { return (m_msgEnabled & msgType); } status_t ExynosCameraHWInterface::startPreview() { int ret = OK; ALOGV("DEBUG(%s):", __func__); Mutex::Autolock lock(m_stateLock); if (m_captureInProgress == true) { ALOGE("%s : capture in progress, not allowed", __func__); return INVALID_OPERATION; } m_previewLock.lock(); if (m_previewRunning == true) { ALOGE("%s : preview thread already running", __func__); m_previewLock.unlock(); return INVALID_OPERATION; } m_previewRunning = true; m_previewStartDeferred = false; if (m_previewWindow == NULL) { if (!(m_msgEnabled & CAMERA_MSG_PREVIEW_FRAME)) { ALOGV("DEBUG(%s):deferring", __func__); m_previewStartDeferred = true; m_previewLock.unlock(); return NO_ERROR; } ALOGE("%s(%d): m_previewWindow is NULL", __func__, __LINE__); return UNKNOWN_ERROR; } if (m_startPreviewInternal() == true) { m_previewCondition.signal(); ret = OK; } else { ret = UNKNOWN_ERROR; } m_previewLock.unlock(); return ret; } void ExynosCameraHWInterface::stopPreview() { ALOGV("DEBUG(%s):", __func__); /* request that the preview thread stop. */ m_previewLock.lock(); m_stopPreviewInternal(); m_previewLock.unlock(); } bool ExynosCameraHWInterface::previewEnabled() { Mutex::Autolock lock(m_previewLock); ALOGV("DEBUG(%s):%d", __func__, m_previewRunning); return m_previewRunning; } status_t ExynosCameraHWInterface::storeMetaDataInBuffers(bool enable) { if (!enable) { ALOGE("Non-m_frameMetadata buffer mode is not supported!"); return INVALID_OPERATION; } return OK; } status_t ExynosCameraHWInterface::startRecording() { ALOGV("DEBUG(%s):", __func__); Mutex::Autolock lock(m_videoLock); int videoW, videoH, videoFormat, videoFramesize; m_secCamera->getVideoSize(&videoW, &videoH); videoFormat = m_secCamera->getVideoFormat(); videoFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), videoW, videoH); int orgVideoFrameSize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), m_orgVideoRect.w, m_orgVideoRect.h); for (int i = 0; i < NUM_OF_VIDEO_BUF; i++) { #ifdef USE_3DNR_DMAOUT ExynosBuffer videoBuf; if (m_videoHeap[i] != NULL) { m_videoHeap[i]->release(m_videoHeap[i]); m_videoHeap[i] = 0; } m_videoHeap[i] = m_getMemoryCb(-1, videoFramesize, 1, NULL); if (!m_videoHeap[i]) { ALOGE("ERR(%s):m_getMemoryCb(m_videoHeap[%d], size(%d) fail", __func__, i, videoFramesize); return UNKNOWN_ERROR; } m_getAlignedYUVSize(videoFormat, videoW, videoH, &videoBuf); videoBuf.virt.extP[0] = (char *)m_videoHeap[i]->data; for (int j = 1; j < 3; j++) { if (videoBuf.size.extS[j] != 0) videoBuf.virt.extP[j] = videoBuf.virt.extP[j-1] + videoBuf.size.extS[j-1]; else videoBuf.virt.extP[j] = NULL; } videoBuf.reserved.p = i; m_secCamera->setVideoBuf(&videoBuf); #endif // original VideoSized heap if (m_resizedVideoHeap[i] != NULL) { m_resizedVideoHeap[i]->release(m_resizedVideoHeap[i]); m_resizedVideoHeap[i] = 0; } m_resizedVideoHeap[i] = m_getMemoryCb(-1, orgVideoFrameSize, 1, NULL); if (!m_resizedVideoHeap[i]) { ALOGE("ERR(%s):m_getMemoryCb(m_resizedVideoHeap[%d], size(%d) fail", __func__, i, orgVideoFrameSize); return UNKNOWN_ERROR; } } if (m_videoRunning == false) { if (m_secCamera->startVideo() == false) { ALOGE("ERR(%s):Fail on m_secCamera->startVideo()", __func__); return UNKNOWN_ERROR; } m_numOfAvailableVideoBuf = NUM_OF_VIDEO_BUF; #ifdef USE_3DNR_DMAOUT m_videoRunning = true; m_videoCondition.signal(); #else m_videoStart = true; #endif } return NO_ERROR; } void ExynosCameraHWInterface::stopRecording() { ALOGV("DEBUG(%s):", __func__); #ifndef USE_3DNR_DMAOUT m_videoStart = false; #endif if (m_videoRunning == true) { m_videoRunning = false; Mutex::Autolock lock(m_videoLock); m_videoCondition.signal(); /* wait until video thread is stopped */ m_videoStoppedCondition.wait(m_videoLock); } else ALOGV("DEBUG(%s):video not running, doing nothing", __func__); } bool ExynosCameraHWInterface::recordingEnabled() { return m_videoStart; } void ExynosCameraHWInterface::releaseRecordingFrame(const void *opaque) { // This lock makes video lock up // Mutex::Autolock lock(m_videoLock); int i; bool find = false; // HACK : this causes recording slow /* for (i = 0; i < NUM_OF_VIDEO_BUF; i++) { if ((char *)m_videoHeap[i]->data == (char *)opaque) { find = true; break; } } if (find == true) { ExynosBuffer videoBuf; videoBuf.reserved.p = i; m_secCamera->putVideoBuf(&videoBuf); m_numOfAvailableVideoBuf++; if (NUM_OF_VIDEO_BUF <= m_numOfAvailableVideoBuf) m_numOfAvailableVideoBuf = NUM_OF_VIDEO_BUF; } else { ALOGV("DEBUG(%s):no matched index(%p)", __func__, (char *)opaque); } */ } status_t ExynosCameraHWInterface::autoFocus() { ALOGV("DEBUG(%s):", __func__); /* signal m_autoFocusThread to run once */ m_focusCondition.signal(); return NO_ERROR; } status_t ExynosCameraHWInterface::cancelAutoFocus() { if (m_secCamera->cancelAutoFocus() == false) { ALOGE("ERR(%s):Fail on m_secCamera->cancelAutoFocus()", __func__); return UNKNOWN_ERROR; } return NO_ERROR; } status_t ExynosCameraHWInterface::takePicture() { Mutex::Autolock lock(m_stateLock); if (m_captureInProgress == true) { ALOGE("%s : capture already in progress", __func__); return INVALID_OPERATION; } if (m_pictureRunning == false) { ALOGI("%s(%d): m_pictureRunning is false", __func__, __LINE__); if (m_startPictureInternal() == false) { ALOGE("%s(%d): m_startPictureInternal() fail!!!", __func__, __LINE__); return INVALID_OPERATION; } } m_pictureLock.lock(); m_captureInProgress = true; m_pictureLock.unlock(); if (m_pictureThread->run("CameraPictureThread", PRIORITY_DEFAULT) != NO_ERROR) { ALOGE("%s : couldn't run picture thread", __func__); return INVALID_OPERATION; } return NO_ERROR; } status_t ExynosCameraHWInterface::cancelPicture() { ALOGV("DEBUG(%s):", __func__); if (m_pictureThread.get()) { ALOGV("DEBUG(%s):waiting for picture thread to exit", __func__); m_pictureThread->requestExitAndWait(); ALOGV("DEBUG(%s):picture thread has exited", __func__); } return NO_ERROR; } status_t ExynosCameraHWInterface::setParameters(const CameraParameters& params) { ALOGV("DEBUG(%s):", __func__); status_t ret = NO_ERROR; /* if someone calls us while picture thread is running, it could screw * up the sensor quite a bit so return error. we can't wait because * that would cause deadlock with the callbacks */ m_stateLock.lock(); if (m_captureInProgress == true) { m_stateLock.unlock(); m_pictureLock.lock(); m_pictureCondition.waitRelative(m_pictureLock, (2000 * 1000000)); m_pictureLock.unlock(); } m_stateLock.unlock(); /////////////////////////////////////////////////// // Google Official API : Camera.Parameters // http://developer.android.com/reference/android/hardware/Camera.Parameters.html /////////////////////////////////////////////////// // recording hint const char *newRecordingHint = params.get(CameraParameters::KEY_RECORDING_HINT); if (newRecordingHint != NULL) { if (strcmp(newRecordingHint, "true") == 0) m_recordingHint = true; else m_recordingHint = false; m_secCamera->setRecordingHint(m_recordingHint); } // preview size int newPreviewW = 0; int newPreviewH = 0; int newCalPreviewW = 0; int newCalPreviewH = 0; int previewMaxW = 0; int previewMaxH = 0; params.getPreviewSize(&newPreviewW, &newPreviewH); // In general, it will show preview max size m_secCamera->getSupportedPreviewSizes(&previewMaxW, &previewMaxH); newCalPreviewW = previewMaxW; newCalPreviewH = previewMaxH; // When recording, it will show video max size if (m_recordingHint == true) { m_secCamera->getSupportedVideoSizes(&newCalPreviewW, &newCalPreviewH); if ( previewMaxW < newCalPreviewW || previewMaxH < newCalPreviewH) { newCalPreviewW = previewMaxW; newCalPreviewH = previewMaxH; } } m_orgPreviewRect.w = newPreviewW; m_orgPreviewRect.h = newPreviewH; // TODO : calibrate original preview ratio //m_getRatioSize(newCalPreviewW, newCalPreviewH, newPreviewW, newPreviewH, &newPreviewW, &newPreviewH); newPreviewW = newCalPreviewW; newPreviewH = newCalPreviewH; const char *strNewPreviewFormat = params.getPreviewFormat(); ALOGV("DEBUG(%s):newPreviewW x newPreviewH = %dx%d, format = %s", __func__, newPreviewW, newPreviewH, strNewPreviewFormat); if (0 < newPreviewW && 0 < newPreviewH && strNewPreviewFormat != NULL && m_isSupportedPreviewSize(newPreviewW, newPreviewH) == true) { int newPreviewFormat = 0; if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_RGB565)) newPreviewFormat = V4L2_PIX_FMT_RGB565; else if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_RGBA8888)) newPreviewFormat = V4L2_PIX_FMT_RGB32; else if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) newPreviewFormat = V4L2_PIX_FMT_NV21; else if (!strcmp(strNewPreviewFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) newPreviewFormat = V4L2_PIX_FMT_YVU420M; else if (!strcmp(strNewPreviewFormat, "yuv420sp_custom")) newPreviewFormat = V4L2_PIX_FMT_NV12T; else if (!strcmp(strNewPreviewFormat, "yuv422i")) newPreviewFormat = V4L2_PIX_FMT_YUYV; else if (!strcmp(strNewPreviewFormat, "yuv422p")) newPreviewFormat = V4L2_PIX_FMT_YUV422P; else newPreviewFormat = V4L2_PIX_FMT_NV21; //for 3rd party m_orgPreviewRect.colorFormat = newPreviewFormat; int curPreviewW, curPreviewH; m_secCamera->getPreviewSize(&curPreviewW, &curPreviewH); int curPreviewFormat = m_secCamera->getPreviewFormat(); if (curPreviewW != newPreviewW || curPreviewH != newPreviewH || curPreviewFormat != newPreviewFormat) { if ( m_secCamera->setPreviewSize(newPreviewW, newPreviewH) == false || m_secCamera->setPreviewFormat(newPreviewFormat) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setPreviewSize(width(%d), height(%d), format(%d))", __func__, newPreviewW, newPreviewH, newPreviewFormat); ret = UNKNOWN_ERROR; } else { if (m_previewWindow) { if (m_previewRunning == true && m_previewStartDeferred == false) { ALOGE("ERR(%s):preview is running, cannot change size and format!", __func__); ret = INVALID_OPERATION; } ALOGV("DEBUG(%s):m_previewWindow (%p) set_buffers_geometry", __func__, m_previewWindow); ALOGV("DEBUG(%s):m_previewWindow->set_buffers_geometry (%p)", __func__, m_previewWindow->set_buffers_geometry); m_previewWindow->set_buffers_geometry(m_previewWindow, newPreviewW, newPreviewH, newPreviewFormat); ALOGV("DEBUG(%s):DONE m_previewWindow (%p) set_buffers_geometry", __func__, m_previewWindow); } m_params.setPreviewSize(newPreviewW, newPreviewH); m_params.setPreviewFormat(strNewPreviewFormat); } } else { ALOGV("DEBUG(%s):preview size and format has not changed", __func__); } } else { ALOGE("ERR(%s):Invalid preview size(%dx%d)", __func__, newPreviewW, newPreviewH); ret = INVALID_OPERATION; } int newPictureW = 0; int newPictureH = 0; params.getPictureSize(&newPictureW, &newPictureH); ALOGV("DEBUG(%s):newPictureW x newPictureH = %dx%d", __func__, newPictureW, newPictureH); if (0 < newPictureW && 0 < newPictureH) { int orgPictureW, orgPictureH = 0; m_secCamera->getPictureSize(&orgPictureW, &orgPictureH); if (m_secCamera->setPictureSize(newPictureW, newPictureH) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setPictureSize(width(%d), height(%d))", __func__, newPictureW, newPictureH); ret = UNKNOWN_ERROR; } else { int tempW, tempH = 0; m_secCamera->getPictureSize(&tempW, &tempH); if (tempW != orgPictureW || tempH != orgPictureH) { if (m_pictureRunning == true) { if (m_stopPictureInternal() == false) ALOGE("ERR(%s):m_stopPictureInternal() fail", __func__); if (m_startPictureInternal() == false) ALOGE("ERR(%s):m_startPictureInternal() fail", __func__); } } m_orgPictureRect.w = newPictureW; m_orgPictureRect.h = newPictureH; m_params.setPictureSize(newPictureW, newPictureH); } } // picture format const char *newPictureFormat = params.getPictureFormat(); ALOGV("DEBUG(%s):newPictureFormat %s", __func__, newPictureFormat); if (newPictureFormat != NULL) { int value = 0; if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_RGB565)) value = V4L2_PIX_FMT_RGB565; else if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_RGBA8888)) value = V4L2_PIX_FMT_RGB32; else if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) value = V4L2_PIX_FMT_NV21; else if (!strcmp(newPictureFormat, "yuv420sp_custom")) value = V4L2_PIX_FMT_NV12T; else if (!strcmp(newPictureFormat, "yuv420p")) value = V4L2_PIX_FMT_YUV420; else if (!strcmp(newPictureFormat, "yuv422i")) value = V4L2_PIX_FMT_YUYV; else if (!strcmp(newPictureFormat, "uyv422i_custom")) //Zero copy UYVY format value = V4L2_PIX_FMT_UYVY; else if (!strcmp(newPictureFormat, "uyv422i")) //Non-zero copy UYVY format value = V4L2_PIX_FMT_UYVY; else if (!strcmp(newPictureFormat, CameraParameters::PIXEL_FORMAT_JPEG)) value = V4L2_PIX_FMT_YUYV; else if (!strcmp(newPictureFormat, "yuv422p")) value = V4L2_PIX_FMT_YUV422P; else value = V4L2_PIX_FMT_NV21; //for 3rd party if (value != m_secCamera->getPictureFormat()) { if (m_secCamera->setPictureFormat(value) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setPictureFormat(format(%d))", __func__, value); ret = UNKNOWN_ERROR; } else { m_orgPictureRect.colorFormat = value; m_params.setPictureFormat(newPictureFormat); } } } // JPEG image quality int newJpegQuality = params.getInt(CameraParameters::KEY_JPEG_QUALITY); ALOGV("DEBUG(%s):newJpegQuality %d", __func__, newJpegQuality); // we ignore bad values if (newJpegQuality >=1 && newJpegQuality <= 100) { if (m_secCamera->setJpegQuality(newJpegQuality) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setJpegQuality(quality(%d))", __func__, newJpegQuality); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_JPEG_QUALITY, newJpegQuality); } } // JPEG thumbnail size int newJpegThumbnailW = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); int newJpegThumbnailH = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); if (0 <= newJpegThumbnailW && 0 <= newJpegThumbnailH) { if (m_secCamera->setJpegThumbnailSize(newJpegThumbnailW, newJpegThumbnailH) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setJpegThumbnailSize(width(%d), height(%d))", __func__, newJpegThumbnailW, newJpegThumbnailH); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, newJpegThumbnailW); m_params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, newJpegThumbnailH); } } // JPEG thumbnail quality int newJpegThumbnailQuality = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); ALOGV("DEBUG(%s):newJpegThumbnailQuality %d", __func__, newJpegThumbnailQuality); // we ignore bad values if (newJpegThumbnailQuality >=1 && newJpegThumbnailQuality <= 100) { if (m_secCamera->setJpegThumbnailQuality(newJpegThumbnailQuality) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setJpegThumbnailQuality(quality(%d))", __func__, newJpegThumbnailQuality); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, newJpegThumbnailQuality); } } // Video size int newVideoW = 0; int newVideoH = 0; params.getVideoSize(&newVideoW, &newVideoH); ALOGV("DEBUG(%s):newVideoW (%d) newVideoH (%d)", __func__, newVideoW, newVideoH); if (0 < newVideoW && 0 < newVideoH && m_videoStart == false) { m_orgVideoRect.w = newVideoW; m_orgVideoRect.h = newVideoH; if (m_secCamera->setVideoSize(newVideoW, newVideoH) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setVideoSize(width(%d), height(%d))", __func__, newVideoW, newVideoH); ret = UNKNOWN_ERROR; } m_params.setVideoSize(newVideoW, newVideoH); } // video stablization const char *newVideoStabilization = params.get(CameraParameters::KEY_VIDEO_STABILIZATION); bool currVideoStabilization = m_secCamera->getVideoStabilization(); ALOGV("DEBUG(%s):newVideoStabilization %s", __func__, newVideoStabilization); if (newVideoStabilization != NULL) { bool toggle = false; if (!strcmp(newVideoStabilization, "true")) toggle = true; if ( currVideoStabilization != toggle) { if (m_secCamera->setVideoStabilization(toggle) == false) { ALOGE("ERR(%s):setVideoStabilization() fail", __func__); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_VIDEO_STABILIZATION, newVideoStabilization); } } } // 3dnr const char *new3dnr = params.get("3dnr"); ALOGV("DEBUG(%s):new3drn %s", __func__, new3dnr); if (new3dnr != NULL) { bool toggle = false; if (!strcmp(new3dnr, "true")) toggle = true; if (m_secCamera->set3DNR(toggle) == false) { ALOGE("ERR(%s):set3DNR() fail", __func__); ret = UNKNOWN_ERROR; } else { m_params.set("3dnr", new3dnr); } } // odc const char *newOdc = params.get("odc"); ALOGV("DEBUG(%s):newOdc %s", __func__, new3dnr); if (newOdc != NULL) { bool toggle = false; if (!strcmp(newOdc, "true")) toggle = true; if (m_secCamera->setODC(toggle) == false) { ALOGE("ERR(%s):setODC() fail", __func__); ret = UNKNOWN_ERROR; } else { m_params.set("odc", newOdc); } } // frame rate int newFrameRate = params.getPreviewFrameRate(); ALOGV("DEBUG(%s):newFrameRate %d", __func__, newFrameRate); // ignore any fps request, we're determine fps automatically based // on scene mode. don't return an error because it causes CTS failure. if (newFrameRate != m_params.getPreviewFrameRate()) { if (m_secCamera->setPreviewFrameRate(newFrameRate) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setPreviewFrameRate(%d)", __func__, newFrameRate); ret = UNKNOWN_ERROR; } else { m_params.setPreviewFrameRate(newFrameRate); } } // zoom int newZoom = params.getInt(CameraParameters::KEY_ZOOM); ALOGV("DEBUG(%s):newZoom %d", __func__, newZoom); if (0 <= newZoom) { if (m_secCamera->setZoom(newZoom) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setZoom(newZoom(%d))", __func__, newZoom); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_ZOOM, newZoom); } } // rotation int newRotation = params.getInt(CameraParameters::KEY_ROTATION); ALOGV("DEBUG(%s):newRotation %d", __func__, newRotation); if (0 <= newRotation) { ALOGV("DEBUG(%s):set orientation:%d", __func__, newRotation); if (m_secCamera->setRotation(newRotation) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setRotation(%d)", __func__, newRotation); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_ROTATION, newRotation); } } // auto exposure lock const char *newAutoExposureLock = params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK); if (newAutoExposureLock != NULL) { bool toggle = false; if (!strcmp(newAutoExposureLock, "true")) toggle = true; if (m_secCamera->setAutoExposureLock(toggle) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setAutoExposureLock()", __func__); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, newAutoExposureLock); } } // exposure int minExposureCompensation = params.getInt(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION); int maxExposureCompensation = params.getInt(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION); int newExposureCompensation = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); ALOGV("DEBUG(%s):newExposureCompensation %d", __func__, newExposureCompensation); if ((minExposureCompensation <= newExposureCompensation) && (newExposureCompensation <= maxExposureCompensation)) { if (m_secCamera->setExposureCompensation(newExposureCompensation) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setExposureCompensation(exposure(%d))", __func__, newExposureCompensation); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, newExposureCompensation); } } // auto white balance lock const char *newAutoWhitebalanceLock = params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK); if (newAutoWhitebalanceLock != NULL) { bool toggle = false; if (!strcmp(newAutoWhitebalanceLock, "true")) toggle = true; if (m_secCamera->setAutoWhiteBalanceLock(toggle) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setAutoWhiteBalanceLock()", __func__); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, newAutoWhitebalanceLock); } } // white balance const char *newWhiteBalance = params.get(CameraParameters::KEY_WHITE_BALANCE); ALOGV("DEBUG(%s):newWhiteBalance %s", __func__, newWhiteBalance); if (newWhiteBalance != NULL) { int value = -1; if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_AUTO)) value = ExynosCamera::WHITE_BALANCE_AUTO; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_INCANDESCENT)) value = ExynosCamera::WHITE_BALANCE_INCANDESCENT; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_FLUORESCENT)) value = ExynosCamera::WHITE_BALANCE_FLUORESCENT; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT)) value = ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_DAYLIGHT)) value = ExynosCamera::WHITE_BALANCE_DAYLIGHT; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT)) value = ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_TWILIGHT)) value = ExynosCamera::WHITE_BALANCE_TWILIGHT; else if (!strcmp(newWhiteBalance, CameraParameters::WHITE_BALANCE_SHADE)) value = ExynosCamera::WHITE_BALANCE_SHADE; else { ALOGE("ERR(%s):Invalid white balance(%s)", __func__, newWhiteBalance); //twilight, shade, warm_flourescent ret = UNKNOWN_ERROR; } if (0 <= value) { if (m_secCamera->setWhiteBalance(value) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setWhiteBalance(white(%d))", __func__, value); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_WHITE_BALANCE, newWhiteBalance); } } } // Metering // This is the additional API(not Google API). // But, This is set berfore the below KEY_METERING_AREAS. const char *strNewMetering = params.get("metering"); ALOGV("DEBUG(%s):strNewMetering %s", __func__, strNewMetering); if (strNewMetering != NULL) { int newMetering = -1; if (!strcmp(strNewMetering, "average")) newMetering = ExynosCamera::METERING_MODE_AVERAGE; else if (!strcmp(strNewMetering, "center")) newMetering = ExynosCamera::METERING_MODE_CENTER; else if (!strcmp(strNewMetering, "matrix")) newMetering = ExynosCamera::METERING_MODE_MATRIX; else if (!strcmp(strNewMetering, "spot")) newMetering = ExynosCamera::METERING_MODE_SPOT; else { ALOGE("ERR(%s):Invalid metering newMetering(%s)", __func__, strNewMetering); ret = UNKNOWN_ERROR; } if (0 <= newMetering) { if (m_secCamera->setMeteringMode(newMetering) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setMeteringMode(%d)", __func__, newMetering); ret = UNKNOWN_ERROR; } else { m_params.set("metering", strNewMetering); } } } // metering areas const char *newMeteringAreas = params.get(CameraParameters::KEY_METERING_AREAS); int maxNumMeteringAreas = m_secCamera->getMaxNumMeteringAreas(); if (newMeteringAreas != NULL && maxNumMeteringAreas != 0) { // ex : (-10,-10,0,0,300),(0,0,10,10,700) ExynosRect2 *rect2s = new ExynosRect2[maxNumMeteringAreas]; int *weights = new int[maxNumMeteringAreas]; int validMeteringAreas = m_bracketsStr2Ints((char *)newMeteringAreas, maxNumMeteringAreas, rect2s, weights); if (0 < validMeteringAreas) { for (int i = 0; i < validMeteringAreas; i++) { rect2s[i].x1 = m_calibratePosition(2000, newPreviewW, rect2s[i].x1 + 1000); rect2s[i].y1 = m_calibratePosition(2000, newPreviewH, rect2s[i].y1 + 1000); rect2s[i].x2 = m_calibratePosition(2000, newPreviewW, rect2s[i].x2 + 1000); rect2s[i].y2 = m_calibratePosition(2000, newPreviewH, rect2s[i].y2 + 1000); } if (m_secCamera->setMeteringAreas(validMeteringAreas, rect2s, weights) == false) { ALOGE("ERR(%s):setMeteringAreas(%s) fail", __func__, newMeteringAreas); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_METERING_AREAS, newMeteringAreas); } } delete [] rect2s; delete [] weights; } // anti banding const char *newAntibanding = params.get(CameraParameters::KEY_ANTIBANDING); ALOGV("DEBUG(%s):newAntibanding %s", __func__, newAntibanding); if (newAntibanding != NULL) { int value = -1; if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_AUTO)) value = ExynosCamera::ANTIBANDING_AUTO; else if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_50HZ)) value = ExynosCamera::ANTIBANDING_50HZ; else if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_60HZ)) value = ExynosCamera::ANTIBANDING_60HZ; else if (!strcmp(newAntibanding, CameraParameters::ANTIBANDING_OFF)) value = ExynosCamera::ANTIBANDING_OFF; else { ALOGE("ERR(%s):Invalid antibanding value(%s)", __func__, newAntibanding); ret = UNKNOWN_ERROR; } if (0 <= value) { if (m_secCamera->setAntibanding(value) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setAntibanding(%d)", __func__, value); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_ANTIBANDING, newAntibanding); } } } // scene mode const char *strNewSceneMode = params.get(CameraParameters::KEY_SCENE_MODE); const char *strCurSceneMode = m_params.get(CameraParameters::KEY_SCENE_MODE); // fps range int newMinFps = 0; int newMaxFps = 0; int curMinFps = 0; int curMaxFps = 0; params.getPreviewFpsRange(&newMinFps, &newMaxFps); m_params.getPreviewFpsRange(&curMinFps, &curMaxFps); /* our fps range is determined by the sensor, reject any request * that isn't exactly what we're already at. * but the check is performed when requesting only changing fps range */ if (strNewSceneMode && strCurSceneMode) { if (!strcmp(strNewSceneMode, strCurSceneMode)) { if ((newMinFps != curMinFps) || (newMaxFps != curMaxFps)) { ALOGW("%s : requested newMinFps = %d, newMaxFps = %d not allowed", __func__, newMinFps, newMaxFps); ALOGE("%s : curMinFps = %d, curMaxFps = %d", __func__, curMinFps, curMaxFps); ret = UNKNOWN_ERROR; } } } else { /* Check basic validation if scene mode is different */ if ((newMaxFps < newMinFps) || (newMinFps < 0) || (newMaxFps < 0)) ret = UNKNOWN_ERROR; } if (strNewSceneMode != NULL) { int newSceneMode = -1; const char *strNewFlashMode = params.get(CameraParameters::KEY_FLASH_MODE); const char *strNewFocusMode = params.get(CameraParameters::KEY_FOCUS_MODE); // fps range is (15000,30000) by default. m_params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(15000,30000)"); m_params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "15000,30000"); if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_AUTO)) { newSceneMode = ExynosCamera::SCENE_MODE_AUTO; } else { // defaults for non-auto scene modes if (m_secCamera->getSupportedFocusModes() != 0) strNewFocusMode = CameraParameters::FOCUS_MODE_AUTO; strNewFlashMode = CameraParameters::FLASH_MODE_OFF; if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_ACTION)) { newSceneMode = ExynosCamera::SCENE_MODE_ACTION; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_PORTRAIT)) { newSceneMode = ExynosCamera::SCENE_MODE_PORTRAIT; strNewFlashMode = CameraParameters::FLASH_MODE_AUTO; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_LANDSCAPE)) { newSceneMode = ExynosCamera::SCENE_MODE_LANDSCAPE; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_NIGHT)) { newSceneMode = ExynosCamera::SCENE_MODE_NIGHT; m_params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(4000,30000)"); m_params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "4000,30000"); } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_NIGHT_PORTRAIT)) { newSceneMode = ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_THEATRE)) { newSceneMode = ExynosCamera::SCENE_MODE_THEATRE; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_BEACH)) { newSceneMode = ExynosCamera::SCENE_MODE_BEACH; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_SNOW)) { newSceneMode = ExynosCamera::SCENE_MODE_SNOW; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_SUNSET)) { newSceneMode = ExynosCamera::SCENE_MODE_SUNSET; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_STEADYPHOTO)) { newSceneMode = ExynosCamera::SCENE_MODE_STEADYPHOTO; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_FIREWORKS)) { newSceneMode = ExynosCamera::SCENE_MODE_FIREWORKS; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_SPORTS)) { newSceneMode = ExynosCamera::SCENE_MODE_SPORTS; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_PARTY)) { newSceneMode = ExynosCamera::SCENE_MODE_PARTY; strNewFlashMode = CameraParameters::FLASH_MODE_AUTO; } else if (!strcmp(strNewSceneMode, CameraParameters::SCENE_MODE_CANDLELIGHT)) { newSceneMode = ExynosCamera::SCENE_MODE_CANDLELIGHT; } else { ALOGE("ERR(%s):unmatched scene_mode(%s)", __func__, strNewSceneMode); //action, night-portrait, theatre, steadyphoto ret = UNKNOWN_ERROR; } } // focus mode if (strNewFocusMode != NULL) { int newFocusMode = -1; if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_AUTO)) { newFocusMode = ExynosCamera::FOCUS_MODE_AUTO; m_params.set(CameraParameters::KEY_FOCUS_DISTANCES, BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR); } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_INFINITY)) { newFocusMode = ExynosCamera::FOCUS_MODE_INFINITY; m_params.set(CameraParameters::KEY_FOCUS_DISTANCES, BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR); } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_MACRO)) { newFocusMode = ExynosCamera::FOCUS_MODE_MACRO; m_params.set(CameraParameters::KEY_FOCUS_DISTANCES, BACK_CAMERA_MACRO_FOCUS_DISTANCES_STR); } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_FIXED)) { newFocusMode = ExynosCamera::FOCUS_MODE_FIXED; } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_EDOF)) { newFocusMode = ExynosCamera::FOCUS_MODE_EDOF; } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO)) { newFocusMode = ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO; } else if (!strcmp(strNewFocusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE)) { newFocusMode = ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE; } else { ALOGE("ERR(%s):unmatched focus_mode(%s)", __func__, strNewFocusMode); ret = UNKNOWN_ERROR; } if (0 <= newFocusMode) { if (m_secCamera->setFocusMode(newFocusMode) == false) { ALOGE("ERR(%s):m_secCamera->setFocusMode(%d) fail", __func__, newFocusMode); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_FOCUS_MODE, strNewFocusMode); } } } // flash mode if (strNewFlashMode != NULL) { int newFlashMode = -1; if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_OFF)) newFlashMode = ExynosCamera::FLASH_MODE_OFF; else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_AUTO)) newFlashMode = ExynosCamera::FLASH_MODE_AUTO; else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_ON)) newFlashMode = ExynosCamera::FLASH_MODE_ON; else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_RED_EYE)) newFlashMode = ExynosCamera::FLASH_MODE_RED_EYE; else if (!strcmp(strNewFlashMode, CameraParameters::FLASH_MODE_TORCH)) newFlashMode = ExynosCamera::FLASH_MODE_TORCH; else { ALOGE("ERR(%s):unmatched flash_mode(%s)", __func__, strNewFlashMode); //red-eye ret = UNKNOWN_ERROR; } if (0 <= newFlashMode) { if (m_secCamera->setFlashMode(newFlashMode) == false) { ALOGE("ERR(%s):m_secCamera->setFlashMode(%d) fail", __func__, newFlashMode); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_FLASH_MODE, strNewFlashMode); } } } // scene mode if (0 <= newSceneMode) { if (m_secCamera->setSceneMode(newSceneMode) == false) { ALOGE("ERR(%s):m_secCamera->setSceneMode(%d) fail", __func__, newSceneMode); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_SCENE_MODE, strNewSceneMode); } } } // focus areas const char *newFocusAreas = params.get(CameraParameters::KEY_FOCUS_AREAS); int maxNumFocusAreas = m_secCamera->getMaxNumFocusAreas(); if (newFocusAreas != NULL && maxNumFocusAreas != 0) { int curFocusMode = m_secCamera->getFocusMode(); // In CameraParameters.h // Focus area only has effect if the cur focus mode is FOCUS_MODE_AUTO, // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or // FOCUS_MODE_CONTINUOUS_PICTURE. if ( curFocusMode & ExynosCamera::FOCUS_MODE_AUTO || curFocusMode & ExynosCamera::FOCUS_MODE_MACRO || curFocusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO || curFocusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE) { // ex : (-10,-10,0,0,300),(0,0,10,10,700) ExynosRect2 *rect2s = new ExynosRect2[maxNumFocusAreas]; int *weights = new int[maxNumFocusAreas]; int validFocusedAreas = m_bracketsStr2Ints((char *)newFocusAreas, maxNumFocusAreas, rect2s, weights); if (0 < validFocusedAreas) { // CameraParameters.h // A special case of single focus area (0,0,0,0,0) means driver to decide // the focus area. For example, the driver may use more signals to decide // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they // want the driver to decide focus areas. if ( validFocusedAreas == 1 && rect2s[0].x1 == 0 && rect2s[0].y1 == 0 && rect2s[0].x2 == 0 && rect2s[0].y2 == 0) { rect2s[0].x1 = 0; rect2s[0].y1 = 0; rect2s[0].x2 = newPreviewW; rect2s[0].y2 = newPreviewH; } else { for (int i = 0; i < validFocusedAreas; i++) { rect2s[i].x1 = (rect2s[i].x1 + 1000) * 1023 / 2000; rect2s[i].y1 = (rect2s[i].y1 + 1000) * 1023 / 2000; rect2s[i].x2 = (rect2s[i].x2 + 1000) * 1023 / 2000; rect2s[i].y2 = (rect2s[i].y2 + 1000) * 1023 / 2000; } if (m_secCamera->setFocusAreas(validFocusedAreas, rect2s, weights) == false) { ALOGE("ERR(%s):setFocusAreas(%s) fail", __func__, newFocusAreas); ret = UNKNOWN_ERROR; } else { m_params.set(CameraParameters::KEY_FOCUS_AREAS, newFocusAreas); } } } delete [] rect2s; delete [] weights; } } // image effect const char *strNewEffect = params.get(CameraParameters::KEY_EFFECT); if (strNewEffect != NULL) { int newEffect = -1; if (!strcmp(strNewEffect, CameraParameters::EFFECT_NONE)) { newEffect = ExynosCamera::EFFECT_NONE; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_MONO)) { newEffect = ExynosCamera::EFFECT_MONO; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_NEGATIVE)) { newEffect = ExynosCamera::EFFECT_NEGATIVE; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_SOLARIZE)) { newEffect = ExynosCamera::EFFECT_SOLARIZE; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_SEPIA)) { newEffect = ExynosCamera::EFFECT_SEPIA; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_POSTERIZE)) { newEffect = ExynosCamera::EFFECT_POSTERIZE; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_WHITEBOARD)) { newEffect = ExynosCamera::EFFECT_WHITEBOARD; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_BLACKBOARD)) { newEffect = ExynosCamera::EFFECT_BLACKBOARD; } else if (!strcmp(strNewEffect, CameraParameters::EFFECT_AQUA)) { newEffect = ExynosCamera::EFFECT_AQUA; } else { ALOGE("ERR(%s):Invalid effect(%s)", __func__, strNewEffect); ret = UNKNOWN_ERROR; } if (0 <= newEffect) { if (m_secCamera->setColorEffect(newEffect) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setColorEffect(effect(%d))", __func__, newEffect); ret = UNKNOWN_ERROR; } else { const char *oldStrEffect = m_params.get(CameraParameters::KEY_EFFECT); if (oldStrEffect) { if (strcmp(oldStrEffect, strNewEffect)) { m_setSkipFrame(EFFECT_SKIP_FRAME); } } m_params.set(CameraParameters::KEY_EFFECT, strNewEffect); } } } // gps altitude const char *strNewGpsAltitude = params.get(CameraParameters::KEY_GPS_ALTITUDE); if (m_secCamera->setGpsAltitude(strNewGpsAltitude) == false) { ALOGE("ERR(%s):m_secCamera->setGpsAltitude(%s) fail", __func__, strNewGpsAltitude); ret = UNKNOWN_ERROR; } else { if (strNewGpsAltitude) m_params.set(CameraParameters::KEY_GPS_ALTITUDE, strNewGpsAltitude); else m_params.remove(CameraParameters::KEY_GPS_ALTITUDE); } // gps latitude const char *strNewGpsLatitude = params.get(CameraParameters::KEY_GPS_LATITUDE); if (m_secCamera->setGpsLatitude(strNewGpsLatitude) == false) { ALOGE("ERR(%s):m_secCamera->setGpsLatitude(%s) fail", __func__, strNewGpsLatitude); ret = UNKNOWN_ERROR; } else { if (strNewGpsLatitude) m_params.set(CameraParameters::KEY_GPS_LATITUDE, strNewGpsLatitude); else m_params.remove(CameraParameters::KEY_GPS_LATITUDE); } // gps longitude const char *strNewGpsLongtitude = params.get(CameraParameters::KEY_GPS_LONGITUDE); if (m_secCamera->setGpsLongitude(strNewGpsLongtitude) == false) { ALOGE("ERR(%s):m_secCamera->setGpsLongitude(%s) fail", __func__, strNewGpsLongtitude); ret = UNKNOWN_ERROR; } else { if (strNewGpsLongtitude) m_params.set(CameraParameters::KEY_GPS_LONGITUDE, strNewGpsLongtitude); else m_params.remove(CameraParameters::KEY_GPS_LONGITUDE); } // gps processing method const char *strNewGpsProcessingMethod = params.get(CameraParameters::KEY_GPS_PROCESSING_METHOD); if (m_secCamera->setGpsProcessingMethod(strNewGpsProcessingMethod) == false) { ALOGE("ERR(%s):m_secCamera->setGpsProcessingMethod(%s) fail", __func__, strNewGpsProcessingMethod); ret = UNKNOWN_ERROR; } else { if (strNewGpsProcessingMethod) m_params.set(CameraParameters::KEY_GPS_PROCESSING_METHOD, strNewGpsProcessingMethod); else m_params.remove(CameraParameters::KEY_GPS_PROCESSING_METHOD); } // gps timestamp const char *strNewGpsTimestamp = params.get(CameraParameters::KEY_GPS_TIMESTAMP); if (m_secCamera->setGpsTimeStamp(strNewGpsTimestamp) == false) { ALOGE("ERR(%s):m_secCamera->setGpsTimeStamp(%s) fail", __func__, strNewGpsTimestamp); ret = UNKNOWN_ERROR; } else { if (strNewGpsTimestamp) m_params.set(CameraParameters::KEY_GPS_TIMESTAMP, strNewGpsTimestamp); else m_params.remove(CameraParameters::KEY_GPS_TIMESTAMP); } /////////////////////////////////////////////////// // Additional API. /////////////////////////////////////////////////// // brightness int newBrightness = params.getInt("brightness"); int maxBrightness = params.getInt("brightness-max"); int minBrightness = params.getInt("brightness-min"); ALOGV("DEBUG(%s):newBrightness %d", __func__, newBrightness); if ((minBrightness <= newBrightness) && (newBrightness <= maxBrightness)) { if (m_secCamera->setBrightness(newBrightness) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setBrightness(%d)", __func__, newBrightness); ret = UNKNOWN_ERROR; } else { m_params.set("brightness", newBrightness); } } // saturation int newSaturation = params.getInt("saturation"); int maxSaturation = params.getInt("saturation-max"); int minSaturation = params.getInt("saturation-min"); ALOGV("DEBUG(%s):newSaturation %d", __func__, newSaturation); if ((minSaturation <= newSaturation) && (newSaturation <= maxSaturation)) { if (m_secCamera->setSaturation(newSaturation) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setSaturation(%d)", __func__, newSaturation); ret = UNKNOWN_ERROR; } else { m_params.set("saturation", newSaturation); } } // sharpness int newSharpness = params.getInt("sharpness"); int maxSharpness = params.getInt("sharpness-max"); int minSharpness = params.getInt("sharpness-min"); ALOGV("DEBUG(%s):newSharpness %d", __func__, newSharpness); if ((minSharpness <= newSharpness) && (newSharpness <= maxSharpness)) { if (m_secCamera->setSharpness(newSharpness) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setSharpness(%d)", __func__, newSharpness); ret = UNKNOWN_ERROR; } else { m_params.set("sharpness", newSharpness); } } // hue int newHue = params.getInt("hue"); int maxHue = params.getInt("hue-max"); int minHue = params.getInt("hue-min"); ALOGV("DEBUG(%s):newHue %d", __func__, newHue); if ((minHue <= newHue) && (maxHue >= newHue)) { if (m_secCamera->setHue(newHue) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setHue(hue(%d))", __func__, newHue); ret = UNKNOWN_ERROR; } else { m_params.set("hue", newHue); } } // ISO const char *strNewISO = params.get("iso"); ALOGV("DEBUG(%s):strNewISO %s", __func__, strNewISO); if (strNewISO != NULL) { int newISO = -1; if (!strcmp(strNewISO, "auto")) newISO = 0; else { newISO = (int)atoi(strNewISO); if (newISO == 0) { ALOGE("ERR(%s):Invalid iso value(%s)", __func__, strNewISO); ret = UNKNOWN_ERROR; } } if (0 <= newISO) { if (m_secCamera->setISO(newISO) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setISO(iso(%d))", __func__, newISO); ret = UNKNOWN_ERROR; } else { m_params.set("iso", strNewISO); } } } //contrast const char *strNewContrast = params.get("contrast"); ALOGV("DEBUG(%s):strNewContrast %s", __func__, strNewContrast); if (strNewContrast != NULL) { int newContrast = -1; if (!strcmp(strNewContrast, "auto")) newContrast = ExynosCamera::CONTRAST_AUTO; else if (!strcmp(strNewContrast, "-2")) newContrast = ExynosCamera::CONTRAST_MINUS_2; else if (!strcmp(strNewContrast, "-1")) newContrast = ExynosCamera::CONTRAST_MINUS_1; else if (!strcmp(strNewContrast, "0")) newContrast = ExynosCamera::CONTRAST_DEFAULT; else if (!strcmp(strNewContrast, "1")) newContrast = ExynosCamera::CONTRAST_PLUS_1; else if (!strcmp(strNewContrast, "2")) newContrast = ExynosCamera::CONTRAST_PLUS_2; else { ALOGE("ERR(%s):Invalid contrast value(%s)", __func__, strNewContrast); ret = UNKNOWN_ERROR; } if (0 <= newContrast) { if (m_secCamera->setContrast(newContrast) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setContrast(contrast(%d))", __func__, newContrast); ret = UNKNOWN_ERROR; } else { m_params.set("contrast", strNewContrast); } } } //WDR int newWdr = params.getInt("wdr"); ALOGV("DEBUG(%s):newWdr %d", __func__, newWdr); if (0 <= newWdr) { if (m_secCamera->setWDR(newWdr) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setWDR(%d)", __func__, newWdr); ret = UNKNOWN_ERROR; } } //anti shake int newAntiShake = m_internalParams.getInt("anti-shake"); ALOGV("DEBUG(%s):newAntiShake %d", __func__, newAntiShake); if (0 <= newAntiShake) { bool toggle = false; if (newAntiShake == 1) toggle = true; if (m_secCamera->setAntiShake(toggle) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setAntiShake(%d)", __func__, newAntiShake); ret = UNKNOWN_ERROR; } } //gamma const char *strNewGamma = m_internalParams.get("video_recording_gamma"); ALOGV("DEBUG(%s):strNewGamma %s", __func__, strNewGamma); if (strNewGamma != NULL) { int newGamma = -1; if (!strcmp(strNewGamma, "off")) newGamma = 0; else if (!strcmp(strNewGamma, "on")) newGamma = 1; else { ALOGE("ERR(%s):unmatched gamma(%s)", __func__, strNewGamma); ret = UNKNOWN_ERROR; } if (0 <= newGamma) { bool toggle = false; if (newGamma == 1) toggle = true; if (m_secCamera->setGamma(toggle) == false) { ALOGE("ERR(%s):m_secCamera->setGamma(%s) fail", __func__, strNewGamma); ret = UNKNOWN_ERROR; } } } //slow ae const char *strNewSlowAe = m_internalParams.get("slow_ae"); ALOGV("DEBUG(%s):strNewSlowAe %s", __func__, strNewSlowAe); if (strNewSlowAe != NULL) { int newSlowAe = -1; if (!strcmp(strNewSlowAe, "off")) newSlowAe = 0; else if (!strcmp(strNewSlowAe, "on")) newSlowAe = 1; else { ALOGE("ERR(%s):unmatched slow_ae(%s)", __func__, strNewSlowAe); ret = UNKNOWN_ERROR; } if (0 <= newSlowAe) { bool toggle = false; if (newSlowAe == 1) toggle = true; if (m_secCamera->setSlowAE(newSlowAe) == false) { ALOGE("ERR(%s):m_secCamera->setSlowAE(%d) fail", __func__, newSlowAe); ret = UNKNOWN_ERROR; } } } // Shot mode int newShotMode = m_internalParams.getInt("shot_mode"); ALOGV("DEBUG(%s):newShotMode %d", __func__, newShotMode); if (0 <= newShotMode) { if (m_secCamera->setShotMode(newShotMode) == false) { ALOGE("ERR(%s):Fail on m_secCamera->setShotMode(%d)", __func__, newShotMode); ret = UNKNOWN_ERROR; } } else { newShotMode=0; } ALOGV("DEBUG(%s):return ret = %d", __func__, ret); return ret; } CameraParameters ExynosCameraHWInterface::getParameters() const { ALOGV("DEBUG(%s):", __func__); return m_params; } status_t ExynosCameraHWInterface::sendCommand(int32_t command, int32_t arg1, int32_t arg2) { switch (command) { case CAMERA_CMD_START_FACE_DETECTION: case CAMERA_CMD_STOP_FACE_DETECTION: if (m_secCamera->getMaxNumDetectedFaces() == 0) { ALOGE("ERR(%s):getMaxNumDetectedFaces == 0", __func__); return BAD_VALUE; } if (arg1 == CAMERA_FACE_DETECTION_SW) { ALOGE("ERR(%s):only support HW face dectection", __func__); return BAD_VALUE; } if (command == CAMERA_CMD_START_FACE_DETECTION) { if ( m_secCamera->flagStartFaceDetection() == false && m_secCamera->startFaceDetection() == false) { ALOGE("ERR(%s):startFaceDetection() fail", __func__); return BAD_VALUE; } } else { // if (command == CAMERA_CMD_STOP_FACE_DETECTION) if ( m_secCamera->flagStartFaceDetection() == true && m_secCamera->stopFaceDetection() == false) { ALOGE("ERR(%s):stopFaceDetection() fail", __func__); return BAD_VALUE; } } break; default: ALOGE("ERR(%s):unexpectect command(%d) fail", __func__, command); return BAD_VALUE; break; } return NO_ERROR; } void ExynosCameraHWInterface::release() { ALOGV("DEBUG(%s):", __func__); /* shut down any threads we have that might be running. do it here * instead of the destructor. we're guaranteed to be on another thread * than the ones below. if we used the destructor, since the threads * have a reference to this object, we could wind up trying to wait * for ourself to exit, which is a deadlock. */ if (m_videoThread != NULL) { m_videoThread->requestExit(); m_exitVideoThread = true; m_videoRunning = true; // let it run so it can exit m_videoCondition.signal(); m_videoThread->requestExitAndWait(); m_videoThread.clear(); } if (m_previewThread != NULL) { /* this thread is normally already in it's threadLoop but blocked * on the condition variable or running. signal it so it wakes * up and can exit. */ m_previewThread->requestExit(); m_exitPreviewThread = true; m_previewRunning = true; // let it run so it can exit m_previewCondition.signal(); m_previewThread->requestExitAndWait(); m_previewThread.clear(); } if (m_autoFocusThread != NULL) { /* this thread is normally already in it's threadLoop but blocked * on the condition variable. signal it so it wakes up and can exit. */ m_focusLock.lock(); m_autoFocusThread->requestExit(); m_exitAutoFocusThread = true; m_focusCondition.signal(); m_focusLock.unlock(); m_autoFocusThread->requestExitAndWait(); m_autoFocusThread.clear(); } if (m_pictureThread != NULL) { m_pictureThread->requestExitAndWait(); m_pictureThread.clear(); } for (int i = 0; i < NUM_OF_VIDEO_BUF; i++) { if (m_videoHeap[i]) { m_videoHeap[i]->release(m_videoHeap[i]); m_videoHeap[i] = 0; } if (m_resizedVideoHeap[i]) { m_resizedVideoHeap[i]->release(m_resizedVideoHeap[i]); m_resizedVideoHeap[i] = 0; } } for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { if (m_previewHeap[i]) { m_previewHeap[i]->release(m_previewHeap[i]); m_previewHeap[i] = 0; } } if (m_pictureRunning == true) { if (m_stopPictureInternal() == false) ALOGE("ERR(%s):m_stopPictureInternal() fail", __func__); } if (m_exynosVideoCSC) csc_deinit(m_exynosVideoCSC); m_exynosVideoCSC = NULL; if (m_exynosPictureCSC) csc_deinit(m_exynosPictureCSC); m_exynosPictureCSC = NULL; if (m_exynosPreviewCSC) csc_deinit(m_exynosPreviewCSC); m_exynosPreviewCSC = NULL; /* close after all the heaps are cleared since those * could have dup'd our file descriptor. */ if (m_secCamera->flagCreate() == true) m_secCamera->destroy(); } status_t ExynosCameraHWInterface::dump(int fd) const { const size_t SIZE = 256; char buffer[SIZE]; String8 result; const Vector<String16> args; if (m_secCamera != 0) { m_params.dump(fd, args); m_internalParams.dump(fd, args); snprintf(buffer, 255, " preview running(%s)\n", m_previewRunning?"true": "false"); result.append(buffer); } else { result.append("No camera client yet.\n"); } write(fd, result.string(), result.size()); return NO_ERROR; } int ExynosCameraHWInterface::getCameraId() const { return m_secCamera->getCameraId(); } void ExynosCameraHWInterface::m_initDefaultParameters(int cameraId) { if (m_secCamera == NULL) { ALOGE("ERR(%s):m_secCamera object is NULL", __func__); return; } CameraParameters p; CameraParameters ip; String8 parameterString; char * cameraName; cameraName = m_secCamera->getCameraName(); if (cameraName == NULL) ALOGE("ERR(%s):getCameraName() fail", __func__); /* if (cameraId == ExynosCamera::CAMERA_ID_BACK) { p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "3264x2448,2576x1948,1920x1080,1280x720,800x480,720x480,640x480,320x240,528x432,176x144"); p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "3264x2448,1920x1080,1280x720,800x480,720x480,640x480"); p.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, "1920x1080,1280x720,640x480,176x144"); } else { p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "1392x1392,1280x720,640x480,352x288,320x240,176x144"); p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "1392x1392,1280x960,640x480"); p.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, "1280x720,640x480,176x144"); } */ char strBuf[256]; String8 listString; // preview int previewMaxW = 0; int previewMaxH = 0; m_secCamera->getSupportedPreviewSizes(&previewMaxW, &previewMaxH); listString.setTo(""); if (m_getResolutionList(listString, strBuf, previewMaxW, previewMaxH) == false) { ALOGE("ERR(%s):m_getResolutionList() fail", __func__); previewMaxW = 640; previewMaxH = 480; listString = String8::format("%dx%d", previewMaxW, previewMaxH); } p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, listString.string()); p.setPreviewSize(previewMaxW, previewMaxH); p.getSupportedPreviewSizes(m_supportedPreviewSizes); listString.setTo(""); listString = String8::format("%s,%s", CameraParameters::PIXEL_FORMAT_YUV420SP, CameraParameters::PIXEL_FORMAT_YUV420P); p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, listString); p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420P); // video int videoMaxW = 0; int videoMaxH = 0; m_secCamera->getSupportedVideoSizes(&videoMaxW, &videoMaxH); listString.setTo(""); if (m_getResolutionList(listString, strBuf, videoMaxW, videoMaxH) == false) { ALOGE("ERR(%s):m_getResolutionList() fail", __func__); videoMaxW = 640; videoMaxH = 480; listString = String8::format("%dx%d", videoMaxW, videoMaxH); } p.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, listString.string()); p.setVideoSize(videoMaxW, videoMaxH); int preferredPreviewW = 0; int preferredPreviewH = 0; m_secCamera->getPreferredPreivewSizeForVideo(&preferredPreviewW, &preferredPreviewH); listString.setTo(""); listString = String8::format("%dx%d", preferredPreviewW, preferredPreviewH); p.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO, listString.string()); p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_YUV420SP); if (m_secCamera->isVideoSnapshotSupported() == true) p.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, "true"); else p.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, "false"); if (m_secCamera->isVideoStabilizationSupported() == true) p.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED, "true"); else p.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED, "false"); // picture int pictureMaxW = 0; int pictureMaxH = 0; m_secCamera->getSupportedPictureSizes(&pictureMaxW, &pictureMaxH); listString.setTo(""); if (m_getResolutionList(listString, strBuf, pictureMaxW, pictureMaxH) == false) { ALOGE("ERR(%s):m_getResolutionList() fail", __func__); pictureMaxW = 640; pictureMaxW = 480; listString = String8::format("%dx%d", pictureMaxW, pictureMaxH); } p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, listString.string()); p.setPictureSize(pictureMaxW, pictureMaxH); p.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, CameraParameters::PIXEL_FORMAT_JPEG); p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG); p.set(CameraParameters::KEY_JPEG_QUALITY, "100"); // maximum quality // thumbnail int thumbnailMaxW = 0; int thumbnailMaxH = 0; m_secCamera->getSupportedJpegThumbnailSizes(&thumbnailMaxW, &thumbnailMaxH); listString = String8::format("%dx%d", thumbnailMaxW, thumbnailMaxH); listString.append(",0x0"); p.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, listString.string()); p.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, thumbnailMaxW); p.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, thumbnailMaxH); p.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, "100"); // exposure p.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, m_secCamera->getMinExposureCompensation()); p.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, m_secCamera->getMaxExposureCompensation()); p.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, m_secCamera->getExposureCompensation()); p.setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, m_secCamera->getExposureCompensationStep()); if (m_secCamera->isAutoExposureLockSupported() == true) p.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, "true"); else p.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, "false"); // face detection p.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW, m_secCamera->getMaxNumDetectedFaces()); p.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW, 0); // focus mode int focusMode = m_secCamera->getSupportedFocusModes(); parameterString.setTo(""); if (focusMode & ExynosCamera::FOCUS_MODE_AUTO) { parameterString.append(CameraParameters::FOCUS_MODE_AUTO); parameterString.append(","); } if (focusMode & ExynosCamera::FOCUS_MODE_INFINITY) { parameterString.append(CameraParameters::FOCUS_MODE_INFINITY); parameterString.append(","); } if (focusMode & ExynosCamera::FOCUS_MODE_MACRO) { parameterString.append(CameraParameters::FOCUS_MODE_MACRO); parameterString.append(","); } if (focusMode & ExynosCamera::FOCUS_MODE_FIXED) { parameterString.append(CameraParameters::FOCUS_MODE_FIXED); parameterString.append(","); } if (focusMode & ExynosCamera::FOCUS_MODE_EDOF) { parameterString.append(CameraParameters::FOCUS_MODE_EDOF); parameterString.append(","); } if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO) { parameterString.append(CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO); parameterString.append(","); } if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE) parameterString.append(CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE); p.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, parameterString.string()); if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_PICTURE) p.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE); else if (focusMode & ExynosCamera::FOCUS_MODE_CONTINUOUS_VIDEO) p.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO); else if (focusMode & ExynosCamera::FOCUS_MODE_AUTO) p.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_AUTO); else p.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_FIXED); // HACK if (cameraId == ExynosCamera::CAMERA_ID_BACK) { p.set(CameraParameters::KEY_FOCUS_DISTANCES, BACK_CAMERA_AUTO_FOCUS_DISTANCES_STR); p.set(CameraParameters::FOCUS_DISTANCE_INFINITY, BACK_CAMERA_FOCUS_DISTANCE_INFINITY); } else { p.set(CameraParameters::KEY_FOCUS_DISTANCES, FRONT_CAMERA_FOCUS_DISTANCES_STR); p.set(CameraParameters::FOCUS_DISTANCE_INFINITY, FRONT_CAMERA_FOCUS_DISTANCE_INFINITY); } if (focusMode & ExynosCamera::FOCUS_MODE_TOUCH) p.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, m_secCamera->getMaxNumFocusAreas()); // flash int flashMode = m_secCamera->getSupportedFlashModes(); parameterString.setTo(""); if (flashMode & ExynosCamera::FLASH_MODE_OFF) { parameterString.append(CameraParameters::FLASH_MODE_OFF); parameterString.append(","); } if (flashMode & ExynosCamera::FLASH_MODE_AUTO) { parameterString.append(CameraParameters::FLASH_MODE_AUTO); parameterString.append(","); } if (flashMode & ExynosCamera::FLASH_MODE_ON) { parameterString.append(CameraParameters::FLASH_MODE_ON); parameterString.append(","); } if (flashMode & ExynosCamera::FLASH_MODE_RED_EYE) { parameterString.append(CameraParameters::FLASH_MODE_RED_EYE); parameterString.append(","); } if (flashMode & ExynosCamera::FLASH_MODE_TORCH) parameterString.append(CameraParameters::FLASH_MODE_TORCH); p.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, parameterString.string()); p.set(CameraParameters::KEY_FLASH_MODE, CameraParameters::FLASH_MODE_OFF); // scene mode int sceneMode = m_secCamera->getSupportedSceneModes(); parameterString.setTo(""); if (sceneMode & ExynosCamera::SCENE_MODE_AUTO) { parameterString.append(CameraParameters::SCENE_MODE_AUTO); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_ACTION) { parameterString.append(CameraParameters::SCENE_MODE_ACTION); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_PORTRAIT) { parameterString.append(CameraParameters::SCENE_MODE_PORTRAIT); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_LANDSCAPE) { parameterString.append(CameraParameters::SCENE_MODE_LANDSCAPE); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_NIGHT) { parameterString.append(CameraParameters::SCENE_MODE_NIGHT); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_NIGHT_PORTRAIT) { parameterString.append(CameraParameters::SCENE_MODE_NIGHT_PORTRAIT); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_THEATRE) { parameterString.append(CameraParameters::SCENE_MODE_THEATRE); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_BEACH) { parameterString.append(CameraParameters::SCENE_MODE_BEACH); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_SNOW) { parameterString.append(CameraParameters::SCENE_MODE_SNOW); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_SUNSET) { parameterString.append(CameraParameters::SCENE_MODE_SUNSET); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_STEADYPHOTO) { parameterString.append(CameraParameters::SCENE_MODE_STEADYPHOTO); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_FIREWORKS) { parameterString.append(CameraParameters::SCENE_MODE_FIREWORKS); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_SPORTS) { parameterString.append(CameraParameters::SCENE_MODE_SPORTS); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_PARTY) { parameterString.append(CameraParameters::SCENE_MODE_PARTY); parameterString.append(","); } if (sceneMode & ExynosCamera::SCENE_MODE_CANDLELIGHT) parameterString.append(CameraParameters::SCENE_MODE_CANDLELIGHT); p.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES, parameterString.string()); p.set(CameraParameters::KEY_SCENE_MODE, CameraParameters::SCENE_MODE_AUTO); // effect int effect = m_secCamera->getSupportedColorEffects(); parameterString.setTo(""); if (effect & ExynosCamera::EFFECT_NONE) { parameterString.append(CameraParameters::EFFECT_NONE); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_MONO) { parameterString.append(CameraParameters::EFFECT_MONO); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_NEGATIVE) { parameterString.append(CameraParameters::EFFECT_NEGATIVE); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_SOLARIZE) { parameterString.append(CameraParameters::EFFECT_SOLARIZE); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_SEPIA) { parameterString.append(CameraParameters::EFFECT_SEPIA); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_POSTERIZE) { parameterString.append(CameraParameters::EFFECT_POSTERIZE); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_WHITEBOARD) { parameterString.append(CameraParameters::EFFECT_WHITEBOARD); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_BLACKBOARD) { parameterString.append(CameraParameters::EFFECT_BLACKBOARD); parameterString.append(","); } if (effect & ExynosCamera::EFFECT_AQUA) parameterString.append(CameraParameters::EFFECT_AQUA); p.set(CameraParameters::KEY_SUPPORTED_EFFECTS, parameterString.string()); p.set(CameraParameters::KEY_EFFECT, CameraParameters::EFFECT_NONE); // white balance int whiteBalance = m_secCamera->getSupportedWhiteBalance(); parameterString.setTo(""); if (whiteBalance & ExynosCamera::WHITE_BALANCE_AUTO) { parameterString.append(CameraParameters::WHITE_BALANCE_AUTO); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_INCANDESCENT) { parameterString.append(CameraParameters::WHITE_BALANCE_INCANDESCENT); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_FLUORESCENT) { parameterString.append(CameraParameters::WHITE_BALANCE_FLUORESCENT); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_WARM_FLUORESCENT) { parameterString.append(CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_DAYLIGHT) { parameterString.append(CameraParameters::WHITE_BALANCE_DAYLIGHT); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_CLOUDY_DAYLIGHT) { parameterString.append(CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_TWILIGHT) { parameterString.append(CameraParameters::WHITE_BALANCE_TWILIGHT); parameterString.append(","); } if (whiteBalance & ExynosCamera::WHITE_BALANCE_SHADE) parameterString.append(CameraParameters::WHITE_BALANCE_SHADE); p.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, parameterString.string()); p.set(CameraParameters::KEY_WHITE_BALANCE, CameraParameters::WHITE_BALANCE_AUTO); if (m_secCamera->isAutoWhiteBalanceLockSupported() == true) p.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, "true"); else p.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, "false"); // anti banding int antiBanding = m_secCamera->getSupportedAntibanding(); parameterString.setTo(""); if (antiBanding & ExynosCamera::ANTIBANDING_AUTO) { parameterString.append(CameraParameters::ANTIBANDING_AUTO); parameterString.append(","); } if (antiBanding & ExynosCamera::ANTIBANDING_50HZ) { parameterString.append(CameraParameters::ANTIBANDING_50HZ); parameterString.append(","); } if (antiBanding & ExynosCamera::ANTIBANDING_60HZ) { parameterString.append(CameraParameters::ANTIBANDING_60HZ); parameterString.append(","); } if (antiBanding & ExynosCamera::ANTIBANDING_OFF) parameterString.append(CameraParameters::ANTIBANDING_OFF); p.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING, parameterString.string()); p.set(CameraParameters::KEY_ANTIBANDING, CameraParameters::ANTIBANDING_OFF); // rotation p.set(CameraParameters::KEY_ROTATION, 0); // view angle p.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, m_secCamera->getHorizontalViewAngle()); p.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, m_secCamera->getVerticalViewAngle()); // metering if (0 < m_secCamera->getMaxNumMeteringAreas()) p.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS, m_secCamera->getMaxNumMeteringAreas()); // zoom if (m_secCamera->isZoomSupported() == true) { int maxZoom = m_secCamera->getMaxZoom(); if (0 < maxZoom) { p.set(CameraParameters::KEY_ZOOM_SUPPORTED, "true"); if (m_secCamera->isSmoothZoomSupported() == true) p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "true"); else p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "false"); p.set(CameraParameters::KEY_MAX_ZOOM, maxZoom); p.set(CameraParameters::KEY_ZOOM, m_secCamera->getZoom()); int max_zoom_ratio = m_secCamera->getMaxZoomRatio(); listString.setTo(""); if (m_getZoomRatioList(listString, strBuf, maxZoom, 100, max_zoom_ratio) == true) p.set(CameraParameters::KEY_ZOOM_RATIOS, listString.string()); else p.set(CameraParameters::KEY_ZOOM_RATIOS, "100"); } else { p.set(CameraParameters::KEY_ZOOM_SUPPORTED, "false"); p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "false"); } } else { p.set(CameraParameters::KEY_ZOOM_SUPPORTED, "false"); p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, "false"); } // fps int minPreviewFps, maxPreviewFps; m_secCamera->getPreviewFpsRange(&minPreviewFps, &maxPreviewFps); int baseFps = ((minPreviewFps + 5) / 5) * 5; listString.setTo(""); snprintf(strBuf, 256, "%d", minPreviewFps); listString.append(strBuf); for (int i = baseFps; i <= maxPreviewFps; i += 5) { int step = (i / 5) * 5; snprintf(strBuf, 256, ",%d", step); listString.append(strBuf); } p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, listString.string()); p.setPreviewFrameRate(maxPreviewFps); int minFpsRange = minPreviewFps * 1000; // 15 -> 15000 int maxFpsRange = maxPreviewFps * 1000; // 30 -> 30000 snprintf(strBuf, 256, "(%d,%d)", minFpsRange, maxFpsRange); p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, strBuf); snprintf(strBuf, 256, "%d,%d", minFpsRange, maxFpsRange); p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, strBuf); //p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, "(15000,30000)"); //p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, "15000,30000") // focal length int num = 0; int den = 0; int precision = 0; m_secCamera->getFocalLength(&num, &den); switch (den) { default: case 1000: precision = 3; break; case 100: precision = 2; break; case 10: precision = 1; break; case 1: precision = 0; break; } snprintf(strBuf, 256, "%.*f", precision, ((float)num / (float)den)); p.set(CameraParameters::KEY_FOCAL_LENGTH, strBuf); //p.set(CameraParameters::KEY_FOCAL_LENGTH, "3.43"); //p.set(CameraParameters::KEY_FOCAL_LENGTH, "0.9"); // Additional params. p.set("contrast", "auto"); p.set("iso", "auto"); p.set("wdr", 0); p.set("metering", "center"); p.set("brightness", 0); p.set("brightness-max", 2); p.set("brightness-min", -2); p.set("saturation", 0); p.set("saturation-max", 2); p.set("saturation-min", -2); p.set("sharpness", 0); p.set("sharpness-max", 2); p.set("sharpness-min", -2); p.set("hue", 0); p.set("hue-max", 2); p.set("hue-min", -2); m_params = p; m_internalParams = ip; /* make sure m_secCamera has all the settings we do. applications * aren't required to call setParameters themselves (only if they * want to change something. */ setParameters(p); m_secCamera->setPreviewFrameRate(maxPreviewFps); } bool ExynosCameraHWInterface::m_startPreviewInternal(void) { ALOGV("DEBUG(%s):", __func__); int i; int previewW, previewH, previewFormat, previewFramesize; m_secCamera->getPreviewSize(&previewW, &previewH); previewFormat = m_secCamera->getPreviewFormat(); // we will use previewFramesize for m_previewHeap[i] previewFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(m_orgPreviewRect.colorFormat), m_orgPreviewRect.w, m_orgPreviewRect.h); ExynosBuffer previewBuf; void *virtAddr[3]; int fd[3]; for (i = 0; i < 3; i++) { virtAddr[i] = NULL; fd[i] = -1; } for (i = 0; i < NUM_OF_PREVIEW_BUF; i++) { m_avaliblePreviewBufHandle[i] = false; if (m_previewWindow->dequeue_buffer(m_previewWindow, &m_previewBufHandle[i], &m_previewStride[i]) != 0) { ALOGE("ERR(%s):Could not dequeue gralloc buffer[%d]!!", __func__, i); continue; } else { if (m_previewWindow->lock_buffer(m_previewWindow, m_previewBufHandle[i]) != 0) ALOGE("ERR(%s):Could not lock gralloc buffer[%d]!!", __func__, i); } if (m_flagGrallocLocked[i] == false) { if (m_grallocHal->lock(m_grallocHal, *m_previewBufHandle[i], GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_YUV_ADDR, 0, 0, previewW, previewH, virtAddr) != 0) { ALOGE("ERR(%s):could not obtain gralloc buffer", __func__); if (m_previewWindow->cancel_buffer(m_previewWindow, m_previewBufHandle[i]) != 0) ALOGE("ERR(%s):Could not cancel_buffer gralloc buffer[%d]!!", __func__, i); continue; } const private_handle_t *priv_handle = reinterpret_cast<const private_handle_t *>(*m_previewBufHandle[i]); fd[0] = priv_handle->fd; fd[1] = priv_handle->u_fd; fd[2] = priv_handle->v_fd; m_grallocVirtAddr[i] = virtAddr[0]; m_matchedGrallocIndex[i] = i; m_flagGrallocLocked[i] = true; } m_getAlignedYUVSize(previewFormat, previewW, previewH, &previewBuf); previewBuf.reserved.p = i; previewBuf.virt.extP[0] = (char *)virtAddr[0]; previewBuf.virt.extP[1] = (char *)virtAddr[1]; previewBuf.virt.extP[2] = (char *)virtAddr[2]; previewBuf.fd.extFd[0] = fd[0]; previewBuf.fd.extFd[1] = fd[1]; previewBuf.fd.extFd[2] = fd[2]; m_secCamera->setPreviewBuf(&previewBuf); if (m_previewHeap[i]) { m_previewHeap[i]->release(m_previewHeap[i]); m_previewHeap[i] = 0; } m_previewHeap[i] = m_getMemoryCb(-1, previewFramesize, 1, 0); if (!m_previewHeap[i]) { ALOGE("ERR(%s):m_getMemoryCb(m_previewHeap[%d], size(%d) fail", __func__, i, previewFramesize); continue; } m_avaliblePreviewBufHandle[i] = true; } if (m_secCamera->startPreview() == false) { ALOGE("ERR(%s):Fail on m_secCamera->startPreview()", __func__); return false; } for (i = NUM_OF_PREVIEW_BUF - m_minUndequeuedBufs; i < NUM_OF_PREVIEW_BUF; i++) { if (m_secCamera->getPreviewBuf(&previewBuf) == false) { ALOGE("ERR(%s):getPreviewBuf() fail", __func__); return false; } if (m_grallocHal && m_flagGrallocLocked[previewBuf.reserved.p] == true) { m_grallocHal->unlock(m_grallocHal, *m_previewBufHandle[previewBuf.reserved.p]); m_flagGrallocLocked[previewBuf.reserved.p] = false; } if (m_previewWindow->cancel_buffer(m_previewWindow, m_previewBufHandle[previewBuf.reserved.p]) != 0) ALOGE("ERR(%s):Could not cancel_buffer gralloc buffer[%d]!!", __func__, previewBuf.reserved.p); m_avaliblePreviewBufHandle[previewBuf.reserved.p] = false; } m_setSkipFrame(INITIAL_SKIP_FRAME); if (m_pictureRunning == false && m_startPictureInternal() == false) ALOGE("ERR(%s):m_startPictureInternal() fail", __func__); return true; } void ExynosCameraHWInterface::m_stopPreviewInternal(void) { ALOGV("DEBUG(%s):", __func__); /* request that the preview thread stop. */ if (m_previewRunning == true) { m_previewRunning = false; if (m_previewStartDeferred == false) { m_previewCondition.signal(); /* wait until preview thread is stopped */ m_previewStoppedCondition.wait(m_previewLock); for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { if (m_previewBufHandle[i] != NULL) { if (m_grallocHal && m_flagGrallocLocked[i] == true) { m_grallocHal->unlock(m_grallocHal, *m_previewBufHandle[i]); m_flagGrallocLocked[i] = false; } if (m_avaliblePreviewBufHandle[i] == true) { if (m_previewWindow->cancel_buffer(m_previewWindow, m_previewBufHandle[i]) != 0) { ALOGE("ERR(%s):Fail to cancel buffer(%d)", __func__, i); } else { m_previewBufHandle[i] = NULL; m_previewStride[i] = NULL; } m_avaliblePreviewBufHandle[i] = false; } } } } else { ALOGV("DEBUG(%s):preview running but deferred, doing nothing", __func__); } } else { ALOGV("DEBUG(%s):preview not running, doing nothing", __func__); } } bool ExynosCameraHWInterface::m_previewThreadFuncWrapper(void) { ALOGV("DEBUG(%s):starting", __func__); while (1) { m_previewLock.lock(); while (m_previewRunning == false) { if ( m_secCamera->flagStartPreview() == true && m_secCamera->stopPreview() == false) ALOGE("ERR(%s):Fail on m_secCamera->stopPreview()", __func__); ALOGV("DEBUG(%s):calling m_secCamera->stopPreview() and waiting", __func__); m_previewStoppedCondition.signal(); m_previewCondition.wait(m_previewLock); ALOGV("DEBUG(%s):return from wait", __func__); } m_previewLock.unlock(); if (m_exitPreviewThread == true) { if ( m_secCamera->flagStartPreview() == true && m_secCamera->stopPreview() == false) ALOGE("ERR(%s):Fail on m_secCamera->stopPreview()", __func__); return true; } m_previewThreadFunc(); } } bool ExynosCameraHWInterface::m_previewThreadFunc(void) { ExynosBuffer previewBuf, callbackBuf; int stride; int previewW, previewH; bool doPutPreviewBuf = true; if (m_secCamera->getPreviewBuf(&previewBuf) == false) { ALOGE("ERR(%s):getPreviewBuf() fail", __func__); return false; } #ifndef USE_3DNR_DMAOUT if (m_videoStart == true) { copy_previewBuf = previewBuf; m_videoRunning = true; m_videoCondition.signal(); } #endif m_skipFrameLock.lock(); if (0 < m_skipFrame) { m_skipFrame--; m_skipFrameLock.unlock(); ALOGV("DEBUG(%s):skipping %d frame", __func__, previewBuf.reserved.p); if ( doPutPreviewBuf == true && m_secCamera->putPreviewBuf(&previewBuf) == false) { ALOGE("ERR(%s):putPreviewBuf(%d) fail", __func__, previewBuf.reserved.p); return false; } return true; } m_skipFrameLock.unlock(); callbackBuf = previewBuf; m_secCamera->getPreviewSize(&previewW, &previewH); if (m_previewWindow && m_grallocHal && m_previewRunning == true) { bool findGrallocBuf = false; buffer_handle_t *bufHandle = NULL; void *virtAddr[3]; int fd[3]; /* Unlock grallocHal buffer if locked */ if (m_flagGrallocLocked[previewBuf.reserved.p] == true) { m_grallocHal->unlock(m_grallocHal, *m_previewBufHandle[previewBuf.reserved.p]); m_flagGrallocLocked[previewBuf.reserved.p] = false; } else { if (m_previewWindow->lock_buffer(m_previewWindow, bufHandle) != 0) ALOGE("ERR(%s):Could not lock gralloc buffer!!", __func__); } /* Enqueue lastest buffer */ if (m_avaliblePreviewBufHandle[previewBuf.reserved.p] == true) { if (m_previewWindow->enqueue_buffer(m_previewWindow, m_previewBufHandle[previewBuf.reserved.p]) != 0) { ALOGE("ERR(%s):Could not enqueue gralloc buffer[%d]!!", __func__, previewBuf.reserved.p); goto callbacks; } m_avaliblePreviewBufHandle[previewBuf.reserved.p] = false; } /* Dequeue buffer from Gralloc */ if (m_previewWindow->dequeue_buffer(m_previewWindow, &bufHandle, &stride) != 0) { ALOGE("ERR(%s):Could not dequeue gralloc buffer!!", __func__); goto callbacks; } /* Get virtual address from dequeued buf */ if (m_grallocHal->lock(m_grallocHal, *bufHandle, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_YUV_ADDR, 0, 0, previewW, previewH, virtAddr) != 0) { ALOGE("ERR(%s):could not obtain gralloc buffer", __func__); goto callbacks; } const private_handle_t *priv_handle = reinterpret_cast<const private_handle_t *>(*bufHandle); fd[0] = priv_handle->fd; fd[1] = priv_handle->u_fd; fd[2] = priv_handle->v_fd; for (int i = 0; i < NUM_OF_PREVIEW_BUF; i++) { if ((unsigned int)m_grallocVirtAddr[i] == (unsigned int)virtAddr[0]) { findGrallocBuf = true; m_previewBufHandle[i] = bufHandle; m_previewStride[i] = stride; previewBuf.reserved.p = i; previewBuf.virt.extP[0] = (char *)virtAddr[0]; previewBuf.virt.extP[1] = (char *)virtAddr[1]; previewBuf.virt.extP[2] = (char *)virtAddr[2]; previewBuf.fd.extFd[0] = fd[0]; previewBuf.fd.extFd[1] = fd[1]; previewBuf.fd.extFd[2] = fd[2]; m_secCamera->setPreviewBuf(&previewBuf); m_matchedGrallocIndex[previewBuf.reserved.p] = i; m_avaliblePreviewBufHandle[i] = true; break; } } if (findGrallocBuf == false) { ALOGE("%s:addr(%x) is not matched any gralloc buffer's addr", __func__, virtAddr[0]); goto callbacks; } if ( doPutPreviewBuf == true && m_secCamera->putPreviewBuf(&previewBuf) == false) ALOGE("ERR(%s):putPreviewBuf(%d) fail", __func__, previewBuf.reserved.p); else doPutPreviewBuf = false; } callbacks: if ( m_previewRunning == true && m_msgEnabled & CAMERA_MSG_PREVIEW_FRAME) { // resize from previewBuf(max size) to m_previewHeap(user's set size) if (m_exynosPreviewCSC) { int previewFormat = m_secCamera->getPreviewFormat(); csc_set_src_format(m_exynosPreviewCSC, previewW, previewH - 8, 0, 0, previewW, previewH - 8, V4L2_PIX_2_HAL_PIXEL_FORMAT(previewFormat), 0); csc_set_dst_format(m_exynosPreviewCSC, m_orgPreviewRect.w, m_orgPreviewRect.h, 0, 0, m_orgPreviewRect.w, m_orgPreviewRect.h, V4L2_PIX_2_HAL_PIXEL_FORMAT(m_orgPreviewRect.colorFormat), 1); csc_set_src_buffer(m_exynosPreviewCSC, (unsigned char *)callbackBuf.virt.extP[0], (unsigned char *)callbackBuf.virt.extP[1], (unsigned char *)callbackBuf.virt.extP[2], 0); ExynosBuffer dstBuf; m_getAlignedYUVSize(m_orgPreviewRect.colorFormat, m_orgPreviewRect.w, m_orgPreviewRect.h, &dstBuf); dstBuf.virt.extP[0] = (char *)m_previewHeap[callbackBuf.reserved.p]->data; for (int i = 1; i < 3; i++) { if (dstBuf.size.extS[i] != 0) dstBuf.virt.extP[i] = dstBuf.virt.extP[i-1] + dstBuf.size.extS[i-1]; } csc_set_dst_buffer(m_exynosPreviewCSC, (unsigned char *)dstBuf.virt.extP[0], (unsigned char *)dstBuf.virt.extP[1], (unsigned char *)dstBuf.virt.extP[2], 0); if (csc_convert(m_exynosPreviewCSC) != 0) ALOGE("ERR(%s):csc_convert() fail", __func__); } else { ALOGE("ERR(%s):m_exynosPreviewCSC == NULL", __func__); } } /* TODO: We need better error handling scheme than this scheme */ if ( doPutPreviewBuf == true && m_secCamera->putPreviewBuf(&previewBuf) == false) ALOGE("ERR(%s):putPreviewBuf(%d) fail", __func__, previewBuf.reserved.p); else doPutPreviewBuf = false; if ( m_previewRunning == true && m_msgEnabled & CAMERA_MSG_PREVIEW_FRAME) { m_dataCb(CAMERA_MSG_PREVIEW_FRAME, m_previewHeap[callbackBuf.reserved.p], 0, NULL, m_callbackCookie); } /* Face detection */ if ( m_previewRunning == true && m_msgEnabled & CAMERA_MSG_PREVIEW_METADATA && m_secCamera->flagStartFaceDetection() == true) { camera_frame_metadata_t *ptrMetadata = NULL; int id[NUM_OF_DETECTED_FACES]; int score[NUM_OF_DETECTED_FACES]; ExynosRect2 detectedFace[NUM_OF_DETECTED_FACES]; ExynosRect2 detectedLeftEye[NUM_OF_DETECTED_FACES]; ExynosRect2 detectedRightEye[NUM_OF_DETECTED_FACES]; ExynosRect2 detectedMouth[NUM_OF_DETECTED_FACES]; int numOfDetectedFaces = m_secCamera->getDetectedFacesAreas(NUM_OF_DETECTED_FACES, id, score, detectedFace, detectedLeftEye, detectedRightEye, detectedMouth); if (0 < numOfDetectedFaces) { // camera.h // width : -1000~1000 // height : -1000~1000 // if eye, mouth is not detectable : -2000, -2000. int realNumOfDetectedFaces = 0; m_faceDetected = true; for (int i = 0; i < numOfDetectedFaces; i++) { // over 50s, we will catch //if (score[i] < 50) // continue; m_faces[realNumOfDetectedFaces].rect[0] = m_calibratePosition(previewW, 2000, detectedFace[i].x1) - 1000; m_faces[realNumOfDetectedFaces].rect[1] = m_calibratePosition(previewH, 2000, detectedFace[i].y1) - 1000; m_faces[realNumOfDetectedFaces].rect[2] = m_calibratePosition(previewW, 2000, detectedFace[i].x2) - 1000; m_faces[realNumOfDetectedFaces].rect[3] = m_calibratePosition(previewH, 2000, detectedFace[i].y2) - 1000; m_faces[realNumOfDetectedFaces].id = id[i]; m_faces[realNumOfDetectedFaces].score = score[i]; m_faces[realNumOfDetectedFaces].left_eye[0] = (detectedLeftEye[i].x1 < 0) ? -2000 : m_calibratePosition(previewW, 2000, detectedLeftEye[i].x1) - 1000; m_faces[realNumOfDetectedFaces].left_eye[1] = (detectedLeftEye[i].y1 < 0) ? -2000 : m_calibratePosition(previewH, 2000, detectedLeftEye[i].y1) - 1000; m_faces[realNumOfDetectedFaces].right_eye[0] = (detectedRightEye[i].x1 < 0) ? -2000 : m_calibratePosition(previewW, 2000, detectedRightEye[i].x1) - 1000; m_faces[realNumOfDetectedFaces].right_eye[1] = (detectedRightEye[i].y1 < 0) ? -2000 : m_calibratePosition(previewH, 2000, detectedRightEye[i].y1) - 1000; m_faces[realNumOfDetectedFaces].mouth[0] = (detectedMouth[i].x1 < 0) ? -2000 : m_calibratePosition(previewW, 2000, detectedMouth[i].x1) - 1000; m_faces[realNumOfDetectedFaces].mouth[1] = (detectedMouth[i].y1 < 0) ? -2000 : m_calibratePosition(previewH, 2000, detectedMouth[i].y1) - 1000; realNumOfDetectedFaces++; } m_frameMetadata.number_of_faces = realNumOfDetectedFaces; m_frameMetadata.faces = m_faces; ptrMetadata = &m_frameMetadata; m_dataCb(CAMERA_MSG_PREVIEW_METADATA, m_previewHeap[callbackBuf.reserved.p], 0, ptrMetadata, m_callbackCookie); } else if (numOfDetectedFaces == 0 && m_faceDetected == true) { m_frameMetadata.number_of_faces = 0; m_frameMetadata.faces = m_faces; ptrMetadata = &m_frameMetadata; m_dataCb(CAMERA_MSG_PREVIEW_METADATA, m_previewHeap[callbackBuf.reserved.p], 0, ptrMetadata, m_callbackCookie); m_faceDetected = false; } } // zero shutter lag if (m_pictureRunning == false && m_startPictureInternal() == false) ALOGE("ERR(%s):m_startPictureInternal() fail", __func__); m_stateLock.lock(); if (m_captureInProgress == true) { m_stateLock.unlock(); } else { m_stateLock.unlock(); if (m_numOfAvaliblePictureBuf < NUM_OF_PICTURE_BUF) { ExynosBufferQueue *cur = m_oldPictureBufQueueHead; do { if(cur->next == NULL) { cur->buf = m_pictureBuf; break; } cur = cur->next; } while (cur->next); if (m_secCamera->getPictureBuf(&m_pictureBuf) == false) ALOGE("ERR(%s):getPictureBuf() fail", __func__); else m_numOfAvaliblePictureBuf++; } if (NUM_OF_WAITING_PUT_PICTURE_BUF < m_numOfAvaliblePictureBuf) { ExynosBuffer nullBuf; ExynosBuffer oldBuf; oldBuf = m_oldPictureBufQueueHead->buf; m_oldPictureBufQueueHead->buf = nullBuf; if (m_oldPictureBufQueueHead->next) { ExynosBufferQueue *newQueueHead = m_oldPictureBufQueueHead->next; m_oldPictureBufQueueHead->next = NULL; m_oldPictureBufQueueHead = newQueueHead; } else { m_oldPictureBufQueueHead = &m_oldPictureBufQueue[0]; } if (oldBuf != nullBuf) { if (m_secCamera->putPictureBuf(&oldBuf) == false) ALOGE("ERR(%s):putPictureBuf(%d) fail", __func__, oldBuf.reserved.p); else { m_numOfAvaliblePictureBuf--; if (m_numOfAvaliblePictureBuf < 0) m_numOfAvaliblePictureBuf = 0; } } } } return true; } bool ExynosCameraHWInterface::m_videoThreadFuncWrapper(void) { while (1) { while (m_videoRunning == false) { m_videoLock.lock(); #ifdef USE_3DNR_DMAOUT if ( m_secCamera->flagStartVideo() == true && m_secCamera->stopVideo() == false) ALOGE("ERR(%s):Fail on m_secCamera->stopVideo()", __func__); #endif ALOGV("DEBUG(%s):calling mExynosCamera->stopVideo() and waiting", __func__); m_videoStoppedCondition.signal(); m_videoCondition.wait(m_videoLock); ALOGV("DEBUG(%s):return from wait", __func__); m_videoLock.unlock(); } if (m_exitVideoThread == true) { m_videoLock.lock(); #ifdef USE_3DNR_DMAOUT if ( m_secCamera->flagStartVideo() == true && m_secCamera->stopVideo() == false) ALOGE("ERR(%s):Fail on m_secCamera->stopVideo()", __func__); #endif m_videoLock.unlock(); return true; } m_videoThreadFunc(); #ifndef USE_3DNR_DMAOUT m_videoRunning = false; #endif } return true; } bool ExynosCameraHWInterface::m_videoThreadFunc(void) { nsecs_t timestamp; #ifdef USE_3DNR_DMAOUT ExynosBuffer videoBuf; #endif if (m_numOfAvailableVideoBuf == 0) usleep(1000); // sleep 1msec for other threads. { if ( m_msgEnabled & CAMERA_MSG_VIDEO_FRAME && m_videoRunning == true) { Mutex::Autolock lock(m_videoLock); if (m_numOfAvailableVideoBuf == 0) { ALOGV("DEBUG(%s):waiting releaseRecordingFrame()", __func__); return true; } #ifdef USE_3DNR_DMAOUT if (m_secCamera->getVideoBuf(&videoBuf) == false) { ALOGE("ERR(%s):Fail on ExynosCamera->getVideoBuf()", __func__); return false; } #endif m_numOfAvailableVideoBuf--; if (m_numOfAvailableVideoBuf < 0) m_numOfAvailableVideoBuf = 0; timestamp = systemTime(SYSTEM_TIME_MONOTONIC); // Notify the client of a new frame. if ( m_msgEnabled & CAMERA_MSG_VIDEO_FRAME && m_videoRunning == true) { // resize from videoBuf(max size) to m_videoHeap(user's set size) if (m_exynosVideoCSC) { int videoW, videoH, videoFormat = 0; int cropX, cropY, cropW, cropH = 0; #ifndef USE_3DNR_DMAOUT int previewW, previewH, previewFormat = 0; previewFormat = m_secCamera->getPreviewFormat(); m_secCamera->getPreviewSize(&previewW, &previewH); #endif videoFormat = m_secCamera->getVideoFormat(); m_secCamera->getVideoSize(&videoW, &videoH); m_getRatioSize(videoW, videoH, m_orgVideoRect.w, m_orgVideoRect.h, &cropX, &cropY, &cropW, &cropH, m_secCamera->getZoom()); ALOGV("DEBUG(%s):cropX = %d, cropY = %d, cropW = %d, cropH = %d", __func__, cropX, cropY, cropW, cropH); #ifdef USE_3DNR_DMAOUT csc_set_src_format(m_exynosVideoCSC, videoW, videoH, cropX, cropY, cropW, cropH, V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), 0); #else csc_set_src_format(m_exynosVideoCSC, previewW, previewH - 8, 0, 0, previewW, previewH - 8, V4L2_PIX_2_HAL_PIXEL_FORMAT(previewFormat), 0); #endif csc_set_dst_format(m_exynosVideoCSC, m_orgVideoRect.w, m_orgVideoRect.h, 0, 0, m_orgVideoRect.w, m_orgVideoRect.h, V4L2_PIX_2_HAL_PIXEL_FORMAT(videoFormat), 1); #ifdef USE_3DNR_DMAOUT csc_set_src_buffer(m_exynosVideoCSC, (unsigned char *)videoBuf.virt.extP[0], (unsigned char *)videoBuf.virt.extP[1], (unsigned char *)videoBuf.virt.extP[2], 0); #else csc_set_src_buffer(m_exynosVideoCSC, (unsigned char *)copy_previewBuf.virt.extP[0], (unsigned char *)copy_previewBuf.virt.extP[2], (unsigned char *)copy_previewBuf.virt.extP[1], 0); #endif ExynosBuffer dstBuf; m_getAlignedYUVSize(videoFormat, m_orgVideoRect.w, m_orgVideoRect.h, &dstBuf); #ifdef USE_3DNR_DMAOUT dstBuf.virt.extP[0] = (char *)m_resizedVideoHeap[videoBuf.reserved.p]->data; #else dstBuf.virt.extP[0] = (char *)m_resizedVideoHeap[m_cntVideoBuf]->data; #endif for (int i = 1; i < 3; i++) { if (dstBuf.size.extS[i] != 0) dstBuf.virt.extP[i] = dstBuf.virt.extP[i-1] + dstBuf.size.extS[i-1]; } csc_set_dst_buffer(m_exynosVideoCSC, (unsigned char *)dstBuf.virt.extP[0], (unsigned char *)dstBuf.virt.extP[1], (unsigned char *)dstBuf.virt.extP[2], 0); if (csc_convert(m_exynosVideoCSC) != 0) ALOGE("ERR(%s):csc_convert() fail", __func__); } else { ALOGE("ERR(%s):m_exynosVideoCSC == NULL", __func__); } #ifdef USE_3DNR_DMAOUT m_dataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, m_resizedVideoHeap[videoBuf.reserved.p], 0, m_callbackCookie); #else m_dataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, m_resizedVideoHeap[m_cntVideoBuf], 0, m_callbackCookie); m_cntVideoBuf++; if (m_cntVideoBuf == NUM_OF_VIDEO_BUF) m_cntVideoBuf = 0; #endif } // HACK : This must can handle on releaseRecordingFrame() #ifdef USE_3DNR_DMAOUT m_secCamera->putVideoBuf(&videoBuf); #endif m_numOfAvailableVideoBuf++; if (NUM_OF_VIDEO_BUF <= m_numOfAvailableVideoBuf) m_numOfAvailableVideoBuf = NUM_OF_VIDEO_BUF; // until here } else usleep(1000); // sleep 1msec for stopRecording } return true; } bool ExynosCameraHWInterface::m_autoFocusThreadFunc(void) { int count =0; bool afResult = false; ALOGV("DEBUG(%s):starting", __func__); /* block until we're told to start. we don't want to use * a restartable thread and requestExitAndWait() in cancelAutoFocus() * because it would cause deadlock between our callbacks and the * caller of cancelAutoFocus() which both want to grab the same lock * in CameraServices layer. */ m_focusLock.lock(); /* check early exit request */ if (m_exitAutoFocusThread == true) { m_focusLock.unlock(); ALOGV("DEBUG(%s):exiting on request0", __func__); return true; } m_focusCondition.wait(m_focusLock); /* check early exit request */ if (m_exitAutoFocusThread == true) { m_focusLock.unlock(); ALOGV("DEBUG(%s):exiting on request1", __func__); return true; } m_focusLock.unlock(); if (m_secCamera->autoFocus() == false) { ALOGE("ERR(%s):Fail on m_secCamera->autoFocus()", __func__); return false; } switch (m_secCamera->getFucusModeResult()) { case 0: ALOGV("DEBUG(%s):AF Cancelled !!", __func__); afResult = true; break; case 1: ALOGV("DEBUG(%s):AF Success!!", __func__); afResult = true; break; default: ALOGV("DEBUG(%s):AF Fail !!", __func__); afResult = false; break; } // CAMERA_MSG_FOCUS only takes a bool. true for // finished and false for failure. cancel is still // considered a true result. if (m_msgEnabled & CAMERA_MSG_FOCUS) m_notifyCb(CAMERA_MSG_FOCUS, afResult, 0, m_callbackCookie); ALOGV("DEBUG(%s):exiting with no error", __func__); return true; } bool ExynosCameraHWInterface::m_startPictureInternal(void) { if (m_pictureRunning == true) { ALOGE("ERR(%s):Aready m_pictureRunning is running", __func__); return false; } int pictureW, pictureH, pictureFormat; unsigned int pictureFrameSize, pictureChromaSize; ExynosBuffer nullBuf; int numPlanes; m_secCamera->getPictureSize(&pictureW, &pictureH); pictureFormat = m_secCamera->getPictureFormat(); PLANAR_FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(V4L2_PIX_FMT_NV16), pictureW, pictureH, &pictureFrameSize, &pictureChromaSize); numPlanes = NUM_PLANES(V4L2_PIX_2_HAL_PIXEL_FORMAT(V4L2_PIX_FMT_NV16)); #if 0 if (m_rawHeap) { m_rawHeap->release(m_rawHeap); m_rawHeap = 0; } m_rawHeap = m_getMemoryCb(-1, pictureFramesize, 1, NULL); if (!m_rawHeap) { ALOGE("ERR(%s):m_getMemoryCb(m_rawHeap, size(%d) fail", __func__, pictureFramesize); return false; } pictureFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(pictureFormat), pictureW, pictureH); #endif for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) { for (int j = 0; j < 3; j++) if (m_pictureFds[i][j] >= 0) { close(m_pictureFds[i][j]); m_pictureFds[i][j] = -1; } m_pictureFds[i][0] = ion_alloc(m_ion_client, pictureFrameSize, 0, ION_HEAP_SYSTEM_MASK, 0); if (m_pictureFds[i][0] < 0) { ALOGE("ERR(%s):ion_alloc(m_pictureFds[%d], size(%d) fail", __func__, i, pictureFrameSize); return false; } for (int j = 1; j < numPlanes; j++) { m_pictureFds[i][j] = ion_alloc(m_ion_client, pictureChromaSize, 0, ION_HEAP_SYSTEM_MASK, 0); if (m_pictureFds[i][j]) { ALOGE("ERR(%s):ion_alloc(m_pictureFds[%d][%d], size(%d) fail", __func__, i, j, pictureFrameSize); return false; } } m_getAlignedYUVSize(pictureFormat, pictureW, pictureH, &m_pictureBuf); m_pictureBuf.fd.extFd[0] = m_pictureFds[i][0]; for (int j = 1; j < 3; j++) { if (m_pictureBuf.size.extS[j] != 0) m_pictureBuf.fd.extFd[j] = m_pictureFds[i][j]; else m_pictureBuf.fd.extFd[j] = -1; } m_pictureBuf.reserved.p = i; m_secCamera->setPictureBuf(&m_pictureBuf); } // zero shutter lag if (m_secCamera->startPicture() == false) { ALOGE("ERR(%s):Fail on m_secCamera->startPicture()", __func__); return false; } m_numOfAvaliblePictureBuf = 0; m_pictureBuf = nullBuf; for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) { m_oldPictureBufQueue[i].buf = nullBuf; m_oldPictureBufQueue[i].next = NULL; } m_oldPictureBufQueueHead = &m_oldPictureBufQueue[0]; m_pictureRunning = true; return true; } bool ExynosCameraHWInterface::m_stopPictureInternal(void) { if (m_pictureRunning == false) { ALOGE("ERR(%s):Aready m_pictureRunning is stop", __func__); return false; } if (m_secCamera->flagStartPicture() == true && m_secCamera->stopPicture() == false) ALOGE("ERR(%s):Fail on m_secCamera->stopPicture()", __func__); for (int i = 0; i < NUM_OF_PICTURE_BUF; i++) { if (m_pictureHeap[i]) { m_pictureHeap[i]->release(m_pictureHeap[i]); m_pictureHeap[i] = 0; } } if (m_rawHeap) { m_rawHeap->release(m_rawHeap); m_rawHeap = 0; } m_pictureRunning = false; return true; } bool ExynosCameraHWInterface::m_pictureThreadFunc(void) { bool ret = false; int pictureW, pictureH, pictureFramesize = 0; int pictureFormat; int cropX, cropY, cropW, cropH = 0; ExynosBuffer pictureBuf; ExynosBuffer jpegBuf; camera_memory_t *JpegHeap = NULL; camera_memory_t *JpegHeapOut = NULL; m_secCamera->getPictureSize(&pictureW, &pictureH); pictureFormat = m_secCamera->getPictureFormat(); pictureFramesize = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(pictureFormat), pictureW, pictureH); JpegHeap = m_getMemoryCb(-1, pictureFramesize, 1, 0); if (!JpegHeap) { ALOGE("ERR(%s):m_getMemoryCb(JpegHeap, size(%d) fail", __func__, pictureFramesize); return false; } // resize from pictureBuf(max size) to rawHeap(user's set size) if (m_exynosPictureCSC) { m_getRatioSize(pictureW, pictureH, m_orgPictureRect.w, m_orgPictureRect.h, &cropX, &cropY, &cropW, &cropH, m_secCamera->getZoom()); ALOGV("DEBUG(%s):cropX = %d, cropY = %d, cropW = %d, cropH = %d", __func__, cropX, cropY, cropW, cropH); csc_set_src_format(m_exynosPictureCSC, pictureW, pictureH, cropX, cropY, cropW, cropH, V4L2_PIX_2_HAL_PIXEL_FORMAT(pictureFormat), 1); //0); csc_set_dst_format(m_exynosPictureCSC, m_orgPictureRect.w, m_orgPictureRect.h, 0, 0, m_orgPictureRect.w, m_orgPictureRect.h, V4L2_PIX_2_HAL_PIXEL_FORMAT(V4L2_PIX_FMT_NV16), 1); //0); csc_set_src_buffer(m_exynosPictureCSC, (unsigned char *)m_pictureBuf.virt.extP[0], (unsigned char *)m_pictureBuf.virt.extP[1], (unsigned char *)m_pictureBuf.virt.extP[2], 0); pictureBuf.size.extS[0] = ALIGN(m_orgPictureRect.w, 16) * ALIGN(m_orgPictureRect.h, 16) * 2; pictureBuf.size.extS[1] = 0; pictureBuf.size.extS[2] = 0; pictureBuf.virt.extP[0] = (char *)m_rawHeap->data; csc_set_dst_buffer(m_exynosPictureCSC, (unsigned char *)pictureBuf.virt.extP[0], (unsigned char *)pictureBuf.virt.extP[1], (unsigned char *)pictureBuf.virt.extP[2], 0); if (csc_convert(m_exynosPictureCSC) != 0) ALOGE("ERR(%s):csc_convert() fail", __func__); } else { ALOGE("ERR(%s):m_exynosPictureCSC == NULL", __func__); } if (m_msgEnabled & CAMERA_MSG_SHUTTER) m_notifyCb(CAMERA_MSG_SHUTTER, 0, 0, m_callbackCookie); m_getAlignedYUVSize(V4L2_PIX_FMT_NV16, m_orgPictureRect.w, m_orgPictureRect.h, &pictureBuf); for (int i = 1; i < 3; i++) { if (pictureBuf.size.extS[i] != 0) pictureBuf.virt.extP[i] = pictureBuf.virt.extP[i-1] + pictureBuf.size.extS[i-1]; ALOGV("(%s): pictureBuf.size.extS[%d] = %d", __func__, i, pictureBuf.size.extS[i]); } if (m_msgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { jpegBuf.virt.p = (char *)JpegHeap->data; jpegBuf.size.s = pictureFramesize; ExynosRect jpegRect; jpegRect.w = m_orgPictureRect.w; jpegRect.h = m_orgPictureRect.h; jpegRect.colorFormat = V4L2_PIX_FMT_NV16; if (m_secCamera->yuv2Jpeg(&pictureBuf, &jpegBuf, &jpegRect) == false) { ALOGE("ERR(%s):yuv2Jpeg() fail", __func__); m_stateLock.lock(); m_captureInProgress = false; m_pictureLock.lock(); m_pictureCondition.signal(); m_pictureLock.unlock(); m_stateLock.unlock(); goto out; } } m_stateLock.lock(); m_captureInProgress = false; m_pictureLock.lock(); m_pictureCondition.signal(); m_pictureLock.unlock(); m_stateLock.unlock(); if (m_msgEnabled & CAMERA_MSG_RAW_IMAGE) m_dataCb(CAMERA_MSG_RAW_IMAGE, m_rawHeap, 0, NULL, m_callbackCookie); /* TODO: Currently framework dose not support CAMERA_MSG_RAW_IMAGE_NOTIFY callback */ /* if (m_msgEnabled & CAMERA_MSG_RAW_IMAGE_NOTIFY) m_dataCb(CAMERA_MSG_RAW_IMAGE_NOTIFY, m_rawHeap, 0, NULL, m_callbackCookie); */ if (m_msgEnabled & CAMERA_MSG_POSTVIEW_FRAME) m_dataCb(CAMERA_MSG_POSTVIEW_FRAME, m_rawHeap, 0, NULL, m_callbackCookie); if (m_msgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { JpegHeapOut = m_getMemoryCb(-1, jpegBuf.size.s, 1, 0); if (!JpegHeapOut) { ALOGE("ERR(%s):m_getMemoryCb(JpegHeapOut, size(%d) fail", __func__, jpegBuf.size.s); return false; } // TODO : we shall pass JpegHeap mem directly? memcpy(JpegHeapOut->data, JpegHeap->data, jpegBuf.size.s); m_dataCb(CAMERA_MSG_COMPRESSED_IMAGE, JpegHeapOut, 0, NULL, m_callbackCookie); } if (m_videoStart == false) stopPreview(); ALOGV("DEBUG(%s):m_pictureThread end", __func__); ret = true; out: if (JpegHeapOut) { JpegHeapOut->release(JpegHeapOut); JpegHeapOut = 0; } if (JpegHeap) { JpegHeap->release(JpegHeap); JpegHeap = 0; } return ret; } #ifdef LOG_NDEBUG bool ExynosCameraHWInterface::m_fileDump(char *filename, void *srcBuf, uint32_t size) { FILE *yuv_fd = NULL; char *buffer = NULL; static int count = 0; yuv_fd = fopen(filename, "w+"); if (yuv_fd == NULL) { ALOGE("ERR file open fail: %s", filename); return 0; } buffer = (char *)malloc(size); if (buffer == NULL) { ALOGE("ERR malloc file"); fclose(yuv_fd); return 0; } memcpy(buffer, srcBuf, size); fflush(stdout); fwrite(buffer, 1, size, yuv_fd); fflush(yuv_fd); if (yuv_fd) fclose(yuv_fd); if (buffer) free(buffer); ALOGV("filedump(%s) is successed!!", filename); return true; } #endif void ExynosCameraHWInterface::m_setSkipFrame(int frame) { Mutex::Autolock lock(m_skipFrameLock); if (frame < m_skipFrame) return; m_skipFrame = frame; } int ExynosCameraHWInterface::m_saveJpeg( unsigned char *real_jpeg, int jpeg_size) { FILE *yuv_fp = NULL; char filename[100], *buffer = NULL; /* file create/open, note to "wb" */ yuv_fp = fopen("/data/camera_dump.jpeg", "wb"); if (yuv_fp == NULL) { ALOGE("Save jpeg file open error"); return -1; } ALOGV("DEBUG(%s):[BestIQ] real_jpeg size ========> %d", __func__, jpeg_size); buffer = (char *) malloc(jpeg_size); if (buffer == NULL) { ALOGE("Save YUV] buffer alloc failed"); if (yuv_fp) fclose(yuv_fp); return -1; } memcpy(buffer, real_jpeg, jpeg_size); fflush(stdout); fwrite(buffer, 1, jpeg_size, yuv_fp); fflush(yuv_fp); if (yuv_fp) fclose(yuv_fp); if (buffer) free(buffer); return 0; } void ExynosCameraHWInterface::m_savePostView(const char *fname, uint8_t *buf, uint32_t size) { int nw; int cnt = 0; uint32_t written = 0; ALOGD("opening file [%s]", fname); int fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { ALOGE("failed to create file [%s]: %s", fname, strerror(errno)); return; } ALOGD("writing %d bytes to file [%s]", size, fname); while (written < size) { nw = ::write(fd, buf + written, size - written); if (nw < 0) { ALOGE("failed to write to file %d [%s]: %s",written,fname, strerror(errno)); break; } written += nw; cnt++; } ALOGD("done writing %d bytes to file [%s] in %d passes",size, fname, cnt); ::close(fd); } bool ExynosCameraHWInterface::m_scaleDownYuv422(char *srcBuf, uint32_t srcWidth, uint32_t srcHeight, char *dstBuf, uint32_t dstWidth, uint32_t dstHeight) { int32_t step_x, step_y; int32_t iXsrc, iXdst; int32_t x, y, src_y_start_pos, dst_pos, src_pos; if (dstWidth % 2 != 0 || dstHeight % 2 != 0) { ALOGE("scale_down_yuv422: invalid width, height for scaling"); return false; } step_x = srcWidth / dstWidth; step_y = srcHeight / dstHeight; dst_pos = 0; for (uint32_t y = 0; y < dstHeight; y++) { src_y_start_pos = (y * step_y * (srcWidth * 2)); for (uint32_t x = 0; x < dstWidth; x += 2) { src_pos = src_y_start_pos + (x * (step_x * 2)); dstBuf[dst_pos++] = srcBuf[src_pos ]; dstBuf[dst_pos++] = srcBuf[src_pos + 1]; dstBuf[dst_pos++] = srcBuf[src_pos + 2]; dstBuf[dst_pos++] = srcBuf[src_pos + 3]; } } return true; } bool ExynosCameraHWInterface::m_YUY2toNV21(void *srcBuf, void *dstBuf, uint32_t srcWidth, uint32_t srcHeight) { int32_t x, y, src_y_start_pos, dst_cbcr_pos, dst_pos, src_pos; unsigned char *srcBufPointer = (unsigned char *)srcBuf; unsigned char *dstBufPointer = (unsigned char *)dstBuf; dst_pos = 0; dst_cbcr_pos = srcWidth*srcHeight; for (uint32_t y = 0; y < srcHeight; y++) { src_y_start_pos = (y * (srcWidth * 2)); for (uint32_t x = 0; x < (srcWidth * 2); x += 2) { src_pos = src_y_start_pos + x; dstBufPointer[dst_pos++] = srcBufPointer[src_pos]; } } for (uint32_t y = 0; y < srcHeight; y += 2) { src_y_start_pos = (y * (srcWidth * 2)); for (uint32_t x = 0; x < (srcWidth * 2); x += 4) { src_pos = src_y_start_pos + x; dstBufPointer[dst_cbcr_pos++] = srcBufPointer[src_pos + 3]; dstBufPointer[dst_cbcr_pos++] = srcBufPointer[src_pos + 1]; } } return true; } bool ExynosCameraHWInterface::m_checkVideoStartMarker(unsigned char *pBuf) { if (!pBuf) { ALOGE("m_checkVideoStartMarker() => pBuf is NULL"); return false; } if (HIBYTE(VIDEO_COMMENT_MARKER_H) == * pBuf && LOBYTE(VIDEO_COMMENT_MARKER_H) == *(pBuf + 1) && HIBYTE(VIDEO_COMMENT_MARKER_L) == *(pBuf + 2) && LOBYTE(VIDEO_COMMENT_MARKER_L) == *(pBuf + 3)) return true; return false; } bool ExynosCameraHWInterface::m_checkEOIMarker(unsigned char *pBuf) { if (!pBuf) { ALOGE("m_checkEOIMarker() => pBuf is NULL"); return false; } // EOI marker [FF D9] if (HIBYTE(JPEG_EOI_MARKER) == *pBuf && LOBYTE(JPEG_EOI_MARKER) == *(pBuf + 1)) return true; return false; } bool ExynosCameraHWInterface::m_findEOIMarkerInJPEG(unsigned char *pBuf, int dwBufSize, int *pnJPEGsize) { if (NULL == pBuf || 0 >= dwBufSize) { ALOGE("m_findEOIMarkerInJPEG() => There is no contents."); return false; } unsigned char *pBufEnd = pBuf + dwBufSize; while (pBuf < pBufEnd) { if (m_checkEOIMarker(pBuf++)) return true; (*pnJPEGsize)++; } return false; } bool ExynosCameraHWInterface::m_splitFrame(unsigned char *pFrame, int dwSize, int dwJPEGLineLength, int dwVideoLineLength, int dwVideoHeight, void *pJPEG, int *pdwJPEGSize, void *pVideo, int *pdwVideoSize) { ALOGV("DEBUG(%s):===========m_splitFrame Start==============", __func__); if (NULL == pFrame || 0 >= dwSize) { ALOGE("There is no contents (pFrame=%p, dwSize=%d", pFrame, dwSize); return false; } if (0 == dwJPEGLineLength || 0 == dwVideoLineLength) { ALOGE("There in no input information for decoding interleaved jpeg"); return false; } unsigned char *pSrc = pFrame; unsigned char *pSrcEnd = pFrame + dwSize; unsigned char *pJ = (unsigned char *)pJPEG; int dwJSize = 0; unsigned char *pV = (unsigned char *)pVideo; int dwVSize = 0; bool bRet = false; bool isFinishJpeg = false; while (pSrc < pSrcEnd) { // Check video start marker if (m_checkVideoStartMarker(pSrc)) { int copyLength; if (pSrc + dwVideoLineLength <= pSrcEnd) copyLength = dwVideoLineLength; else copyLength = pSrcEnd - pSrc - VIDEO_COMMENT_MARKER_LENGTH; // Copy video data if (pV) { memcpy(pV, pSrc + VIDEO_COMMENT_MARKER_LENGTH, copyLength); pV += copyLength; dwVSize += copyLength; } pSrc += copyLength + VIDEO_COMMENT_MARKER_LENGTH; } else { // Copy pure JPEG data int size = 0; int dwCopyBufLen = dwJPEGLineLength <= pSrcEnd-pSrc ? dwJPEGLineLength : pSrcEnd - pSrc; if (m_findEOIMarkerInJPEG((unsigned char *)pSrc, dwCopyBufLen, &size)) { isFinishJpeg = true; size += 2; // to count EOF marker size } else { if ((dwCopyBufLen == 1) && (pJPEG < pJ)) { unsigned char checkBuf[2] = { *(pJ - 1), *pSrc }; if (m_checkEOIMarker(checkBuf)) isFinishJpeg = true; } size = dwCopyBufLen; } memcpy(pJ, pSrc, size); dwJSize += size; pJ += dwCopyBufLen; pSrc += dwCopyBufLen; } if (isFinishJpeg) break; } if (isFinishJpeg) { bRet = true; if (pdwJPEGSize) *pdwJPEGSize = dwJSize; if (pdwVideoSize) *pdwVideoSize = dwVSize; } else { ALOGE("DecodeInterleaveJPEG_WithOutDT() => Can not find EOI"); bRet = false; if (pdwJPEGSize) *pdwJPEGSize = 0; if (pdwVideoSize) *pdwVideoSize = 0; } ALOGV("DEBUG(%s):===========m_splitFrame end==============", __func__); return bRet; } int ExynosCameraHWInterface::m_decodeInterleaveData(unsigned char *pInterleaveData, int interleaveDataSize, int yuvWidth, int yuvHeight, int *pJpegSize, void *pJpegData, void *pYuvData) { if (pInterleaveData == NULL) return false; bool ret = true; unsigned int *interleave_ptr = (unsigned int *)pInterleaveData; unsigned char *jpeg_ptr = (unsigned char *)pJpegData; unsigned char *yuv_ptr = (unsigned char *)pYuvData; unsigned char *p; int jpeg_size = 0; int yuv_size = 0; int i = 0; ALOGV("DEBUG(%s):m_decodeInterleaveData Start~~~", __func__); while (i < interleaveDataSize) { if ((*interleave_ptr == 0xFFFFFFFF) || (*interleave_ptr == 0x02FFFFFF) || (*interleave_ptr == 0xFF02FFFF)) { // Padding Data interleave_ptr++; i += 4; } else if ((*interleave_ptr & 0xFFFF) == 0x05FF) { // Start-code of YUV Data p = (unsigned char *)interleave_ptr; p += 2; i += 2; // Extract YUV Data if (pYuvData != NULL) { memcpy(yuv_ptr, p, yuvWidth * 2); yuv_ptr += yuvWidth * 2; yuv_size += yuvWidth * 2; } p += yuvWidth * 2; i += yuvWidth * 2; // Check End-code of YUV Data if ((*p == 0xFF) && (*(p + 1) == 0x06)) { interleave_ptr = (unsigned int *)(p + 2); i += 2; } else { ret = false; break; } } else { // Extract JPEG Data if (pJpegData != NULL) { memcpy(jpeg_ptr, interleave_ptr, 4); jpeg_ptr += 4; jpeg_size += 4; } interleave_ptr++; i += 4; } } if (ret) { if (pJpegData != NULL) { // Remove Padding after EOI for (i = 0; i < 3; i++) { if (*(--jpeg_ptr) != 0xFF) { break; } jpeg_size--; } *pJpegSize = jpeg_size; } // Check YUV Data Size if (pYuvData != NULL) { if (yuv_size != (yuvWidth * yuvHeight * 2)) { ret = false; } } } ALOGV("DEBUG(%s):m_decodeInterleaveData End~~~", __func__); return ret; } bool ExynosCameraHWInterface::m_isSupportedPreviewSize(const int width, const int height) const { unsigned int i; for (i = 0; i < m_supportedPreviewSizes.size(); i++) { if (m_supportedPreviewSizes[i].width == width && m_supportedPreviewSizes[i].height == height) return true; } return false; } void ExynosCameraHWInterface::m_getAlignedYUVSize(int colorFormat, int w, int h, ExynosBuffer *buf) { switch (colorFormat) { // 1p case V4L2_PIX_FMT_RGB565 : case V4L2_PIX_FMT_YUYV : case V4L2_PIX_FMT_UYVY : case V4L2_PIX_FMT_VYUY : case V4L2_PIX_FMT_YVYU : buf->size.extS[0] = FRAME_SIZE(V4L2_PIX_2_HAL_PIXEL_FORMAT(colorFormat), w, h); buf->size.extS[1] = 0; buf->size.extS[2] = 0; break; // 2p case V4L2_PIX_FMT_NV12 : case V4L2_PIX_FMT_NV12T : case V4L2_PIX_FMT_NV21 : buf->size.extS[0] = ALIGN(w, 16) * ALIGN(h, 16); buf->size.extS[1] = ALIGN(w/2, 16) * ALIGN(h/2, 16); buf->size.extS[2] = 0; break; case V4L2_PIX_FMT_NV12M : case V4L2_PIX_FMT_NV12MT_16X16 : buf->size.extS[0] = ALIGN(ALIGN(w, 16) * ALIGN(h, 16), 2048); buf->size.extS[1] = ALIGN(ALIGN(w, 16) * ALIGN(h >> 1, 8), 2048); buf->size.extS[2] = 0; break; case V4L2_PIX_FMT_NV16 : case V4L2_PIX_FMT_NV61 : buf->size.extS[0] = ALIGN(w, 16) * ALIGN(h, 16); buf->size.extS[1] = ALIGN(w, 16) * ALIGN(h, 16); buf->size.extS[2] = 0; break; // 3p case V4L2_PIX_FMT_YUV420 : case V4L2_PIX_FMT_YVU420 : buf->size.extS[0] = (w * h); buf->size.extS[1] = (w * h) >> 2; buf->size.extS[2] = (w * h) >> 2; break; case V4L2_PIX_FMT_YUV420M: case V4L2_PIX_FMT_YVU420M : case V4L2_PIX_FMT_YUV422P : buf->size.extS[0] = ALIGN(w, 16) * ALIGN(h, 16); buf->size.extS[1] = ALIGN(w/2, 8) * ALIGN(h/2, 8); buf->size.extS[2] = ALIGN(w/2, 8) * ALIGN(h/2, 8); break; default: ALOGE("ERR(%s):unmatched colorFormat(%d)", __func__, colorFormat); return; break; } } bool ExynosCameraHWInterface::m_getResolutionList(String8 & string8Buf, char * strBuf, int w, int h) { bool ret = false; bool flagFirst = true; // this is up to /packages/apps/Camera/res/values/arrays.xml int RESOLUTION_LIST[][2] = { { 3264, 2448}, { 2592, 1936}, { 2576, 1948}, { 2560, 1920}, { 2048, 1536}, { 1920, 1080}, { 1600, 1200}, { 1280, 720}, { 1024, 768}, { 800, 600}, { 800, 480}, { 720, 480}, { 640, 480}, { 528, 432}, { 480, 320}, { 352, 288}, { 320, 240}, { 176, 144} }; int sizeOfResSize = sizeof(RESOLUTION_LIST) / (sizeof(int) * 2); for (int i = 0; i < sizeOfResSize; i++) { if ( RESOLUTION_LIST[i][0] <= w && RESOLUTION_LIST[i][1] <= h) { if (flagFirst == true) flagFirst = false; else string8Buf.append(","); sprintf(strBuf, "%dx%d", RESOLUTION_LIST[i][0], RESOLUTION_LIST[i][1]); string8Buf.append(strBuf); ret = true; } } if (ret == false) ALOGE("ERR(%s):cannot find resolutions", __func__); return ret; } bool ExynosCameraHWInterface::m_getZoomRatioList(String8 & string8Buf, char * strBuf, int maxZoom, int start, int end) { bool flagFirst = true; int cur = start; int step = (end - start) / maxZoom; for (int i = 0; i < maxZoom; i++) { sprintf(strBuf, "%d", cur); string8Buf.append(strBuf); string8Buf.append(","); cur += step; } sprintf(strBuf, "%d", end); string8Buf.append(strBuf); // ex : "100,130,160,190,220,250,280,310,340,360,400" return true; } int ExynosCameraHWInterface::m_bracketsStr2Ints(char *str, int num, ExynosRect2 *rect2s, int *weights) { char *curStr = str; char buf[128]; char *bracketsOpen; char *bracketsClose; int tempArray[5]; int validFocusedAreas = 0; for (int i = 0; i < num; i++) { if (curStr == NULL) break; bracketsOpen = strchr(curStr, '('); if (bracketsOpen == NULL) break; bracketsClose = strchr(bracketsOpen, ')'); if (bracketsClose == NULL) break; strncpy(buf, bracketsOpen, bracketsClose - bracketsOpen + 1); buf[bracketsClose - bracketsOpen + 1] = 0; if (m_subBracketsStr2Ints(5, buf, tempArray) == false) { ALOGE("ERR(%s):m_subBracketsStr2Ints(%s) fail", __func__, buf); break; } rect2s[i].x1 = tempArray[0]; rect2s[i].y1 = tempArray[1]; rect2s[i].x2 = tempArray[2]; rect2s[i].y2 = tempArray[3]; weights[i] = tempArray[4]; validFocusedAreas++; curStr = bracketsClose; } return validFocusedAreas; } bool ExynosCameraHWInterface::m_subBracketsStr2Ints(int num, char *str, int *arr) { if (str == NULL || arr == NULL) { ALOGE("ERR(%s):str or arr is NULL", __func__); return false; } // ex : (-10,-10,0,0,300) char buf[128]; char *bracketsOpen; char *bracketsClose; char *tok; bracketsOpen = strchr(str, '('); if (bracketsOpen == NULL) { ALOGE("ERR(%s):no '('", __func__); return false; } bracketsClose = strchr(bracketsOpen, ')'); if (bracketsClose == NULL) { ALOGE("ERR(%s):no ')'", __func__); return false; } strncpy(buf, bracketsOpen + 1, bracketsClose - bracketsOpen + 1); buf[bracketsClose - bracketsOpen + 1] = 0; tok = strtok(buf, ","); if (tok == NULL) { ALOGE("ERR(%s):strtok(%s) fail", __func__, buf); return false; } arr[0] = atoi(tok); for (int i = 1; i < num; i++) { tok = strtok(NULL, ","); if (tok == NULL) { if (i < num - 1) { ALOGE("ERR(%s):strtok() (index : %d, num : %d) fail", __func__, i, num); return false; } break; } arr[i] = atoi(tok); } return true; } bool ExynosCameraHWInterface::m_getRatioSize(int src_w, int src_h, int dst_w, int dst_h, int *crop_x, int *crop_y, int *crop_w, int *crop_h, int zoom) { *crop_w = src_w; *crop_h = src_h; if ( src_w != dst_w || src_h != dst_h) { float src_ratio = 1.0f; float dst_ratio = 1.0f; // ex : 1024 / 768 src_ratio = (float)src_w / (float)src_h; // ex : 352 / 288 dst_ratio = (float)dst_w / (float)dst_h; if (src_ratio != dst_ratio) { if (dst_w * dst_h < src_w * src_h) { if (src_ratio <= dst_ratio) { // shrink h *crop_w = src_w; *crop_h = src_w / dst_ratio; } else { // shrink w *crop_w = dst_h * dst_ratio; *crop_h = dst_h; } } else { if (src_ratio <= dst_ratio) { // shrink h *crop_w = src_w; *crop_h = src_w / dst_ratio; } else { // shrink w *crop_w = src_h * dst_ratio; *crop_h = src_h; } } if (zoom != 0) { int zoomLevel = ((float)zoom + 10.0) / 10.0; *crop_w = (int)((float)*crop_w / zoomLevel); *crop_h = (int)((float)*crop_h / zoomLevel); } } } #define CAMERA_CROP_WIDTH_RESTRAIN_NUM (0x2) unsigned int w_align = (*crop_w & (CAMERA_CROP_WIDTH_RESTRAIN_NUM - 1)); if (w_align != 0) { if ( (CAMERA_CROP_WIDTH_RESTRAIN_NUM >> 1) <= w_align && *crop_w + (CAMERA_CROP_WIDTH_RESTRAIN_NUM - w_align) <= dst_w) { *crop_w += (CAMERA_CROP_WIDTH_RESTRAIN_NUM - w_align); } else *crop_w -= w_align; } #define CAMERA_CROP_HEIGHT_RESTRAIN_NUM (0x2) unsigned int h_align = (*crop_h & (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - 1)); if (h_align != 0) { if ( (CAMERA_CROP_HEIGHT_RESTRAIN_NUM >> 1) <= h_align && *crop_h + (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - h_align) <= dst_h) { *crop_h += (CAMERA_CROP_HEIGHT_RESTRAIN_NUM - h_align); } else *crop_h -= h_align; } *crop_x = (src_w - *crop_w) >> 1; *crop_y = (src_h - *crop_h) >> 1; if (*crop_x & (CAMERA_CROP_WIDTH_RESTRAIN_NUM >> 1)) *crop_x -= 1; if (*crop_y & (CAMERA_CROP_HEIGHT_RESTRAIN_NUM >> 1)) *crop_y -= 1; return true; } int ExynosCameraHWInterface::m_calibratePosition(int w, int new_w, int pos) { return (float)(pos * new_w) / (float)w; } static CameraInfo sCameraInfo[] = { { CAMERA_FACING_BACK, 0, /* orientation */ }, { CAMERA_FACING_FRONT, 0, /* orientation */ } }; /** Close this device */ static camera_device_t *g_cam_device; static int HAL_camera_device_close(struct hw_device_t* device) { ALOGV("DEBUG(%s):", __func__); if (device) { camera_device_t *cam_device = (camera_device_t *)device; delete static_cast<ExynosCameraHWInterface *>(cam_device->priv); free(cam_device); g_cam_device = 0; } return 0; } static inline ExynosCameraHWInterface *obj(struct camera_device *dev) { return reinterpret_cast<ExynosCameraHWInterface *>(dev->priv); } /** Set the preview_stream_ops to which preview frames are sent */ static int HAL_camera_device_set_preview_window(struct camera_device *dev, struct preview_stream_ops *buf) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->setPreviewWindow(buf); } /** Set the notification and data callbacks */ static void HAL_camera_device_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) { ALOGV("DEBUG(%s):", __func__); obj(dev)->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user); } /** * The following three functions all take a msg_type, which is a bitmask of * the messages defined in include/ui/Camera.h */ /** * Enable a message, or set of messages. */ static void HAL_camera_device_enable_msg_type(struct camera_device *dev, int32_t msg_type) { ALOGV("DEBUG(%s):", __func__); obj(dev)->enableMsgType(msg_type); } /** * Disable a message, or a set of messages. * * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera * HAL should not rely on its client to call releaseRecordingFrame() to * release video recording frames sent out by the cameral HAL before and * after the disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera HAL * clients must not modify/access any video recording frame after calling * disableMsgType(CAMERA_MSG_VIDEO_FRAME). */ static void HAL_camera_device_disable_msg_type(struct camera_device *dev, int32_t msg_type) { ALOGV("DEBUG(%s):", __func__); obj(dev)->disableMsgType(msg_type); } /** * Query whether a message, or a set of messages, is enabled. Note that * this is operates as an AND, if any of the messages queried are off, this * will return false. */ static int HAL_camera_device_msg_type_enabled(struct camera_device *dev, int32_t msg_type) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->msgTypeEnabled(msg_type); } /** * Start preview mode. */ static int HAL_camera_device_start_preview(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->startPreview(); } /** * Stop a previously started preview. */ static void HAL_camera_device_stop_preview(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); obj(dev)->stopPreview(); } /** * Returns true if preview is enabled. */ static int HAL_camera_device_preview_enabled(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->previewEnabled(); } /** * Request the camera HAL to store meta data or real YUV data in the video * buffers sent out via CAMERA_MSG_VIDEO_FRAME for a recording session. If * it is not called, the default camera HAL behavior is to store real YUV * data in the video buffers. * * This method should be called before startRecording() in order to be * effective. * * If meta data is stored in the video buffers, it is up to the receiver of * the video buffers to interpret the contents and to find the actual frame * data with the help of the meta data in the buffer. How this is done is * outside of the scope of this method. * * Some camera HALs may not support storing meta data in the video buffers, * but all camera HALs should support storing real YUV data in the video * buffers. If the camera HAL does not support storing the meta data in the * video buffers when it is requested to do do, INVALID_OPERATION must be * returned. It is very useful for the camera HAL to pass meta data rather * than the actual frame data directly to the video encoder, since the * amount of the uncompressed frame data can be very large if video size is * large. * * @param enable if true to instruct the camera HAL to store * meta data in the video buffers; false to instruct * the camera HAL to store real YUV data in the video * buffers. * * @return OK on success. */ static int HAL_camera_device_store_meta_data_in_buffers(struct camera_device *dev, int enable) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->storeMetaDataInBuffers(enable); } /** * Start record mode. When a record image is available, a * CAMERA_MSG_VIDEO_FRAME message is sent with the corresponding * frame. Every record frame must be released by a camera HAL client via * releaseRecordingFrame() before the client calls * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's * responsibility to manage the life-cycle of the video recording frames, * and the client must not modify/access any video recording frames. */ static int HAL_camera_device_start_recording(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->startRecording(); } /** * Stop a previously started recording. */ static void HAL_camera_device_stop_recording(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); obj(dev)->stopRecording(); } /** * Returns true if recording is enabled. */ static int HAL_camera_device_recording_enabled(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->recordingEnabled(); } /** * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. * * It is camera HAL client's responsibility to release video recording * frames sent out by the camera HAL before the camera HAL receives a call * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's * responsibility to manage the life-cycle of the video recording frames. */ static void HAL_camera_device_release_recording_frame(struct camera_device *dev, const void *opaque) { ALOGV("DEBUG(%s):", __func__); obj(dev)->releaseRecordingFrame(opaque); } /** * Start auto focus, the notification callback routine is called with * CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() will be * called again if another auto focus is needed. */ static int HAL_camera_device_auto_focus(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->autoFocus(); } /** * Cancels auto-focus function. If the auto-focus is still in progress, * this function will cancel it. Whether the auto-focus is in progress or * not, this function will return the focus position to the default. If * the camera does not support auto-focus, this is a no-op. */ static int HAL_camera_device_cancel_auto_focus(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->cancelAutoFocus(); } /** * Take a picture. */ static int HAL_camera_device_take_picture(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->takePicture(); } /** * Cancel a picture that was started with takePicture. Calling this method * when no picture is being taken is a no-op. */ static int HAL_camera_device_cancel_picture(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->cancelPicture(); } /** * Set the camera parameters. This returns BAD_VALUE if any parameter is * invalid or not supported. */ static int HAL_camera_device_set_parameters(struct camera_device *dev, const char *parms) { ALOGV("DEBUG(%s):", __func__); String8 str(parms); CameraParameters p(str); return obj(dev)->setParameters(p); } /** Return the camera parameters. */ char *HAL_camera_device_get_parameters(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); String8 str; CameraParameters parms = obj(dev)->getParameters(); str = parms.flatten(); return strdup(str.string()); } static void HAL_camera_device_put_parameters(struct camera_device *dev, char *parms) { ALOGV("DEBUG(%s):", __func__); free(parms); } /** * Send command to camera driver. */ static int HAL_camera_device_send_command(struct camera_device *dev, int32_t cmd, int32_t arg1, int32_t arg2) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->sendCommand(cmd, arg1, arg2); } /** * Release the hardware resources owned by this object. Note that this is * *not* done in the destructor. */ static void HAL_camera_device_release(struct camera_device *dev) { ALOGV("DEBUG(%s):", __func__); obj(dev)->release(); } /** * Dump state of the camera hardware */ static int HAL_camera_device_dump(struct camera_device *dev, int fd) { ALOGV("DEBUG(%s):", __func__); return obj(dev)->dump(fd); } static int HAL_getNumberOfCameras() { ALOGV("DEBUG(%s):", __func__); return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]); } static int HAL_getCameraInfo(int cameraId, struct camera_info *cameraInfo) { ALOGV("DEBUG(%s):", __func__); memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo)); return 0; } #define SET_METHOD(m) m : HAL_camera_device_##m static camera_device_ops_t camera_device_ops = { SET_METHOD(set_preview_window), SET_METHOD(set_callbacks), SET_METHOD(enable_msg_type), SET_METHOD(disable_msg_type), SET_METHOD(msg_type_enabled), SET_METHOD(start_preview), SET_METHOD(stop_preview), SET_METHOD(preview_enabled), SET_METHOD(store_meta_data_in_buffers), SET_METHOD(start_recording), SET_METHOD(stop_recording), SET_METHOD(recording_enabled), SET_METHOD(release_recording_frame), SET_METHOD(auto_focus), SET_METHOD(cancel_auto_focus), SET_METHOD(take_picture), SET_METHOD(cancel_picture), SET_METHOD(set_parameters), SET_METHOD(get_parameters), SET_METHOD(put_parameters), SET_METHOD(send_command), SET_METHOD(release), SET_METHOD(dump), }; #undef SET_METHOD static int HAL_camera_device_open(const struct hw_module_t* module, const char *id, struct hw_device_t** device) { ALOGV("DEBUG(%s):", __func__); int cameraId = atoi(id); if (cameraId < 0 || cameraId >= HAL_getNumberOfCameras()) { ALOGE("ERR(%s):Invalid camera ID %s", __func__, id); return -EINVAL; } if (g_cam_device) { if (obj(g_cam_device)->getCameraId() == cameraId) { ALOGV("DEBUG(%s):returning existing camera ID %s", __func__, id); goto done; } else { ALOGE("ERR(%s):Cannot open camera %d. camera %d is already running!", __func__, cameraId, obj(g_cam_device)->getCameraId()); return -ENOSYS; } } g_cam_device = (camera_device_t *)malloc(sizeof(camera_device_t)); if (!g_cam_device) return -ENOMEM; g_cam_device->common.tag = HARDWARE_DEVICE_TAG; g_cam_device->common.version = 1; g_cam_device->common.module = const_cast<hw_module_t *>(module); g_cam_device->common.close = HAL_camera_device_close; g_cam_device->ops = &camera_device_ops; ALOGV("DEBUG(%s):open camera %s", __func__, id); g_cam_device->priv = new ExynosCameraHWInterface(cameraId, g_cam_device); done: *device = (hw_device_t *)g_cam_device; ALOGV("DEBUG(%s):opened camera %s (%p)", __func__, id, *device); return 0; } static hw_module_methods_t camera_module_methods = { open : HAL_camera_device_open }; extern "C" { struct camera_module HAL_MODULE_INFO_SYM = { common : { tag : HARDWARE_MODULE_TAG, version_major : 1, version_minor : 0, id : CAMERA_HARDWARE_MODULE_ID, name : "orion camera HAL", author : "Samsung Corporation", methods : &camera_module_methods, }, get_number_of_cameras : HAL_getNumberOfCameras, get_camera_info : HAL_getCameraInfo }; } }; // namespace android