diff options
author | Iliyan Malchev <malchev@google.com> | 2011-08-08 11:24:41 -0700 |
---|---|---|
committer | Iliyan Malchev <malchev@google.com> | 2011-08-08 11:46:17 -0700 |
commit | a40968e9b9abcdcc042948ea73346b020279d4b7 (patch) | |
tree | 926da5b4447017617fcc255b490eaee5174a4a9a | |
parent | 8558b0909d3f42288f488e6fd1341877c639a594 (diff) | |
download | hardware_ti_omap4-a40968e9b9abcdcc042948ea73346b020279d4b7.zip hardware_ti_omap4-a40968e9b9abcdcc042948ea73346b020279d4b7.tar.gz hardware_ti_omap4-a40968e9b9abcdcc042948ea73346b020279d4b7.tar.bz2 |
initial commit
Change-Id: I8f7a7eeece0e516efa486b77e9d97805c0e65d3e
Signed-off-by: Iliyan Malchev <malchev@google.com>
93 files changed, 37622 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..2729bab --- /dev/null +++ b/Android.mk @@ -0,0 +1,34 @@ +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + +LOCAL_PATH:= $(call my-dir) +HARDWARE_TI_OMAP4_BASE:= $(LOCAL_PATH) +OMAP4_DEBUG_MEMLEAK:= false + +ifeq ($(OMAP4_DEBUG_MEMLEAK),true) + +OMAP4_DEBUG_CFLAGS:= -DHEAPTRACKER +OMAP4_DEBUG_LDFLAGS:= $(foreach f, $(strip malloc realloc calloc free), -Wl,--wrap=$(f)) +OMAP4_DEBUG_SHARED_LIBRARIES:= liblog +BUILD_HEAPTRACKED_SHARED_LIBRARY:= hardware/ti/omap4xxx/heaptracked-shared-library.mk +BUILD_HEAPTRACKED_EXECUTABLE:= hardware/ti/omap4xxx/heaptracked-executable.mk + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= heaptracker.c stacktrace.c mapinfo.c +LOCAL_MODULE:= libheaptracker +LOCAL_MODULE_TAGS:= optional +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= tm.c +LOCAL_MODULE:= tm +LOCAL_MODULE_TAGS:= test +include $(BUILD_HEAPTRACKED_EXECUTABLE) + +else +BUILD_HEAPTRACKED_SHARED_LIBRARY:=$(BUILD_SHARED_LIBRARY) +BUILD_HEAPTRACKED_EXECUTABLE:= $(BUILD_EXECUTABLE) +endif + +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/CleanSpec.mk b/CleanSpec.mk new file mode 100644 index 0000000..9450dc7 --- /dev/null +++ b/CleanSpec.mk @@ -0,0 +1,55 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/vendor/lib/hw/hwcomposer.omap4.so) +$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "lib*cameraadapter*" -print0 | xargs -0 rm -f) +$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libcamera.so" -print0 | xargs -0 rm -f) +$(call add-clean-step, find $(PRODUCT_OUT) -type d -name "libcamera_intermediates" -print0 | xargs -0 rm -rf) +$(call add-clean-step, find $(PRODUCT_OUT) -type d -name "lib*cameraadapter_intermediates" -print0 | xargs -0 rm -rf) diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_APACHE2 diff --git a/camera/ANativeWindowDisplayAdapter.cpp b/camera/ANativeWindowDisplayAdapter.cpp new file mode 100755 index 0000000..38e641f --- /dev/null +++ b/camera/ANativeWindowDisplayAdapter.cpp @@ -0,0 +1,1096 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + + + +#define LOG_TAG "CameraHAL" + +#include "ANativeWindowDisplayAdapter.h" +#include <OMX_IVCommon.h> +#include <ui/GraphicBufferMapper.h> +#include <hal_public.h> + +namespace android { + +///Constant declarations +///@todo Check the time units +const int ANativeWindowDisplayAdapter::DISPLAY_TIMEOUT = 1000; // seconds + +//Suspends buffers after given amount of failed dq's +const int ANativeWindowDisplayAdapter::FAILED_DQS_TO_SUSPEND = 3; + + + +OMX_COLOR_FORMATTYPE toOMXPixFormat(const char* parameters_format) +{ + OMX_COLOR_FORMATTYPE pixFormat; + + if ( parameters_format != NULL ) + { + if (strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) + { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + } + else + { + CAMHAL_LOGDA("Invalid format, CbYCrY format selected as default"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + } + else { + CAMHAL_LOGEA("Preview format is NULL, defaulting to CbYCrY"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + + return pixFormat; +} + +const char* getPixFormatConstant(const char* parameters_format) +{ + const char* pixFormat; + + if ( parameters_format != NULL ) + { + if (strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGVA("CbYCrY format selected"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV422I; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_YUV420P) == 0) + { + // TODO(XXX): We are treating YV12 the same as YUV420SP + CAMHAL_LOGVA("YUV420SP format selected"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP; + } + else if(strcmp(parameters_format, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGVA("RGB565 format selected"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_RGB565; + } + else + { + CAMHAL_LOGEA("Invalid format, CbYCrY format selected as default"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV422I; + } + } + else + { + CAMHAL_LOGEA("Preview format is NULL, defaulting to CbYCrY"); + pixFormat = (const char *) CameraParameters::PIXEL_FORMAT_YUV422I; + } + + return pixFormat; +} + +const size_t getBufSize(const char* parameters_format, int width, int height) +{ + int buf_size; + + if ( parameters_format != NULL ) { + if (strcmp(parameters_format, + (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + buf_size = width * height * 2; + } + else if((strcmp(parameters_format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) || + (strcmp(parameters_format, CameraParameters::PIXEL_FORMAT_YUV420P) == 0)) { + buf_size = width * height * 3 / 2; + } + else if(strcmp(parameters_format, + (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + buf_size = width * height * 2; + } else { + CAMHAL_LOGEA("Invalid format"); + buf_size = 0; + } + } else { + CAMHAL_LOGEA("Preview format is NULL"); + buf_size = 0; + } + + return buf_size; +} +/*--------------------ANativeWindowDisplayAdapter Class STARTS here-----------------------------*/ + + +/** + * Display Adapter class STARTS here.. + */ +ANativeWindowDisplayAdapter::ANativeWindowDisplayAdapter():mDisplayThread(NULL), + mDisplayState(ANativeWindowDisplayAdapter::DISPLAY_INIT), + mDisplayEnabled(false), + mBufferCount(0) + + + +{ + LOG_FUNCTION_NAME; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + mShotToShot = false; + mStartCapture.tv_sec = 0; + mStartCapture.tv_usec = 0; + mStandbyToShot.tv_sec = 0; + mStandbyToShot.tv_usec = 0; + mMeasureStandby = false; +#endif + + mPixelFormat = NULL; + mBufferHandleMap = NULL; + mGrallocHandleMap = NULL; + mOffsetsMap = NULL; + mFrameProvider = NULL; + + mFrameWidth = 0; + mFrameHeight = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + + mSuspend = false; + mFailedDQs = 0; + + mPaused = false; + mXOff = 0; + mYOff = 0; + mFirstInit = false; + + mFD = -1; + + LOG_FUNCTION_NAME_EXIT; +} + +ANativeWindowDisplayAdapter::~ANativeWindowDisplayAdapter() +{ + Semaphore sem; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + ///If Frame provider exists + if(mFrameProvider) + { + // Unregister with the frame provider + mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES); + } + + ///The ANativeWindow object will get destroyed here + destroy(); + + ///If Display thread exists + if(mDisplayThread.get()) + { + ///Kill the display thread + sem.Create(); + msg.command = DisplayThread::DISPLAY_EXIT; + + // Send the semaphore to signal once the command is completed + msg.arg1 = &sem; + + ///Post the message to display thread + mDisplayThread->msgQ().put(&msg); + + ///Wait for the ACK - implies that the thread is now started and waiting for frames + sem.Wait(); + + // Exit and cleanup the thread + mDisplayThread->requestExitAndWait(); + + // Delete the display thread + mDisplayThread.clear(); + } + + LOG_FUNCTION_NAME_EXIT; + +} + +status_t ANativeWindowDisplayAdapter::initialize() +{ + LOG_FUNCTION_NAME; + + ///Create the display thread + mDisplayThread = new DisplayThread(this); + if ( !mDisplayThread.get() ) + { + CAMHAL_LOGEA("Couldn't create display thread"); + LOG_FUNCTION_NAME_EXIT; + return NO_MEMORY; + } + + ///Start the display thread + status_t ret = mDisplayThread->run("DisplayThread", PRIORITY_URGENT_DISPLAY); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEA("Couldn't run display thread"); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +int ANativeWindowDisplayAdapter::setPreviewWindow(preview_stream_ops_t* window) +{ + LOG_FUNCTION_NAME; + ///Note that Display Adapter cannot work without a valid window object + if ( !window) + { + CAMHAL_LOGEA("NULL window object passed to DisplayAdapter"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + ///Destroy the existing window object, if it exists + destroy(); + + ///Move to new window obj + mANativeWindow = window; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int ANativeWindowDisplayAdapter::setFrameProvider(FrameNotifier *frameProvider) +{ + LOG_FUNCTION_NAME; + + // Check for NULL pointer + if ( !frameProvider ) + { + CAMHAL_LOGEA("NULL passed for frame provider"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + /** Dont do anything here, Just save the pointer for use when display is + actually enabled or disabled + */ + mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int ANativeWindowDisplayAdapter::setErrorHandler(ErrorNotifier *errorNotifier) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL == errorNotifier ) + { + CAMHAL_LOGEA("Invalid Error Notifier reference"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + mErrorNotifier = errorNotifier; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +status_t ANativeWindowDisplayAdapter::setSnapshotTimeRef(struct timeval *refTime) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL != refTime ) + { + Mutex::Autolock lock(mLock); + memcpy(&mStartCapture, refTime, sizeof(struct timeval)); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +#endif + + +int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams) +{ + Semaphore sem; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + if ( mDisplayEnabled ) + { + CAMHAL_LOGDA("Display is already enabled"); + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + } + +#if 0 //TODO: s3d is not part of bringup...will reenable + if (s3dParams) + mOverlay->set_s3d_params(s3dParams->mode, s3dParams->framePacking, + s3dParams->order, s3dParams->subSampling); +#endif + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + if ( NULL != refTime ) + { + Mutex::Autolock lock(mLock); + memcpy(&mStandbyToShot, refTime, sizeof(struct timeval)); + mMeasureStandby = true; + } + +#endif + + //Send START_DISPLAY COMMAND to display thread. Display thread will start and then wait for a message + sem.Create(); + msg.command = DisplayThread::DISPLAY_START; + + // Send the semaphore to signal once the command is completed + msg.arg1 = &sem; + + ///Post the message to display thread + mDisplayThread->msgQ().put(&msg); + + ///Wait for the ACK - implies that the thread is now started and waiting for frames + sem.Wait(); + + // Register with the frame provider for frames + mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + + mDisplayEnabled = true; + mPreviewWidth = width; + mPreviewHeight = height; + + CAMHAL_LOGVB("mPreviewWidth = %d mPreviewHeight = %d", mPreviewWidth, mPreviewHeight); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +int ANativeWindowDisplayAdapter::disableDisplay() +{ + LOG_FUNCTION_NAME; + + if(!mDisplayEnabled) + { + CAMHAL_LOGDA("Display is already disabled"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + + // Unregister with the frame provider here + mFrameProvider->disableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + + if ( NULL != mDisplayThread.get() ) + { + //Send STOP_DISPLAY COMMAND to display thread. Display thread will stop and dequeue all messages + // and then wait for message + Semaphore sem; + sem.Create(); + TIUTILS::Message msg; + msg.command = DisplayThread::DISPLAY_STOP; + + // Send the semaphore to signal once the command is completed + msg.arg1 = &sem; + + ///Post the message to display thread + mDisplayThread->msgQ().put(&msg); + + ///Wait for the ACK for display to be disabled + + sem.Wait(); + + } + + Mutex::Autolock lock(mLock); + { + ///Reset the display enabled flag + mDisplayEnabled = false; + + ///Reset the offset values + mXOff = 0; + mYOff = 0; + + ///Reset the frame width and height values + mFrameWidth =0; + mFrameHeight = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + + + if (mANativeWindow) + for(unsigned int i = 0; i < mFramesWithCameraAdapterMap.size(); i++) { + int value = mFramesWithCameraAdapterMap.valueAt(i); + mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[value]); + } + else + LOGE("mANativeWindow is NULL"); + + ///Clear the frames with camera adapter map + mFramesWithCameraAdapterMap.clear(); + } + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +status_t ANativeWindowDisplayAdapter::pauseDisplay(bool pause) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + { + Mutex::Autolock lock(mLock); + mPaused = pause; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + +void ANativeWindowDisplayAdapter::destroy() +{ + LOG_FUNCTION_NAME; + + ///Check if the display is disabled, if not disable it + if ( mDisplayEnabled ) + { + CAMHAL_LOGDA("WARNING: Calling destroy of Display adapter when display enabled. Disabling display.."); + disableDisplay(); + } + + mBufferCount = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +// Implementation of inherited interfaces +void* ANativeWindowDisplayAdapter::allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs) +{ + LOG_FUNCTION_NAME; + status_t err; + int i = -1; + const int lnumBufs = numBufs; + int32_t *buffers = new int32_t[lnumBufs]; + mBufferHandleMap = new buffer_handle_t*[lnumBufs]; + mGrallocHandleMap = new IMG_native_handle_t*[lnumBufs]; + int undequeued = 0; + + // Set gralloc usage bits for window. + err = mANativeWindow->set_usage(mANativeWindow, GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN + | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); + if (err != 0) { + LOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); + return NULL; + } + + CAMHAL_LOGDB("Number of buffers set to ANativeWindow %d", numBufs); + //if(mBufferCount != numBufs) + // { + ///Set the number of buffers needed for camera preview + err = mANativeWindow->set_buffer_count(mANativeWindow, numBufs); + if (err != 0) { + LOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err); + return NULL; + } + CAMHAL_LOGDB("Configuring %d buffers for ANativeWindow", numBufs); + mBufferCount = numBufs; + //} + + // Set window geometry + err = mANativeWindow->set_buffers_geometry( + mANativeWindow, + width, + height, + /*toOMXPixFormat(format)*/HAL_PIXEL_FORMAT_NV12); // Gralloc only supports NV12 alloc! + + if (err != 0) { + LOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err); + return NULL; + } + + ///We just return the buffers from ANativeWindow, if the width and height are same, else (vstab, vnf case) + ///re-allocate buffers using ANativeWindow and then get them + ///@todo - Re-allocate buffers for vnf and vstab using the width, height, format, numBufs etc + if ( (buffers == NULL) || (mBufferHandleMap == NULL) ) + { + CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers"); + LOG_FUNCTION_NAME_EXIT; + delete [] buffers; + return NULL; + } + + mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeued); + + for ( i=0; i < mBufferCount; i++ ) + { + IMG_native_handle_t** hndl2hndl; + IMG_native_handle_t* handle; + int stride; // dummy variable to get stride + // TODO(XXX): Do we need to keep stride information in camera hal? + + err = mANativeWindow->dequeue_buffer(mANativeWindow, (buffer_handle_t**) &hndl2hndl, &stride); + + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + goto fail; + } + + handle = *hndl2hndl; + + mBufferHandleMap[i] = (buffer_handle_t*) hndl2hndl; + mGrallocHandleMap[i] = handle; + mFramesWithCameraAdapterMap.add((int) mGrallocHandleMap[i], i); + + bytes = getBufSize(format, width, height); + + CAMHAL_LOGDB("Adding buffer index=%d, address=0x%x", i, buffers[i]); + } + + + // lock the initial queueable buffers + for( i = 0; i < mBufferCount-undequeued; i++ ) + { + mANativeWindow->lock_buffer(mANativeWindow, mBufferHandleMap[i]); + } + + // return the rest of the buffers back to ANativeWindow + for(i = (mBufferCount-undequeued); i >= 0 && i < mBufferCount; i++) + { + mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]); + } + + mFirstInit = true; + mPixelFormat = getPixFormatConstant(format); + mFrameWidth = width; + mFrameHeight = height; + + return mGrallocHandleMap; + + fail: + // need to cancel buffers if any were dequeued + for (int start = 0; start < i && i > 0; start++) { + int err = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[start]); + if (err != 0) { + CAMHAL_LOGEB("cancelBuffer failed w/ error 0x%08x", err); + } + } + CAMHAL_LOGEA("Error occurred, performing cleanup"); + if ( buffers ) + { + delete [] buffers; + } + + if ( NULL != mErrorNotifier.get() ) + { + mErrorNotifier->errorNotify(-ENOMEM); + } + + LOG_FUNCTION_NAME_EXIT; + return NULL; + +} + +uint32_t * ANativeWindowDisplayAdapter::getOffsets() +{ + const int lnumBufs = mBufferCount; + + LOG_FUNCTION_NAME; + + // TODO(XXX): Need to remove getOffsets from the API. No longer needed + + if ( NULL == mANativeWindow ) + { + CAMHAL_LOGEA("mANativeWindow reference is missing"); + goto fail; + } + + if( mBufferHandleMap == NULL) + { + CAMHAL_LOGEA("Buffers not allocated yet!!"); + goto fail; + } + + if(mOffsetsMap == NULL) + { + mOffsetsMap = new uint32_t[lnumBufs]; + for(int i = 0; i < mBufferCount; i++) + { + IMG_native_handle_t* handle = (IMG_native_handle_t*) *(mBufferHandleMap[i]); + mOffsetsMap[i] = 0; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return mOffsetsMap; + + fail: + + if ( NULL != mOffsetsMap ) + { + delete [] mOffsetsMap; + mOffsetsMap = NULL; + } + + if ( NULL != mErrorNotifier.get() ) + { + mErrorNotifier->errorNotify(-ENOSYS); + } + + LOG_FUNCTION_NAME_EXIT; + + return NULL; +} + +int ANativeWindowDisplayAdapter::maxQueueableBuffers(unsigned int& queueable) +{ + LOG_FUNCTION_NAME; + int ret = NO_ERROR; + int undequeued = 0; + + if(mBufferCount == 0) + { + ret = -ENOSYS; + goto end; + } + + if(!mANativeWindow) + { + ret = -ENOSYS; + goto end; + } + + mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeued); + + queueable = mBufferCount - undequeued; + + end: + return ret; + LOG_FUNCTION_NAME_EXIT; +} + +int ANativeWindowDisplayAdapter::getFd() +{ + LOG_FUNCTION_NAME; + + if(mFD == -1) + { + IMG_native_handle_t* handle = (IMG_native_handle_t*) *(mBufferHandleMap[0]); + // TODO: should we dup the fd? not really necessary and another thing for ANativeWindow + // to manage and close... + mFD = dup(handle->fd[0]); + } + + LOG_FUNCTION_NAME_EXIT; + + return mFD; + +} + +int ANativeWindowDisplayAdapter::freeBuffer(void* buf) +{ + LOG_FUNCTION_NAME; + + int *buffers = (int *) buf; + if((int *)mGrallocHandleMap != buffers) + { + CAMHAL_LOGEA("CameraHal passed wrong set of buffers to free!!!"); + if (mGrallocHandleMap != NULL) + delete []mGrallocHandleMap; + mGrallocHandleMap = NULL; + } + + if ( NULL != buf ) + { + delete [] buffers; + } + + if( mBufferHandleMap != NULL) + { + delete [] mBufferHandleMap; + mBufferHandleMap = NULL; + } + + if ( NULL != mOffsetsMap ) + { + delete [] mOffsetsMap; + mOffsetsMap = NULL; + } + + if( mFD != -1) + { + close(mFD); // close duped handle + mFD = -1; + } + + return NO_ERROR; +} + + +bool ANativeWindowDisplayAdapter::supportsExternalBuffering() +{ + return false; +} + +int ANativeWindowDisplayAdapter::useBuffers(void *bufArr, int num) +{ + return NO_ERROR; +} + +void ANativeWindowDisplayAdapter::displayThread() +{ + bool shouldLive = true; + int timeout = 0; + status_t ret; + + LOG_FUNCTION_NAME; + + while(shouldLive) + { + ret = TIUTILS::MessageQueue::waitForMsg(&mDisplayThread->msgQ() + , &mDisplayQ + , NULL + , ANativeWindowDisplayAdapter::DISPLAY_TIMEOUT); + + if ( !mDisplayThread->msgQ().isEmpty() ) + { + ///Received a message from CameraHal, process it + shouldLive = processHalMsg(); + + } + else if( !mDisplayQ.isEmpty()) + { + if ( mDisplayState== ANativeWindowDisplayAdapter::DISPLAY_INIT ) + { + + ///If display adapter is not started, continue + continue; + + } + else + { + TIUTILS::Message msg; + ///Get the dummy msg from the displayQ + if(mDisplayQ.get(&msg)!=NO_ERROR) + { + CAMHAL_LOGEA("Error in getting message from display Q"); + continue; + } + + // There is a frame from ANativeWindow for us to dequeue + // We dequeue and return the frame back to Camera adapter + if(mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED) + { + handleFrameReturn(); + } + + if (mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_EXITED) + { + ///we exit the thread even though there are frames still to dequeue. They will be dequeued + ///in disableDisplay + shouldLive = false; + } + } + } + } + + LOG_FUNCTION_NAME_EXIT; +} + + +bool ANativeWindowDisplayAdapter::processHalMsg() +{ + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + + mDisplayThread->msgQ().get(&msg); + bool ret = true, invalidCommand = false; + + switch ( msg.command ) + { + + case DisplayThread::DISPLAY_START: + + CAMHAL_LOGDA("Display thread received DISPLAY_START command from Camera HAL"); + mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_STARTED; + + break; + + case DisplayThread::DISPLAY_STOP: + + ///@bug There is no API to disable SF without destroying it + ///@bug Buffers might still be w/ display and will get displayed + ///@remarks Ideal seqyence should be something like this + ///mOverlay->setParameter("enabled", false); + CAMHAL_LOGDA("Display thread received DISPLAY_STOP command from Camera HAL"); + mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_STOPPED; + + break; + + case DisplayThread::DISPLAY_EXIT: + + CAMHAL_LOGDA("Display thread received DISPLAY_EXIT command from Camera HAL."); + CAMHAL_LOGDA("Stopping display thread..."); + mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_EXITED; + ///Note that the SF can have pending buffers when we disable the display + ///This is normal and the expectation is that they may not be displayed. + ///This is to ensure that the user experience is not impacted + ret = false; + break; + + default: + + CAMHAL_LOGEB("Invalid Display Thread Command 0x%x.", msg.command); + invalidCommand = true; + + break; + } + + ///Signal the semaphore if it is sent as part of the message + if ( ( msg.arg1 ) && ( !invalidCommand ) ) + { + + CAMHAL_LOGDA("+Signalling display semaphore"); + Semaphore &sem = *((Semaphore*)msg.arg1); + + sem.Signal(); + + CAMHAL_LOGDA("-Signalling display semaphore"); + } + + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +status_t ANativeWindowDisplayAdapter::PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame) +{ + status_t ret = NO_ERROR; + uint32_t actualFramesWithDisplay = 0; + android_native_buffer_t *buffer = NULL; + int i; + + ///@todo Do cropping based on the stabilized frame coordinates + ///@todo Insert logic to drop frames here based on refresh rate of + ///display or rendering rate whichever is lower + ///Queue the buffer to overlay + for ( i = 0; i < mBufferCount; i++ ) + { + if ( ((int) dispFrame.mBuffer ) == (int)mGrallocHandleMap[i] ) + { + break; + } + } + + if ( mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED && + (!mPaused || CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) && + !mSuspend) + { + Mutex::Autolock lock(mLock); + uint32_t xOff = (dispFrame.mOffset% PAGE_SIZE); + uint32_t yOff = (dispFrame.mOffset / PAGE_SIZE); + + // Set crop only if current x and y offsets do not match with frame offsets + if((mXOff!=xOff) || (mYOff!=yOff)) + { + CAMHAL_LOGDB("Offset %d xOff = %d, yOff = %d", dispFrame.mOffset, xOff, yOff); + uint8_t bytesPerPixel; + ///Calculate bytes per pixel based on the pixel format + if(strcmp(mPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + bytesPerPixel = 2; + } + else if(strcmp(mPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + bytesPerPixel = 2; + } + else if(strcmp(mPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) + { + bytesPerPixel = 1; + } + else + { + bytesPerPixel = 1; + } + + CAMHAL_LOGVB(" crop.left = %d crop.top = %d crop.right = %d crop.bottom = %d", + xOff/bytesPerPixel, yOff , (xOff/bytesPerPixel)+mPreviewWidth, yOff+mPreviewHeight); + // We'll ignore any errors here, if the surface is + // already invalid, we'll know soon enough. + mANativeWindow->set_crop(mANativeWindow, xOff/bytesPerPixel, yOff, + (xOff/bytesPerPixel)+mPreviewWidth, yOff+mPreviewHeight); + + ///Update the current x and y offsets + mXOff = xOff; + mYOff = yOff; + } + + ret = mANativeWindow->enqueue_buffer(mANativeWindow, mBufferHandleMap[i]); + if (ret != 0) { + LOGE("Surface::queueBuffer returned error %d", ret); + } + + mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer); + + + // HWComposer has not minimum buffer requirement. We should be able to dequeue + // the buffer immediately + TIUTILS::Message msg; + mDisplayQ.put(&msg); + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + if ( mMeasureStandby ) + { + CameraHal::PPM("Standby to first shot: Sensor Change completed - ", &mStandbyToShot); + mMeasureStandby = false; + } + else if (CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) + { + CameraHal::PPM("Shot to snapshot: ", &mStartCapture); + mShotToShot = true; + } + else if ( mShotToShot ) + { + CameraHal::PPM("Shot to shot: ", &mStartCapture); + mShotToShot = false; + } +#endif + + } + else + { + Mutex::Autolock lock(mLock); + // cancel buffer and dequeue another one + ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]); + if (ret != 0) { + LOGE("Surface::queueBuffer returned error %d", ret); + } + + mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer); + + TIUTILS::Message msg; + mDisplayQ.put(&msg); + ret = NO_ERROR; + } + + return ret; +} + + +bool ANativeWindowDisplayAdapter::handleFrameReturn() +{ + status_t err; + buffer_handle_t* buf; + int i = 0; + int stride; // dummy variable to get stride + // TODO(XXX): Do we need to keep stride information in camera hal? + + err = mANativeWindow->dequeue_buffer(mANativeWindow, &buf, &stride); + if (err != 0) { + CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err); + } + + err = mANativeWindow->lock_buffer(mANativeWindow, buf); + if (err != 0) { + CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err); + } + + for(i = 0; i < mBufferCount; i++) + { + if (mBufferHandleMap[i] == buf) + break; + } + + mFramesWithCameraAdapterMap.add((int) mGrallocHandleMap[i], i); + + CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount-1); + mFrameProvider->returnFrame( (void*)mGrallocHandleMap[i], CameraFrame::PREVIEW_FRAME_SYNC); + return true; +} + +void ANativeWindowDisplayAdapter::frameCallbackRelay(CameraFrame* caFrame) +{ + + if ( NULL != caFrame ) + { + if ( NULL != caFrame->mCookie ) + { + ANativeWindowDisplayAdapter *da = (ANativeWindowDisplayAdapter*) caFrame->mCookie; + da->frameCallback(caFrame); + } + else + { + CAMHAL_LOGEB("Invalid Cookie in Camera Frame = %p, Cookie = %p", caFrame, caFrame->mCookie); + } + } + else + { + CAMHAL_LOGEB("Invalid Camera Frame = %p", caFrame); + } + +} + +void ANativeWindowDisplayAdapter::frameCallback(CameraFrame* caFrame) +{ + ///Call queueBuffer of overlay in the context of the callback thread + DisplayFrame df; + df.mBuffer = caFrame->mBuffer; + df.mType = (CameraFrame::FrameType) caFrame->mFrameType; + df.mOffset = caFrame->mOffset; + df.mWidthStride = caFrame->mAlignment; + df.mLength = caFrame->mLength; + df.mWidth = caFrame->mWidth; + df.mHeight = caFrame->mHeight; + PostFrame(df); +} + + +/*--------------------ANativeWindowDisplayAdapter Class ENDS here-----------------------------*/ + +}; + diff --git a/camera/Android.mk b/camera/Android.mk new file mode 100644 index 0000000..0e2bb8c --- /dev/null +++ b/camera/Android.mk @@ -0,0 +1,131 @@ +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + +LOCAL_PATH:= $(call my-dir) + +OMAP4_CAMERA_HAL_USES:= OMX +# OMAP4_CAMERA_HAL_USES:= USB + +OMAP4_CAMERA_HAL_SRC := \ + CameraHal_Module.cpp \ + CameraHal.cpp \ + CameraHalUtilClasses.cpp \ + AppCallbackNotifier.cpp \ + ANativeWindowDisplayAdapter.cpp \ + CameraProperties.cpp \ + MemoryManager.cpp \ + SensorListener.cpp + +OMAP4_CAMERA_COMMON_SRC:= \ + CameraParameters.cpp \ + TICameraParameters.cpp \ + CameraHalCommon.cpp + +OMAP4_CAMERA_OMX_SRC:= \ + BaseCameraAdapter.cpp \ + OMXCameraAdapter/OMX3A.cpp \ + OMXCameraAdapter/OMXAlgo.cpp \ + OMXCameraAdapter/OMXCameraAdapter.cpp \ + OMXCameraAdapter/OMXCapabilities.cpp \ + OMXCameraAdapter/OMXCapture.cpp \ + OMXCameraAdapter/OMXDefaults.cpp \ + OMXCameraAdapter/OMXExif.cpp \ + OMXCameraAdapter/OMXFD.cpp \ + OMXCameraAdapter/OMXFocus.cpp \ + OMXCameraAdapter/OMXZoom.cpp \ + +OMAP4_CAMERA_USB_SRC:= \ + BaseCameraAdapter.cpp \ + V4LCameraAdapter/V4LCameraAdapter.cpp + +# +# OMX Camera HAL +# + +ifeq ($(OMAP4_CAMERA_HAL_USES),OMX) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + $(OMAP4_CAMERA_HAL_SRC) \ + $(OMAP4_CAMERA_OMX_SRC) \ + $(OMAP4_CAMERA_COMMON_SRC) + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/inc/ \ + $(LOCAL_PATH)/../hwc \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/inc/OMXCameraAdapter \ + $(LOCAL_PATH)/../libtiutils \ + hardware/ti/omap4xxx/tiler \ + frameworks/base/include/ui \ + frameworks/base/include/utils \ + hardware/ti/omap4xxx/domx/omx_core/inc \ + hardware/ti/omap4xxx/domx/mm_osal/inc \ + frameworks/base/include/media/stagefright \ + frameworks/base/include/media/stagefright/openmax + +LOCAL_SHARED_LIBRARIES:= \ + libui \ + libbinder \ + libutils \ + libcutils \ + libtiutils \ + libmm_osal \ + libOMX_Core \ + libtimemmgr \ + libcamera_client \ + libgui \ + libdomx + +LOCAL_CFLAGS := -fno-short-enums -DCOPY_IMAGE_BUFFER + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE:= camera.$(TARGET_BOARD_PLATFORM) +LOCAL_MODULE_TAGS:= optional + +include $(BUILD_HEAPTRACKED_SHARED_LIBRARY) + +else +ifeq ($(OMAP4_CAMERA_HAL_USES),USB) + +# +# USB Camera Adapter +# + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + $(OMAP4_CAMERA_HAL_SRC) \ + $(OMAP4_CAMERA_USB_SRC) \ + $(OMAP4_CAMERA_COMMON_SRC) + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/inc/ \ + $(LOCAL_PATH)/../hwc \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/inc/V4LCameraAdapter \ + $(LOCAL_PATH)/../libtiutils \ + hardware/ti/omap4xxx/tiler \ + frameworks/base/include/ui \ + frameworks/base/include/utils \ + frameworks/base/include/media/stagefright/openmax + +LOCAL_SHARED_LIBRARIES:= \ + libui \ + libbinder \ + libutils \ + libcutils \ + libtiutils \ + libtimemmgr \ + libcamera_client + +LOCAL_CFLAGS := -fno-short-enums -DCOPY_IMAGE_BUFFER + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE:= camera.$(TARGET_BOARD_PLATFORM) +LOCAL_MODULE_TAGS:= optional + +include $(BUILD_HEAPTRACKED_SHARED_LIBRARY) +endif +endif +endif diff --git a/camera/AppCallbackNotifier.cpp b/camera/AppCallbackNotifier.cpp new file mode 100644 index 0000000..d266cc2 --- /dev/null +++ b/camera/AppCallbackNotifier.cpp @@ -0,0 +1,1399 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + + + +#define LOG_TAG "CameraHAL" + + +#include "CameraHal.h" +#include "VideoMetadata.h" +#include <MetadataBufferType.h> +#include <ui/GraphicBuffer.h> +#include <ui/GraphicBufferMapper.h> + + +namespace android { + +const int AppCallbackNotifier::NOTIFIER_TIMEOUT = -1; + +/*--------------------NotificationHandler Class STARTS here-----------------------------*/ + +/** + * NotificationHandler class + */ + + +///Initialization function for AppCallbackNotifier +status_t AppCallbackNotifier::initialize() +{ + LOG_FUNCTION_NAME; + + mMeasurementEnabled = false; + + ///Create the app notifier thread + mNotificationThread = new NotificationThread(this); + if(!mNotificationThread.get()) + { + CAMHAL_LOGEA("Couldn't create Notification thread"); + return NO_MEMORY; + } + + ///Start the display thread + status_t ret = mNotificationThread->run("NotificationThread", PRIORITY_URGENT_DISPLAY); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEA("Couldn't run NotificationThread"); + mNotificationThread.clear(); + return ret; + } + + mUseMetaDataBufferMode = true; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void AppCallbackNotifier::setCallbacks(CameraHal* cameraHal, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + Mutex::Autolock lock(mLock); + + LOG_FUNCTION_NAME; + + mCameraHal = cameraHal; + mNotifyCb = notify_cb; + mDataCb = data_cb; + mDataCbTimestamp = data_cb_timestamp; + mRequestMemory = get_memory; + mCallbackCookie = user; + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::setMeasurements(bool enable) +{ + Mutex::Autolock lock(mLock); + + LOG_FUNCTION_NAME; + + mMeasurementEnabled = enable; + + if ( enable ) + { + mFrameProvider->enableFrameNotification(CameraFrame::FRAME_DATA_SYNC); + } + + LOG_FUNCTION_NAME_EXIT; +} + + +//All sub-components of Camera HAL call this whenever any error happens +void AppCallbackNotifier::errorNotify(int error) +{ + LOG_FUNCTION_NAME; + + CAMHAL_LOGEB("AppCallbackNotifier received error %d", error); + + ///Notify errors to application in callback thread. Post error event to event queue + TIUTILS::Message msg; + msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_ERROR; + msg.arg1 = (void*)error; + + mEventQ.put(&msg); + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::notificationThread() +{ + bool shouldLive = true; + status_t ret; + + LOG_FUNCTION_NAME; + + while(shouldLive) + { + //CAMHAL_LOGDA("Notification Thread waiting for message"); + ret = TIUTILS::MessageQueue::waitForMsg(&mNotificationThread->msgQ(), + &mEventQ, + &mFrameQ, + AppCallbackNotifier::NOTIFIER_TIMEOUT); + + //CAMHAL_LOGDA("Notification Thread received message"); + + if(mNotificationThread->msgQ().hasMsg()) + { + ///Received a message from CameraHal, process it + CAMHAL_LOGDA("Notification Thread received message from Camera HAL"); + shouldLive = processMessage(); + if(!shouldLive) + { + CAMHAL_LOGDA("Notification Thread exiting."); + } + } + if(mEventQ.hasMsg()) + { + ///Received an event from one of the event providers + CAMHAL_LOGDA("Notification Thread received an event from event provider (CameraAdapter)"); + notifyEvent(); + } + if(mFrameQ.hasMsg()) + { + ///Received a frame from one of the frame providers + //CAMHAL_LOGDA("Notification Thread received a frame from frame provider (CameraAdapter)"); + notifyFrame(); + } + } + + CAMHAL_LOGDA("Notification Thread exited."); + LOG_FUNCTION_NAME_EXIT; + +} + +void AppCallbackNotifier::notifyEvent() +{ + ///Receive and send the event notifications to app + TIUTILS::Message msg; + LOG_FUNCTION_NAME; + mEventQ.get(&msg); + bool ret = true; + CameraHalEvent *evt = NULL; + CameraHalEvent::FocusEventData *focusEvtData; + CameraHalEvent::ZoomEventData *zoomEvtData; + CameraHalEvent::FaceEventData faceEvtData; + + if(mNotifierState != AppCallbackNotifier::NOTIFIER_STARTED) + { + return; + } + + switch(msg.command) + { + case AppCallbackNotifier::NOTIFIER_CMD_PROCESS_EVENT: + + evt = ( CameraHalEvent * ) msg.arg1; + + if ( NULL == evt ) + { + CAMHAL_LOGEA("Invalid CameraHalEvent"); + return; + } + + switch(evt->mEventType) + { + case CameraHalEvent::EVENT_SHUTTER: + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb ) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_SHUTTER) ) ) + { + mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie); + } + + break; + + case CameraHalEvent::EVENT_FOCUS_LOCKED: + case CameraHalEvent::EVENT_FOCUS_ERROR: + + focusEvtData = &evt->mEventData->focusEvent; + if ( ( focusEvtData->focusLocked ) && + ( NULL != mCameraHal ) && + ( NULL != mNotifyCb ) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_FOCUS) ) ) + { + mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie); + } + else if ( focusEvtData->focusError && + ( NULL != mCameraHal ) && + ( NULL != mNotifyCb ) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_FOCUS) ) ) + { + mNotifyCb(CAMERA_MSG_FOCUS, false, 0, mCallbackCookie); + } + + break; + + case CameraHalEvent::EVENT_ZOOM_INDEX_REACHED: + + zoomEvtData = &evt->mEventData->zoomEvent; + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_ZOOM) ) ) + { + mNotifyCb(CAMERA_MSG_ZOOM, zoomEvtData->currentZoomIndex, zoomEvtData->targetZoomIndexReached, mCallbackCookie); + } + + break; + + case CameraHalEvent::EVENT_FACE: + + faceEvtData = evt->mEventData->faceEvent; + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_METADATA) ) ) + { + // WA for an issue inside CameraService + camera_memory_t *tmpBuffer = mRequestMemory(-1, 1, 1, NULL); + + mDataCb(CAMERA_MSG_PREVIEW_METADATA, + tmpBuffer, + 0, + faceEvtData->getFaceResult(), + mCallbackCookie); + + faceEvtData.clear(); + + if ( NULL != tmpBuffer ) { + tmpBuffer->release(tmpBuffer); + } + + } + + break; + + case CameraHalEvent::ALL_EVENTS: + break; + default: + break; + } + + break; + + case AppCallbackNotifier::NOTIFIER_CMD_PROCESS_ERROR: + + if ( ( NULL != mCameraHal ) && + ( NULL != mNotifyCb ) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_ERROR) ) ) + { + mNotifyCb(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0, mCallbackCookie); + } + + break; + + } + + if ( NULL != evt ) + { + delete evt; + } + + + LOG_FUNCTION_NAME_EXIT; + +} + +static void copy2Dto1D(void *dst, + void *src, + int width, + int height, + size_t stride, + uint32_t offset, + unsigned int bytesPerPixel, + size_t length, + const char *pixelFormat) +{ + unsigned int alignedRow, row; + unsigned char *bufferDst, *bufferSrc; + unsigned char *bufferDstEnd, *bufferSrcEnd; + uint16_t *bufferSrc_UV; + void *y_uv[2]; //y_uv[0]=> y pointer; y_uv[1]=>uv pointer + + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + Rect bounds; + + bounds.left = offset % stride; + bounds.top = offset / stride; + bounds.right = width; + bounds.bottom = height; + + // get the y & uv pointers from the gralloc handle; + mapper.lock((buffer_handle_t)src, GRALLOC_USAGE_SW_READ_OFTEN, bounds, y_uv); + + CAMHAL_LOGDB("copy2Dto1D() y= %p ; uv=%p.",y_uv[0],y_uv[1]); + CAMHAL_LOGDB("pixelFormat,= %d; offset=%d",*pixelFormat,offset); + + if (pixelFormat!=NULL) { + if (strcmp(pixelFormat, CameraParameters::PIXEL_FORMAT_YUV422I) == 0) { + bytesPerPixel = 2; + } else if (strcmp(pixelFormat, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(pixelFormat, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) { + bytesPerPixel = 1; + bufferDst = ( unsigned char * ) dst; + bufferDstEnd = ( unsigned char * ) dst + width*height*bytesPerPixel; + bufferSrc = ( unsigned char * ) y_uv[0] + offset; + bufferSrcEnd = ( unsigned char * ) ( ( size_t ) y_uv[0] + length + offset); + row = width*bytesPerPixel; + alignedRow = stride-width; + int stride_bytes = stride / 8; + uint32_t xOff = offset % stride; + uint32_t yOff = offset / stride; + + // going to convert from NV12 here and return + // Step 1: Y plane: iterate through each row and copy + for ( int i = 0 ; i < height ; i++) { + memcpy(bufferDst, bufferSrc, row); + bufferSrc += stride; + bufferDst += row; + if ( ( bufferSrc > bufferSrcEnd ) || ( bufferDst > bufferDstEnd ) ) { + break; + } + } + + bufferSrc_UV = ( uint16_t * ) y_uv[1] + (stride/2)*yOff + xOff; + + if (strcmp(pixelFormat, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) { + uint16_t *bufferDst_UV; + + // Step 2: UV plane: convert NV12 to NV21 by swapping U & V + bufferDst_UV = (uint16_t *) (((uint8_t*)dst)+row*height); + + for (int i = 0 ; i < height/2 ; i++, bufferSrc_UV += alignedRow/2) { + int n = width; + asm volatile ( + " pld [%[src], %[src_stride], lsl #2] \n\t" + " cmp %[n], #32 \n\t" + " blt 1f \n\t" + "0: @ 32 byte swap \n\t" + " sub %[n], %[n], #32 \n\t" + " vld2.8 {q0, q1} , [%[src]]! \n\t" + " vswp q0, q1 \n\t" + " cmp %[n], #32 \n\t" + " vst2.8 {q0,q1},[%[dst]]! \n\t" + " bge 0b \n\t" + "1: @ Is there enough data? \n\t" + " cmp %[n], #16 \n\t" + " blt 3f \n\t" + "2: @ 16 byte swap \n\t" + " sub %[n], %[n], #16 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " vswp d0, d1 \n\t" + " cmp %[n], #16 \n\t" + " vst2.8 {d0,d1},[%[dst]]! \n\t" + " bge 2b \n\t" + "3: @ Is there enough data? \n\t" + " cmp %[n], #8 \n\t" + " blt 5f \n\t" + "4: @ 8 byte swap \n\t" + " sub %[n], %[n], #8 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " vswp d0, d1 \n\t" + " cmp %[n], #8 \n\t" + " vst2.8 {d0[0],d1[0]},[%[dst]]! \n\t" + " bge 4b \n\t" + "5: @ end \n\t" +#ifdef NEEDS_ARM_ERRATA_754319_754320 + " vmov s0,s0 @ add noop for errata item \n\t" +#endif + : [dst] "+r" (bufferDst_UV), [src] "+r" (bufferSrc_UV), [n] "+r" (n) + : [src_stride] "r" (stride_bytes) + : "cc", "memory", "q0", "q1" + ); + } + } else if (strcmp(pixelFormat, CameraParameters::PIXEL_FORMAT_YUV420P) == 0) { + uint16_t *bufferDst_U; + uint16_t *bufferDst_V; + + // Step 2: UV plane: convert NV12 to YV12 by de-interleaving U & V + // TODO(XXX): This version of CameraHal assumes NV12 format it set at + // camera adapter to support YV12. Need to address for + // USBCamera + + bufferDst_V = (uint16_t *) (((uint8_t*)dst)+row*height); + bufferDst_U = (uint16_t *) (((uint8_t*)dst)+row*height+row*height/4); + + for (int i = 0 ; i < height/2 ; i++, bufferSrc_UV += alignedRow/2) { + int n = width; + asm volatile ( + " pld [%[src], %[src_stride], lsl #2] \n\t" + " cmp %[n], #32 \n\t" + " blt 1f \n\t" + "0: @ 32 byte swap \n\t" + " sub %[n], %[n], #32 \n\t" + " vld2.8 {q0, q1} , [%[src]]! \n\t" + " cmp %[n], #32 \n\t" + " vst1.8 {q1},[%[dst_v]]! \n\t" + " vst1.8 {q0},[%[dst_u]]! \n\t" + " bge 0b \n\t" + "1: @ Is there enough data? \n\t" + " cmp %[n], #16 \n\t" + " blt 3f \n\t" + "2: @ 16 byte swap \n\t" + " sub %[n], %[n], #16 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " cmp %[n], #16 \n\t" + " vst1.8 {d1},[%[dst_v]]! \n\t" + " vst1.8 {d0},[%[dst_u]]! \n\t" + " bge 2b \n\t" + "3: @ Is there enough data? \n\t" + " cmp %[n], #8 \n\t" + " blt 5f \n\t" + "4: @ 8 byte swap \n\t" + " sub %[n], %[n], #8 \n\t" + " vld2.8 {d0, d1} , [%[src]]! \n\t" + " cmp %[n], #8 \n\t" + " vst1.8 {d1[0]},[%[dst_v]]! \n\t" + " vst1.8 {d0[0]},[%[dst_u]]! \n\t" + " bge 4b \n\t" + "5: @ end \n\t" +#ifdef NEEDS_ARM_ERRATA_754319_754320 + " vmov s0,s0 @ add noop for errata item \n\t" +#endif + : [dst_u] "+r" (bufferDst_U), [dst_v] "+r" (bufferDst_V), + [src] "+r" (bufferSrc_UV), [n] "+r" (n) + : [src_stride] "r" (stride_bytes) + : "cc", "memory", "q0", "q1" + ); + } + } + mapper.unlock((buffer_handle_t)src); + return ; + + } else if(strcmp(pixelFormat, CameraParameters::PIXEL_FORMAT_RGB565) == 0) { + bytesPerPixel = 2; + } + } + + bufferDst = ( unsigned char * ) dst; + bufferSrc = ( unsigned char * ) y_uv[0]; + row = width*bytesPerPixel; + alignedRow = ( row + ( stride -1 ) ) & ( ~ ( stride -1 ) ); + + //iterate through each row + for ( int i = 0 ; i < height ; i++, bufferSrc += alignedRow, bufferDst += row) { + memcpy(bufferDst, bufferSrc, row); + } + mapper.unlock((buffer_handle_t)src); +} + +void AppCallbackNotifier::notifyFrame() +{ + ///Receive and send the frame notifications to app + TIUTILS::Message msg; + CameraFrame *frame; + MemoryHeapBase *heap; + MemoryBase *buffer = NULL; + sp<MemoryBase> memBase; + void *buf = NULL; + + LOG_FUNCTION_NAME; + + if(!mFrameQ.isEmpty()) + { + mFrameQ.get(&msg); + } + else + { + return; + } + + bool ret = true; + + if(mNotifierState != AppCallbackNotifier::NOTIFIER_STARTED) + { + return; + } + + frame = NULL; + switch(msg.command) + { + case AppCallbackNotifier::NOTIFIER_CMD_PROCESS_FRAME: + + frame = (CameraFrame *) msg.arg1; + if(!frame) + { + break; + } + + if ( (CameraFrame::RAW_FRAME == frame->mFrameType )&& + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_RAW_IMAGE) ) ) + { + +#ifdef COPY_IMAGE_BUFFER + + camera_memory_t* raw_picture = mRequestMemory(-1, frame->mLength, 1, NULL); + + if ( NULL != raw_picture ) + { + buf = raw_picture->data; + if ( NULL != buf ) + { + memcpy(buf, + ( void * ) ( (unsigned int) frame->mBuffer + frame->mOffset), + frame->mLength); + } + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + } + + mDataCb(CAMERA_MSG_RAW_IMAGE, raw_picture, 0, NULL, mCallbackCookie); +#else + + //TODO: Find a way to map a Tiler buffer to a MemoryHeapBase + +#endif + if(raw_picture) + { + raw_picture->release(raw_picture); + } + + } + else if ( ( CameraFrame::IMAGE_FRAME == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) ) + { + Mutex::Autolock lock(mLock); + +#ifdef COPY_IMAGE_BUFFER + + camera_memory_t* raw_picture = mRequestMemory(-1, frame->mLength, 1, NULL); + + if(raw_picture) + { + buf = raw_picture->data; + } + + if ( NULL != buf) + { + memcpy(buf, + ( void * ) ( (unsigned int) frame->mBuffer + frame->mOffset), + frame->mLength); + } + + { + Mutex::Autolock lock(mBurstLock); +#if 0 //TODO: enable burst mode later + if ( mBurst ) + { + `(CAMERA_MSG_BURST_IMAGE, JPEGPictureMemBase, mCallbackCookie); + } + else +#endif + { + mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, raw_picture, + 0, NULL, + mCallbackCookie); + } + } +#else + + //TODO: Find a way to map a Tiler buffer to a MemoryHeapBase + +#endif + if(raw_picture) + { + raw_picture->release(raw_picture); + } + + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + + } + else if ( ( CameraFrame::VIDEO_FRAME_SYNC == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_VIDEO_FRAME) ) ) + { + mRecordingLock.lock(); + if(mRecording) + { + if(mUseMetaDataBufferMode) + { + camera_memory_t *videoMedatadaBufferMemory = + (camera_memory_t *) mVideoMetadataBufferMemoryMap.valueFor((uint32_t) frame->mBuffer); + video_metadata_t *videoMetadataBuffer = (video_metadata_t *) videoMedatadaBufferMemory->data; + + if( (NULL == videoMedatadaBufferMemory) || (NULL == videoMetadataBuffer) || (NULL == frame->mBuffer) ) + { + CAMHAL_LOGEA("Error! One of the video buffers is NULL"); + break; + } + + videoMetadataBuffer->metadataBufferType = (int) kMetadataBufferTypeCameraSource; + videoMetadataBuffer->handle = frame->mBuffer; + videoMetadataBuffer->offset = frame->mOffset; + + CAMHAL_LOGVB("mDataCbTimestamp : frame->mBuffer=0x%x, videoMetadataBuffer=0x%x, videoMedatadaBufferMemory=0x%x", + frame->mBuffer, videoMetadataBuffer, videoMedatadaBufferMemory); + + mDataCbTimestamp(frame->mTimestamp, CAMERA_MSG_VIDEO_FRAME, + videoMedatadaBufferMemory, 0, mCallbackCookie); + } + else + { + //TODO: Need to revisit this, should ideally be mapping the TILER buffer using mRequestMemory + camera_memory_t* fakebuf = mRequestMemory(-1, 4, 1, NULL); + if( (NULL == fakebuf) || ( NULL == fakebuf->data) || ( NULL == frame->mBuffer)) + { + CAMHAL_LOGEA("Error! One of the video buffers is NULL"); + break; + } + + fakebuf->data = frame->mBuffer; + mDataCbTimestamp(frame->mTimestamp, CAMERA_MSG_VIDEO_FRAME, fakebuf, 0, mCallbackCookie); + fakebuf->release(fakebuf); + } + } + mRecordingLock.unlock(); + + } + else if(( CameraFrame::SNAPSHOT_FRAME == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( NULL != mNotifyCb)) { + Mutex::Autolock lock(mLock); + //When enabled, measurement data is sent instead of video data + if ( !mMeasurementEnabled ) { + if (!mPreviewMemory || !frame->mBuffer) { + CAMHAL_LOGDA("Error! One of the buffer is NULL"); + break; + } + + buf = (void*) mPreviewBufs[mPreviewBufCount]; + + CAMHAL_LOGVB("%d:copy2Dto1D(%p, %p, %d, %d, %d, %d, %d,%s)", + __LINE__, + buf, + frame->mBuffer, + frame->mWidth, + frame->mHeight, + frame->mAlignment, + 2, + frame->mLength, + mPreviewPixelFormat); + + if ( NULL != buf ) { + copy2Dto1D(buf, + frame->mBuffer, + frame->mWidth, + frame->mHeight, + frame->mAlignment, + frame->mOffset, + 2, + frame->mLength, + mPreviewPixelFormat); + } + + if (mCameraHal->msgTypeEnabled(CAMERA_MSG_POSTVIEW_FRAME)) { + ///Give preview callback to app + mDataCb(CAMERA_MSG_POSTVIEW_FRAME, mPreviewMemory, mPreviewBufCount, NULL, mCallbackCookie); + } + + // increment for next buffer + mPreviewBufCount = (mPreviewBufCount+1) % AppCallbackNotifier::MAX_BUFFERS; + } + + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + } else if ( ( CameraFrame::PREVIEW_FRAME_SYNC== frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) ) { + Mutex::Autolock lock(mLock); + //When enabled, measurement data is sent instead of video data + if ( !mMeasurementEnabled ) { + if (!mPreviewMemory || !frame->mBuffer) { + CAMHAL_LOGDA("Error! One of the buffer is NULL"); + break; + } + + buf = (void*) mPreviewBufs[mPreviewBufCount]; + + CAMHAL_LOGVB("%d:copy2Dto1D(%p, %p, %d, %d, %d, %d, %d,%s)", + __LINE__, + buf, + frame->mBuffer, + frame->mWidth, + frame->mHeight, + frame->mAlignment, + 2, + frame->mLength, + mPreviewPixelFormat); + + if ( NULL != buf ) { + copy2Dto1D(buf, + frame->mBuffer, + frame->mWidth, + frame->mHeight, + frame->mAlignment, + frame->mOffset, + 2, + frame->mLength, + mPreviewPixelFormat); + } + + // Give preview callback to app + mDataCb(CAMERA_MSG_PREVIEW_FRAME, mPreviewMemory, mPreviewBufCount, NULL, mCallbackCookie); + + // increment for next buffer + mPreviewBufCount = (mPreviewBufCount+1) % AppCallbackNotifier::MAX_BUFFERS; + } + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + } else if ( ( CameraFrame::FRAME_DATA_SYNC == frame->mFrameType ) && + ( NULL != mCameraHal ) && + ( NULL != mDataCb) && + ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) ) { + if (!mPreviewMemory || !frame->mBuffer) { + CAMHAL_LOGDA("Error! One of the buffer is NULL"); + break; + } + + buf = (void*) mPreviewBufs[mPreviewBufCount]; + if (buf) { + if ( (mPreviewMemory->size / MAX_BUFFERS) >= frame->mLength ) { + memcpy(buf, ( void * ) frame->mBuffer, frame->mLength); + } else { + memset(buf, 0, (mPreviewMemory->size / MAX_BUFFERS)); + } + } + + // Give preview callback to app + mDataCb(CAMERA_MSG_PREVIEW_FRAME, mPreviewMemory, mPreviewBufCount, NULL, mCallbackCookie); + + //Increment the buffer count + mPreviewBufCount = (mPreviewBufCount+1) % AppCallbackNotifier::MAX_BUFFERS; + + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + } else { + mFrameProvider->returnFrame(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType); + CAMHAL_LOGDB("Frame type 0x%x is still unsupported!", frame->mFrameType); + } + + break; + + default: + + break; + + }; + +exit: + + if ( NULL != frame ) + { + delete frame; + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::frameCallbackRelay(CameraFrame* caFrame) +{ + LOG_FUNCTION_NAME; + AppCallbackNotifier *appcbn = (AppCallbackNotifier*) (caFrame->mCookie); + appcbn->frameCallback(caFrame); + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::frameCallback(CameraFrame* caFrame) +{ + ///Post the event to the event queue of AppCallbackNotifier + TIUTILS::Message msg; + CameraFrame *frame; + + LOG_FUNCTION_NAME; + + if ( NULL != caFrame ) + { + + frame = new CameraFrame(*caFrame); + if ( NULL != frame ) + { + msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_FRAME; + msg.arg1 = frame; + mFrameQ.put(&msg); + } + else + { + CAMHAL_LOGEA("Not enough resources to allocate CameraFrame"); + } + + } + + LOG_FUNCTION_NAME_EXIT; +} + + +void AppCallbackNotifier::eventCallbackRelay(CameraHalEvent* chEvt) +{ + LOG_FUNCTION_NAME; + AppCallbackNotifier *appcbn = (AppCallbackNotifier*) (chEvt->mCookie); + appcbn->eventCallback(chEvt); + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::eventCallback(CameraHalEvent* chEvt) +{ + + ///Post the event to the event queue of AppCallbackNotifier + TIUTILS::Message msg; + CameraHalEvent *event; + + + LOG_FUNCTION_NAME; + + if ( NULL != chEvt ) + { + + event = new CameraHalEvent(*chEvt); + if ( NULL != event ) + { + msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_EVENT; + msg.arg1 = event; + mEventQ.put(&msg); + } + else + { + CAMHAL_LOGEA("Not enough resources to allocate CameraHalEvent"); + } + + } + + LOG_FUNCTION_NAME_EXIT; +} + + +bool AppCallbackNotifier::processMessage() +{ + ///Retrieve the command from the command queue and process it + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + CAMHAL_LOGDA("+Msg get..."); + mNotificationThread->msgQ().get(&msg); + CAMHAL_LOGDA("-Msg get..."); + bool ret = true; + + switch(msg.command) + { + case NotificationThread::NOTIFIER_EXIT: + { + CAMHAL_LOGEA("Received NOTIFIER_EXIT command from Camera HAL"); + mNotifierState = AppCallbackNotifier::NOTIFIER_EXITED; + ret = false; + break; + } + default: + { + CAMHAL_LOGEA("Error: ProcessMsg() command from Camera HAL"); + break; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; + + +} + +AppCallbackNotifier::~AppCallbackNotifier() +{ + LOG_FUNCTION_NAME; + + ///Stop app callback notifier if not already stopped + stop(); + + ///Unregister with the frame provider + if ( NULL != mFrameProvider ) + { + mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES); + } + + //unregister with the event provider + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification(CameraHalEvent::ALL_EVENTS); + } + + TIUTILS::Message msg = {0,0,0,0,0,0}; + msg.command = NotificationThread::NOTIFIER_EXIT; + + ///Post the message to display thread + mNotificationThread->msgQ().put(&msg); + + //Exit and cleanup the thread + mNotificationThread->requestExitAndWait(); + + //Delete the display thread + mNotificationThread.clear(); + + + ///Free the event and frame providers + if ( NULL != mEventProvider ) + { + ///Deleting the event provider + CAMHAL_LOGDA("Stopping Event Provider"); + delete mEventProvider; + mEventProvider = NULL; + } + + if ( NULL != mFrameProvider ) + { + ///Deleting the frame provider + CAMHAL_LOGDA("Stopping Frame Provider"); + delete mFrameProvider; + mFrameProvider = NULL; + } + + releaseSharedVideoBuffers(); + + LOG_FUNCTION_NAME_EXIT; +} + +//Free all video heaps and buffers +void AppCallbackNotifier::releaseSharedVideoBuffers() +{ + LOG_FUNCTION_NAME; + + if(mUseMetaDataBufferMode) + { + camera_memory_t* videoMedatadaBufferMemory; + for (unsigned int i = 0; i < mVideoMetadataBufferMemoryMap.size(); i++) + { + videoMedatadaBufferMemory = (camera_memory_t*) mVideoMetadataBufferMemoryMap.valueAt(i); + if(NULL != videoMedatadaBufferMemory) + { + videoMedatadaBufferMemory->release(videoMedatadaBufferMemory); + CAMHAL_LOGDB("Released videoMedatadaBufferMemory=0x%x", videoMedatadaBufferMemory); + } + } + + mVideoMetadataBufferMemoryMap.clear(); + mVideoMetadataBufferReverseMap.clear(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::setEventProvider(int32_t eventMask, MessageNotifier * eventNotifier) +{ + + LOG_FUNCTION_NAME; + ///@remarks There is no NULL check here. We will check + ///for NULL when we get start command from CameraHal + ///@Remarks Currently only one event provider (CameraAdapter) is supported + ///@todo Have an array of event providers for each event bitmask + mEventProvider = new EventProvider(eventNotifier, this, eventCallbackRelay); + if ( NULL == mEventProvider ) + { + CAMHAL_LOGEA("Error in creating EventProvider"); + } + else + { + mEventProvider->enableEventNotification(eventMask); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void AppCallbackNotifier::setFrameProvider(FrameNotifier *frameNotifier) +{ + LOG_FUNCTION_NAME; + ///@remarks There is no NULL check here. We will check + ///for NULL when we get the start command from CameraAdapter + mFrameProvider = new FrameProvider(frameNotifier, this, frameCallbackRelay); + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Error in creating FrameProvider"); + } + else + { + //Register only for captured images and RAW for now + //TODO: Register for and handle all types of frames + mFrameProvider->enableFrameNotification(CameraFrame::IMAGE_FRAME); + mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t AppCallbackNotifier::startPreviewCallbacks(CameraParameters ¶ms, void *buffers, uint32_t *offsets, int fd, size_t length, size_t count) +{ + sp<MemoryHeapBase> heap; + sp<MemoryBase> buffer; + unsigned int *bufArr; + size_t size = 0; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mLock); + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to start video recording without FrameProvider"); + return -EINVAL; + } + + if ( mPreviewing ) + { + CAMHAL_LOGDA("+Already previewing"); + return NO_INIT; + } + + int w,h; + ///Get preview size + params.getPreviewSize(&w, &h); + + //Get the preview pixel format + mPreviewPixelFormat = params.getPreviewFormat(); + + if(strcmp(mPreviewPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + size = w*h*2; + mPreviewPixelFormat = CameraParameters::PIXEL_FORMAT_YUV422I; + } + else if(strcmp(mPreviewPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(mPreviewPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_YUV420P) == 0) + { + size = (w*h*3)/2; + mPreviewPixelFormat = CameraParameters::PIXEL_FORMAT_YUV420SP; + } + else if(strcmp(mPreviewPixelFormat, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + size = w*h*2; + mPreviewPixelFormat = CameraParameters::PIXEL_FORMAT_RGB565; + } + + mPreviewMemory = mRequestMemory(-1, size, AppCallbackNotifier::MAX_BUFFERS, NULL); + if (!mPreviewMemory) { + return NO_MEMORY; + } + + for (int i=0; i < AppCallbackNotifier::MAX_BUFFERS; i++) { + mPreviewBufs[i] = (unsigned char*) mPreviewMemory->data + (i*size); + } + + if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME ) ) { + mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + } + + mPreviewBufCount = 0; + + mPreviewing = true; + + LOG_FUNCTION_NAME; + + return NO_ERROR; +} + +void AppCallbackNotifier::setBurst(bool burst) +{ + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mBurstLock); + + mBurst = burst; + + LOG_FUNCTION_NAME_EXIT; +} + +status_t AppCallbackNotifier::stopPreviewCallbacks() +{ + sp<MemoryHeapBase> heap; + sp<MemoryBase> buffer; + + LOG_FUNCTION_NAME; + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to stop preview callbacks without FrameProvider"); + return -EINVAL; + } + + if ( !mPreviewing ) + { + return NO_INIT; + } + + mFrameProvider->disableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + + mPreviewMemory->release(mPreviewMemory); + + mPreviewing = false; + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + +} + +status_t AppCallbackNotifier::useMetaDataBufferMode(bool enable) +{ + mUseMetaDataBufferMode = enable; + + return NO_ERROR; +} + + +status_t AppCallbackNotifier::startRecording() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mRecordingLock); + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to start video recording without FrameProvider"); + ret = -1; + } + + if(mRecording) + { + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + mFrameProvider->enableFrameNotification(CameraFrame::VIDEO_FRAME_SYNC); + } + + mRecording = true; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//Allocate metadata buffers for video recording +status_t AppCallbackNotifier::initSharedVideoBuffers(void *buffers, uint32_t *offsets, int fd, size_t length, size_t count) +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + if(mUseMetaDataBufferMode) + { + uint32_t *bufArr = NULL; + camera_memory_t* videoMedatadaBufferMemory = NULL; + + if(NULL == buffers) + { + CAMHAL_LOGEA("Error! Video buffers are NULL"); + return BAD_VALUE; + } + bufArr = (uint32_t *) buffers; + + for (uint32_t i = 0; i < count; i++) + { + videoMedatadaBufferMemory = mRequestMemory(-1, sizeof(video_metadata_t), 1, NULL); + if((NULL == videoMedatadaBufferMemory) || (NULL == videoMedatadaBufferMemory->data)) + { + CAMHAL_LOGEA("Error! Could not allocate memory for Video Metadata Buffers"); + return NO_MEMORY; + } + + mVideoMetadataBufferMemoryMap.add(bufArr[i], (uint32_t)(videoMedatadaBufferMemory)); + mVideoMetadataBufferReverseMap.add((uint32_t)(videoMedatadaBufferMemory->data), bufArr[i]); + CAMHAL_LOGDB("bufArr[%d]=0x%x, videoMedatadaBufferMemory=0x%x, videoMedatadaBufferMemory->data=0x%x", + i, bufArr[i], videoMedatadaBufferMemory, videoMedatadaBufferMemory->data); + } + } + +exit: + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t AppCallbackNotifier::stopRecording() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mRecordingLock); + + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to stop video recording without FrameProvider"); + ret = -1; + } + + if(!mRecording) + { + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + mFrameProvider->disableFrameNotification(CameraFrame::VIDEO_FRAME_SYNC); + } + + ///Release the shared video buffers + releaseSharedVideoBuffers(); + + mRecording = false; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t AppCallbackNotifier::releaseRecordingFrame(const void* mem) +{ + status_t ret = NO_ERROR; + void *frame = NULL; + + LOG_FUNCTION_NAME; + if ( NULL == mFrameProvider ) + { + CAMHAL_LOGEA("Trying to stop video recording without FrameProvider"); + ret = -1; + } + + if ( NULL == mem ) + { + CAMHAL_LOGEA("Video Frame released is invalid"); + ret = -1; + } + + if( NO_ERROR != ret ) + { + return ret; + } + + if(mUseMetaDataBufferMode) + { + video_metadata_t *videoMetadataBuffer = (video_metadata_t *) mem ; + frame = (void*) mVideoMetadataBufferReverseMap.valueFor((uint32_t) videoMetadataBuffer); + CAMHAL_LOGVB("Releasing frame with videoMetadataBuffer=0x%x, videoMetadataBuffer->handle=0x%x & frame handle=0x%x\n", + videoMetadataBuffer, videoMetadataBuffer->handle, frame); + } + else + { + frame = (void*)(*((uint32_t *)mem)); + } + + if ( NO_ERROR == ret ) + { + ret = mFrameProvider->returnFrame(frame, CameraFrame::VIDEO_FRAME_SYNC); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t AppCallbackNotifier::enableMsgType(int32_t msgType) +{ + if(msgType & CAMERA_MSG_POSTVIEW_FRAME) + { + mFrameProvider->enableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + } + + if(msgType & CAMERA_MSG_PREVIEW_FRAME) + { + mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + } + + return NO_ERROR; +} + +status_t AppCallbackNotifier::disableMsgType(int32_t msgType) +{ + if(msgType & CAMERA_MSG_POSTVIEW_FRAME) + { + mFrameProvider->disableFrameNotification(CameraFrame::SNAPSHOT_FRAME); + } + + if(msgType & CAMERA_MSG_PREVIEW_FRAME) + { + mFrameProvider->disableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); + } + + return NO_ERROR; + +} + +status_t AppCallbackNotifier::start() +{ + LOG_FUNCTION_NAME; + if(mNotifierState==AppCallbackNotifier::NOTIFIER_STARTED) + { + CAMHAL_LOGDA("AppCallbackNotifier already running"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + + ///Check whether initial conditions are met for us to start + ///A frame provider should be available, if not return error + if(!mFrameProvider) + { + ///AppCallbackNotifier not properly initialized + CAMHAL_LOGEA("AppCallbackNotifier not properly initialized - Frame provider is NULL"); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + ///At least one event notifier should be available, if not return error + ///@todo Modify here when there is an array of event providers + if(!mEventProvider) + { + CAMHAL_LOGEA("AppCallbackNotifier not properly initialized - Event provider is NULL"); + LOG_FUNCTION_NAME_EXIT; + ///AppCallbackNotifier not properly initialized + return NO_INIT; + } + + mNotifierState = AppCallbackNotifier::NOTIFIER_STARTED; + CAMHAL_LOGDA(" --> AppCallbackNotifier NOTIFIER_STARTED \n"); + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + +} + +status_t AppCallbackNotifier::stop() +{ + LOG_FUNCTION_NAME; + + if(mNotifierState!=AppCallbackNotifier::NOTIFIER_STARTED) + { + CAMHAL_LOGDA("AppCallbackNotifier already in stopped state"); + LOG_FUNCTION_NAME_EXIT; + return ALREADY_EXISTS; + } + + mNotifierState = AppCallbackNotifier::NOTIFIER_STOPPED; + CAMHAL_LOGDA(" --> AppCallbackNotifier NOTIFIER_STOPPED \n"); + + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + + +/*--------------------NotificationHandler Class ENDS here-----------------------------*/ + + + +}; diff --git a/camera/BaseCameraAdapter.cpp b/camera/BaseCameraAdapter.cpp new file mode 100644 index 0000000..fb90a79 --- /dev/null +++ b/camera/BaseCameraAdapter.cpp @@ -0,0 +1,1969 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + + +#define LOG_TAG "CameraHAL" + +#include "BaseCameraAdapter.h" + +namespace android { + +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +BaseCameraAdapter::BaseCameraAdapter() +{ + mReleaseImageBuffersCallback = NULL; + mEndImageCaptureCallback = NULL; + mErrorNotifier = NULL; + mEndCaptureData = NULL; + mReleaseData = NULL; + mRecording = false; + + mPreviewBuffers = NULL; + mPreviewBufferCount = 0; + mPreviewBuffersLength = 0; + + mVideoBuffers = NULL; + mVideoBuffersCount = 0; + mVideoBuffersLength = 0; + + mCaptureBuffers = NULL; + mCaptureBuffersCount = 0; + mCaptureBuffersLength = 0; + + mPreviewDataBuffers = NULL; + mPreviewDataBuffersCount = 0; + mPreviewDataBuffersLength = 0; + + mAdapterState = INTIALIZED_STATE; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + mStartFocus.tv_sec = 0; + mStartFocus.tv_usec = 0; + mStartCapture.tv_sec = 0; + mStartCapture.tv_usec = 0; +#endif + +} + +BaseCameraAdapter::~BaseCameraAdapter() +{ + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mSubscriberLock); + + mFrameSubscribers.clear(); + mImageSubscribers.clear(); + mRawSubscribers.clear(); + mVideoSubscribers.clear(); + mFocusSubscribers.clear(); + mShutterSubscribers.clear(); + mZoomSubscribers.clear(); + mFaceSubscribers.clear(); + + LOG_FUNCTION_NAME_EXIT; +} + +status_t BaseCameraAdapter::registerImageReleaseCallback(release_image_buffers_callback callback, void *user_data) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mReleaseImageBuffersCallback = callback; + mReleaseData = user_data; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::registerEndCaptureCallback(end_image_capture_callback callback, void *user_data) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mEndImageCaptureCallback= callback; + mEndCaptureData = user_data; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::setErrorHandler(ErrorNotifier *errorNotifier) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL == errorNotifier ) + { + CAMHAL_LOGEA("Invalid Error Notifier reference"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + mErrorNotifier = errorNotifier; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void BaseCameraAdapter::enableMsgType(int32_t msgs, frame_callback callback, event_callback eventCb, void* cookie) +{ + Mutex::Autolock lock(mSubscriberLock); + + LOG_FUNCTION_NAME; + + if ( CameraFrame::PREVIEW_FRAME_SYNC == msgs ) + { + mFrameSubscribers.add((int) cookie, callback); + } + else if ( CameraFrame::FRAME_DATA_SYNC == msgs ) + { + mFrameDataSubscribers.add((int) cookie, callback); + } + else if ( CameraFrame::IMAGE_FRAME == msgs) + { + mImageSubscribers.add((int) cookie, callback); + } + else if ( CameraFrame::RAW_FRAME == msgs) + { + mRawSubscribers.add((int) cookie, callback); + } + else if ( CameraFrame::VIDEO_FRAME_SYNC == msgs) + { + mVideoSubscribers.add((int) cookie, callback); + } + else if ( CameraHalEvent::ALL_EVENTS == msgs) + { + mFocusSubscribers.add((int) cookie, eventCb); + mShutterSubscribers.add((int) cookie, eventCb); + mZoomSubscribers.add((int) cookie, eventCb); + mFaceSubscribers.add((int) cookie, eventCb); + } + else + { + CAMHAL_LOGEA("Message type subscription no supported yet!"); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void BaseCameraAdapter::disableMsgType(int32_t msgs, void* cookie) +{ + Mutex::Autolock lock(mSubscriberLock); + + LOG_FUNCTION_NAME; + + if ( CameraFrame::PREVIEW_FRAME_SYNC == msgs ) + { + mFrameSubscribers.removeItem((int) cookie); + } + else if ( CameraFrame::FRAME_DATA_SYNC == msgs ) + { + mFrameDataSubscribers.removeItem((int) cookie); + } + else if ( CameraFrame::IMAGE_FRAME == msgs) + { + mImageSubscribers.removeItem((int) cookie); + } + else if ( CameraFrame::RAW_FRAME == msgs) + { + mRawSubscribers.removeItem((int) cookie); + } + else if ( CameraFrame::VIDEO_FRAME_SYNC == msgs) + { + mVideoSubscribers.removeItem((int) cookie); + } + else if ( CameraFrame::ALL_FRAMES == msgs ) + { + mFrameSubscribers.removeItem((int) cookie); + mFrameDataSubscribers.removeItem((int) cookie); + mImageSubscribers.removeItem((int) cookie); + mRawSubscribers.removeItem((int) cookie); + mVideoSubscribers.removeItem((int) cookie); + } + else if ( CameraHalEvent::ALL_EVENTS == msgs) + { + //Subscribe only for focus + //TODO: Process case by case + mFocusSubscribers.removeItem((int) cookie); + mShutterSubscribers.removeItem((int) cookie); + mZoomSubscribers.removeItem((int) cookie); + mFaceSubscribers.removeItem((int) cookie); + } + else + { + CAMHAL_LOGEB("Message type 0x%x subscription no supported yet!", msgs); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void BaseCameraAdapter::returnFrame(void* frameBuf, CameraFrame::FrameType frameType) +{ + status_t res = NO_ERROR; + size_t subscriberCount = 0; + int refCount = -1; + + Mutex::Autolock lock(mReturnFrameLock); + + if ( NULL == frameBuf ) + { + CAMHAL_LOGEA("Invalid frameBuf"); + return; + } + + if ( NO_ERROR == res) + { + + refCount = getFrameRefCount(frameBuf, frameType); + + if ( 0 < refCount ) + { + + refCount--; + setFrameRefCount(frameBuf, frameType, refCount); + + if ( ( mRecording ) && ( CameraFrame::VIDEO_FRAME_SYNC == frameType ) ) + { + refCount += getFrameRefCount(frameBuf, CameraFrame::PREVIEW_FRAME_SYNC); + } + else if ( ( mRecording ) && ( CameraFrame::PREVIEW_FRAME_SYNC == frameType ) ) + { + refCount += getFrameRefCount(frameBuf, CameraFrame::VIDEO_FRAME_SYNC); + } + + } + else + { + return; + } + } + + if ( NO_ERROR == res ) + { + //check if someone is holding this buffer + if ( 0 == refCount ) + { + res = fillThisBuffer(frameBuf, frameType); + } + } + +} + +status_t BaseCameraAdapter::sendCommand(CameraCommands operation, int value1, int value2, int value3) +{ + status_t ret = NO_ERROR; + struct timeval *refTimestamp; + BuffersDescriptor *desc = NULL; + CameraFrame *frame = NULL; + + LOG_FUNCTION_NAME; + + switch ( operation ) { + case CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW: + CAMHAL_LOGDA("Use buffers for preview"); + desc = ( BuffersDescriptor * ) value1; + + if ( NULL == desc ) + { + CAMHAL_LOGEA("Invalid preview buffers!"); + return -EINVAL; + } + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + Mutex::Autolock lock(mPreviewBufferLock); + mPreviewBuffers = (int *) desc->mBuffers; + mPreviewBuffersLength = desc->mLength; + mPreviewBuffersAvailable.clear(); + for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ ) + { + mPreviewBuffersAvailable.add(mPreviewBuffers[i], 0); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) + { + mPreviewBuffersAvailable.add(mPreviewBuffers[i], 1); + } + } + + if ( NULL != desc ) + { + ret = useBuffers(CameraAdapter::CAMERA_PREVIEW, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA: + CAMHAL_LOGDA("Use buffers for preview data"); + desc = ( BuffersDescriptor * ) value1; + + if ( NULL == desc ) + { + CAMHAL_LOGEA("Invalid preview data buffers!"); + return -EINVAL; + } + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + Mutex::Autolock lock(mPreviewDataBufferLock); + mPreviewDataBuffers = (int *) desc->mBuffers; + mPreviewDataBuffersLength = desc->mLength; + mPreviewDataBuffersAvailable.clear(); + for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ ) + { + mPreviewDataBuffersAvailable.add(mPreviewDataBuffers[i], true); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) + { + mPreviewDataBuffersAvailable.add(mPreviewBuffers[i], 1); + } + } + + if ( NULL != desc ) + { + ret = useBuffers(CameraAdapter::CAMERA_MEASUREMENT, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDA("Use buffers for image capture"); + desc = ( BuffersDescriptor * ) value1; + + if ( NULL == desc ) + { + CAMHAL_LOGEA("Invalid capture buffers!"); + return -EINVAL; + } + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + Mutex::Autolock lock(mCaptureBufferLock); + mCaptureBuffers = (int *) desc->mBuffers; + mCaptureBuffersLength = desc->mLength; + mCaptureBuffersAvailable.clear(); + for ( uint32_t i = 0 ; i < desc->mMaxQueueable ; i++ ) + { + mCaptureBuffersAvailable.add(mCaptureBuffers[i], true); + } + // initial ref count for undeqeueued buffers is 1 since buffer provider + // is still holding on to it + for ( uint32_t i = desc->mMaxQueueable ; i < desc->mCount ; i++ ) + { + mCaptureBuffersAvailable.add(mPreviewBuffers[i], 1); + } + } + + if ( NULL != desc ) + { + ret = useBuffers(CameraAdapter::CAMERA_IMAGE_CAPTURE, + desc->mBuffers, + desc->mCount, + desc->mLength, + desc->mMaxQueueable); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_START_SMOOTH_ZOOM: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startSmoothZoom(value1); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopSmoothZoom(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_PREVIEW: + { + + CAMHAL_LOGDA("Start Preview"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startPreview(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_PREVIEW: + { + + CAMHAL_LOGDA("Stop Preview"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopPreview(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_VIDEO: + { + + CAMHAL_LOGDA("Start video recording"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startVideoCapture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_VIDEO: + { + + CAMHAL_LOGDA("Stop video recording"); + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopVideoCapture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_PREVIEW_FLUSH_BUFFERS: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = flushBuffers(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_IMAGE_CAPTURE: + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + refTimestamp = ( struct timeval * ) value1; + if ( NULL != refTimestamp ) + { + memcpy( &mStartCapture, refTimestamp, sizeof( struct timeval )); + } + +#endif + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = takePicture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopImageCapture(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_START_BRACKET_CAPTURE: + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + refTimestamp = ( struct timeval * ) value2; + if ( NULL != refTimestamp ) + { + memcpy( &mStartCapture, refTimestamp, sizeof( struct timeval )); + } + +#endif + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = startBracketing(value1); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE: + { + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = stopBracketing(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + } + + case CameraAdapter::CAMERA_PERFORM_AUTOFOCUS: + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + refTimestamp = ( struct timeval * ) value1; + if ( NULL != refTimestamp ) + { + memcpy( &mStartFocus, refTimestamp, sizeof( struct timeval )); + } + +#endif + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = autoFocus(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_CANCEL_AUTOFOCUS: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + ret = cancelAutoFocus(); + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + frame = ( CameraFrame * ) value1; + + if ( NULL != frame ) + { + ret = getFrameSize(frame->mWidth, frame->mHeight); + } + else + { + ret = -EINVAL; + } + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + frame = ( CameraFrame * ) value1; + + if ( NULL != frame ) + { + ret = getPictureBufferSize(frame->mLength, value2); + } + else + { + ret = -EINVAL; + } + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA: + + if ( ret == NO_ERROR ) + { + ret = setState(operation); + } + + if ( ret == NO_ERROR ) + { + frame = ( CameraFrame * ) value1; + + if ( NULL != frame ) + { + ret = getFrameDataSize(frame->mLength, value2); + } + else + { + ret = -EINVAL; + } + } + + if ( ret == NO_ERROR ) + { + ret = commitState(); + } + else + { + ret |= rollbackState(); + } + + break; + + case CameraAdapter::CAMERA_START_FD: + + ret = startFaceDetection(); + + break; + + case CameraAdapter::CAMERA_STOP_FD: + + ret = stopFaceDetection(); + + break; + + default: + CAMHAL_LOGEB("Command 0x%x unsupported!", operation); + break; + }; + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +status_t BaseCameraAdapter::notifyFocusSubscribers(bool status) +{ + event_callback eventCb; + CameraHalEvent focusEvent; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mFocusSubscribers.size() == 0 ) { + CAMHAL_LOGDA("No Focus Subscribers!"); + return NO_INIT; + } + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //dump the AF latency + CameraHal::PPM("Focus finished in: ", &mStartFocus); + +#endif + + focusEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == focusEvent.mEventData.get() ) { + return -ENOMEM; + } + + focusEvent.mEventType = CameraHalEvent::EVENT_FOCUS_LOCKED; + focusEvent.mEventData->focusEvent.focusLocked = status; + focusEvent.mEventData->focusEvent.focusError = !status; + + for (unsigned int i = 0 ; i < mFocusSubscribers.size(); i++ ) + { + focusEvent.mCookie = (void *) mFocusSubscribers.keyAt(i); + eventCb = (event_callback) mFocusSubscribers.valueAt(i); + eventCb ( &focusEvent ); + } + + focusEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::notifyShutterSubscribers() +{ + CameraHalEvent shutterEvent; + event_callback eventCb; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mShutterSubscribers.size() == 0 ) + { + CAMHAL_LOGEA("No shutter Subscribers!"); + return NO_INIT; + } + + shutterEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == shutterEvent.mEventData.get() ) { + return -ENOMEM; + } + + shutterEvent.mEventType = CameraHalEvent::EVENT_SHUTTER; + shutterEvent.mEventData->shutterEvent.shutterClosed = true; + + for (unsigned int i = 0 ; i < mShutterSubscribers.size() ; i++ ) { + shutterEvent.mCookie = ( void * ) mShutterSubscribers.keyAt(i); + eventCb = ( event_callback ) mShutterSubscribers.valueAt(i); + + CAMHAL_LOGEA("Sending shutter callback"); + + eventCb ( &shutterEvent ); + } + + shutterEvent.mEventData.clear(); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t BaseCameraAdapter::notifyZoomSubscribers(int zoomIdx, bool targetReached) +{ + event_callback eventCb; + CameraHalEvent zoomEvent; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mZoomSubscribers.size() == 0 ) { + CAMHAL_LOGDA("No zoom Subscribers!"); + return NO_INIT; + } + + zoomEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == zoomEvent.mEventData.get() ) { + return -ENOMEM; + } + + zoomEvent.mEventType = CameraHalEvent::EVENT_ZOOM_INDEX_REACHED; + zoomEvent.mEventData->zoomEvent.currentZoomIndex = zoomIdx; + zoomEvent.mEventData->zoomEvent.targetZoomIndexReached = targetReached; + + for (unsigned int i = 0 ; i < mZoomSubscribers.size(); i++ ) { + zoomEvent.mCookie = (void *) mZoomSubscribers.keyAt(i); + eventCb = (event_callback) mZoomSubscribers.valueAt(i); + + eventCb ( &zoomEvent ); + } + + zoomEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::notifyFaceSubscribers(sp<CameraFDResult> &faces) +{ + event_callback eventCb; + CameraHalEvent faceEvent; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( mFaceSubscribers.size() == 0 ) { + CAMHAL_LOGDA("No face detection subscribers!"); + return NO_INIT; + } + + faceEvent.mEventData = new CameraHalEvent::CameraHalEventData(); + if ( NULL == faceEvent.mEventData.get() ) { + return -ENOMEM; + } + + faceEvent.mEventType = CameraHalEvent::EVENT_FACE; + faceEvent.mEventData->faceEvent = faces; + + for (unsigned int i = 0 ; i < mFaceSubscribers.size(); i++ ) { + faceEvent.mCookie = (void *) mFaceSubscribers.keyAt(i); + eventCb = (event_callback) mFaceSubscribers.valueAt(i); + + eventCb ( &faceEvent ); + } + + faceEvent.mEventData.clear(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::sendFrameToSubscribers(CameraFrame *frame) +{ + status_t ret = NO_ERROR; + frame_callback callback; + uint32_t i = 0; + KeyedVector<int, frame_callback> *subscribers = NULL; + size_t refCount = 0; + + if ( NULL == frame ) + { + CAMHAL_LOGEA("Invalid CameraFrame"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + + switch(frame->mFrameType) + { + case CameraFrame::IMAGE_FRAME: + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + CameraHal::PPM("Shot to Jpeg: ", &mStartCapture); + +#endif + + subscribers = &mImageSubscribers; + break; + } + case CameraFrame::RAW_FRAME: + { + subscribers = &mRawSubscribers; + break; + } + case CameraFrame::VIDEO_FRAME_SYNC: + { + subscribers = &mVideoSubscribers; + break; + } + case CameraFrame::FRAME_DATA_SYNC: + { + subscribers = &mFrameDataSubscribers; + break; + } + case CameraFrame::PREVIEW_FRAME_SYNC: + case CameraFrame::SNAPSHOT_FRAME: + { + subscribers = &mFrameSubscribers; + break; + } + default: + { + ret = -EINVAL; + break; + } + }; + + } + + if ( ( NO_ERROR == ret ) && + ( NULL != subscribers ) ) + { + Mutex::Autolock lock(mSubscriberLock); + + refCount = subscribers->size(); + CAMHAL_LOGVB("Type of Frame: 0x%x address: 0x%x refCount start %d", + frame->mFrameType, + ( uint32_t ) frame->mBuffer, + refCount); + + setFrameRefCount(frame->mBuffer, + ( CameraFrame::FrameType ) frame->mFrameType, + refCount); + + for ( i = 0 ; i < subscribers->size(); i++ ) + { + frame->mCookie = ( void * ) subscribers->keyAt(i); + callback = (frame_callback) subscribers->valueAt(i); + callback(frame); + } + } + + if ( 0 == i ) + { + //No subscribers for this frame + ret = -1; + } + + return ret; +} + +int BaseCameraAdapter::getFrameRefCount(void* frameBuf, CameraFrame::FrameType frameType) +{ + int res = -1; + + LOG_FUNCTION_NAME; + + switch ( frameType ) + { + case CameraFrame::IMAGE_FRAME: + case CameraFrame::RAW_FRAME: + { + Mutex::Autolock lock(mCaptureBufferLock); + res = mCaptureBuffersAvailable.valueFor( ( unsigned int ) frameBuf ); + } + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + case CameraFrame::SNAPSHOT_FRAME: + { + Mutex::Autolock lock(mPreviewBufferLock); + res = mPreviewBuffersAvailable.valueFor( ( unsigned int ) frameBuf ); + } + break; + case CameraFrame::FRAME_DATA_SYNC: + { + Mutex::Autolock lock(mPreviewDataBufferLock); + res = mPreviewDataBuffersAvailable.valueFor( ( unsigned int ) frameBuf ); + } + break; + case CameraFrame::VIDEO_FRAME_SYNC: + { + Mutex::Autolock lock(mVideoBufferLock); + res = mVideoBuffersAvailable.valueFor( ( unsigned int ) frameBuf ); + } + break; + default: + break; + }; + + LOG_FUNCTION_NAME_EXIT; + + return res; +} + +void BaseCameraAdapter::setFrameRefCount(void* frameBuf, CameraFrame::FrameType frameType, int refCount) +{ + + LOG_FUNCTION_NAME; + + switch ( frameType ) + { + case CameraFrame::IMAGE_FRAME: + case CameraFrame::RAW_FRAME: + { + Mutex::Autolock lock(mCaptureBufferLock); + mCaptureBuffersAvailable.replaceValueFor( ( unsigned int ) frameBuf, refCount); + } + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + case CameraFrame::SNAPSHOT_FRAME: + { + Mutex::Autolock lock(mPreviewBufferLock); + mPreviewBuffersAvailable.replaceValueFor( ( unsigned int ) frameBuf, refCount); + } + break; + case CameraFrame::FRAME_DATA_SYNC: + { + Mutex::Autolock lock(mPreviewDataBufferLock); + mPreviewDataBuffersAvailable.replaceValueFor( ( unsigned int ) frameBuf, refCount); + } + break; + case CameraFrame::VIDEO_FRAME_SYNC: + { + Mutex::Autolock lock(mVideoBufferLock); + mVideoBuffersAvailable.replaceValueFor( ( unsigned int ) frameBuf, refCount); + } + break; + default: + break; + }; + + LOG_FUNCTION_NAME_EXIT; + +} + +status_t BaseCameraAdapter::startVideoCapture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mVideoBufferLock); + + //If the capture is already ongoing, return from here. + if ( mRecording ) + { + ret = NO_INIT; + } + + + if ( NO_ERROR == ret ) + { + + for ( unsigned int i = 0 ; i < mPreviewBuffersAvailable.size() ; i++ ) + { + mVideoBuffersAvailable.add(mPreviewBuffersAvailable.keyAt(i), 0); + } + + mRecording = true; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopVideoCapture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( !mRecording ) + { + ret = NO_INIT; + } + + if ( NO_ERROR == ret ) + { + for ( unsigned int i = 0 ; i < mVideoBuffersAvailable.size() ; i++ ) + { + void *frameBuf = ( void * ) mVideoBuffersAvailable.keyAt(i); + if( getFrameRefCount(frameBuf, CameraFrame::VIDEO_FRAME_SYNC) > 0) + { + returnFrame(frameBuf, CameraFrame::VIDEO_FRAME_SYNC); + } + } + + mVideoBuffersAvailable.clear(); + + mRecording = false; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//-----------------Stub implementation of the interface ------------------------------ + +status_t BaseCameraAdapter::takePicture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopImageCapture() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startBracketing(int range) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopBracketing() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::autoFocus() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + notifyFocusSubscribers(false); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::cancelAutoFocus() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startSmoothZoom(int targetIdx) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopSmoothZoom() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startPreview() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopPreview() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::useBuffers(CameraMode mode, void* bufArr, int num, size_t length, unsigned int queueable) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getFrameSize(size_t &width, size_t &height) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getPictureBufferSize(size_t &length, size_t bufferCount) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::startFaceDetection() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::stopFaceDetection() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::setState(CameraCommands operation) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mLock.lock(); + + switch ( mAdapterState ) + { + + case INTIALIZED_STATE: + + switch ( operation ) + { + + case CAMERA_USE_BUFFERS_PREVIEW: + CAMHAL_LOGDB("Adapter state switch INTIALIZED_STATE->LOADED_PREVIEW_STATE event = 0x%x", + operation); + mNextState = LOADED_PREVIEW_STATE; + break; + + //These events don't change the current state + case CAMERA_QUERY_RESOLUTION_PREVIEW: + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA: + CAMHAL_LOGDB("Adapter state switch INTIALIZED_STATE->INTIALIZED_STATE event = 0x%x", + operation); + mNextState = INTIALIZED_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch INTIALIZED_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case LOADED_PREVIEW_STATE: + + switch ( operation ) + { + + case CAMERA_START_PREVIEW: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW_STATE->PREVIEW_STATE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + //These events don't change the current state + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA: + case CAMERA_USE_BUFFERS_PREVIEW_DATA: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW_STATE->LOADED_PREVIEW_STATE event = 0x%x", + operation); + mNextState = LOADED_PREVIEW_STATE; + break; + + default: + CAMHAL_LOGDB("Adapter state switch LOADED_PREVIEW Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case PREVIEW_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_PREVIEW: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->INTIALIZED_STATE event = 0x%x", + operation); + mNextState = INTIALIZED_STATE; + break; + + case CAMERA_PERFORM_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->AF_STATE event = 0x%x", + operation); + mNextState = AF_STATE; + break; + + case CAMERA_START_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->ZOOM_STATE event = 0x%x", + operation); + mNextState = ZOOM_STATE; + break; + + case CAMERA_USE_BUFFERS_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->LOADED_CAPTURE_STATE event = 0x%x", + operation); + mNextState = LOADED_CAPTURE_STATE; + break; + + case CAMERA_START_VIDEO: + CAMHAL_LOGDB("Adapter state switch PREVIEW_STATE->VIDEO_STATE event = 0x%x", + operation); + mNextState = VIDEO_STATE; + break; + + case CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE: + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch PREVIEW_ACTIVE->PREVIEW_ACTIVE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch PREVIEW_ACTIVE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case LOADED_CAPTURE_STATE: + + switch ( operation ) + { + + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_CAPTURE_STATE->CAPTURE_STATE event = 0x%x", + operation); + mNextState = CAPTURE_STATE; + break; + + case CAMERA_START_BRACKET_CAPTURE: + CAMHAL_LOGDB("Adapter state switch LOADED_CAPTURE_STATE->BRACKETING_STATE event = 0x%x", + operation); + mNextState = BRACKETING_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch LOADED_CAPTURE_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case CAPTURE_STATE: + + switch ( operation ) + { + case CAMERA_STOP_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch CAPTURE_STATE->PREVIEW_STATE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch CAPTURE_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case BRACKETING_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_BRACKET_CAPTURE: + CAMHAL_LOGDB("Adapter state switch BRACKETING_STATE->PREVIEW_STATE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_START_IMAGE_CAPTURE: + CAMHAL_LOGDB("Adapter state switch BRACKETING_STATE->CAPTURE_STATE event = 0x%x", + operation); + mNextState = CAPTURE_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch BRACKETING_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case AF_STATE: + + switch ( operation ) + { + + case CAMERA_CANCEL_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch AF_STATE->PREVIEW_STATE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_START_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch AF_STATE->AF_ZOOM_STATE event = 0x%x", + operation); + mNextState = AF_ZOOM_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch AF_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch ZOOM_STATE->PREVIEW_STATE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + case CAMERA_PERFORM_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch ZOOM_STATE->AF_ZOOM_STATE event = 0x%x", + operation); + mNextState = AF_ZOOM_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch ZOOM_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_VIDEO: + CAMHAL_LOGDB("Adapter state switch VIDEO_STATE->PREVIEW_STATE event = 0x%x", + operation); + mNextState = PREVIEW_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch VIDEO_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case AF_ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch AF_ZOOM_STATE->AF_STATE event = 0x%x", + operation); + mNextState = AF_STATE; + break; + + case CAMERA_CANCEL_AUTOFOCUS: + CAMHAL_LOGDB("Adapter state switch AF_ZOOM_STATE->ZOOM_STATE event = 0x%x", + operation); + mNextState = ZOOM_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch AF_ZOOM_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case VIDEO_ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch VIDEO_ZOOM_STATE->VIDEO_STATE event = 0x%x", + operation); + mNextState = VIDEO_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch VIDEO_ZOOM_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + case BRACKETING_ZOOM_STATE: + + switch ( operation ) + { + + case CAMERA_STOP_SMOOTH_ZOOM: + CAMHAL_LOGDB("Adapter state switch BRACKETING_ZOOM_STATE->BRACKETING_STATE event = 0x%x", + operation); + mNextState = BRACKETING_STATE; + break; + + default: + CAMHAL_LOGEB("Adapter state switch BRACKETING_ZOOM_STATE Invalid Op! event = 0x%x", + operation); + ret = INVALID_OPERATION; + break; + + } + + break; + + default: + CAMHAL_LOGEA("Invalid Adapter state!"); + ret = INVALID_OPERATION; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +//State transition finished successfully. +//Commit the state and unlock the adapter state. +status_t BaseCameraAdapter::commitState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mAdapterState = mNextState; + + mLock.unlock(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::rollbackState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + mNextState = mAdapterState; + + mLock.unlock(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// getNextState() and getState() +// publicly exposed functions to retrieve the adapter states +// please notice that these functions are locked +CameraAdapter::AdapterState BaseCameraAdapter::getState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mLock); + + LOG_FUNCTION_NAME_EXIT; + + return mAdapterState; +} + +CameraAdapter::AdapterState BaseCameraAdapter::getNextState() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mLock); + + LOG_FUNCTION_NAME_EXIT; + + return mNextState; +} + +// getNextState() and getState() +// internal protected functions to retrieve the adapter states +// please notice that these functions are NOT locked to help +// internal functions query state in the middle of state +// transition +status_t BaseCameraAdapter::getState(AdapterState &state) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + state = mAdapterState; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t BaseCameraAdapter::getNextState(AdapterState &state) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + state = mNextState; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void BaseCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) +{ + LOG_FUNCTION_NAME; + LOG_FUNCTION_NAME_EXIT; +} +//----------------------------------------------------------------------------- + + + +}; + +/*--------------------Camera Adapter Class ENDS here-----------------------------*/ + diff --git a/camera/CameraHal.cpp b/camera/CameraHal.cpp new file mode 100755 index 0000000..53bc377 --- /dev/null +++ b/camera/CameraHal.cpp @@ -0,0 +1,3030 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 CameraHal.cpp +* +* This file maps the Camera Hardware Interface to V4L2. +* +*/ + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "ANativeWindowDisplayAdapter.h" +#include "TICameraParameters.h" +#include "CameraProperties.h" +#include <cutils/properties.h> + +#include <poll.h> +#include <math.h> + +namespace android { + +extern "C" CameraAdapter* CameraAdapter_Factory(); + +/*****************************************************************************/ + +////Constant definitions and declarations +////@todo Have a CameraProperties class to store these parameters as constants for every camera +//// Currently, they are hard-coded + +const int CameraHal::NO_BUFFERS_PREVIEW = MAX_CAMERA_BUFFERS; +const int CameraHal::NO_BUFFERS_IMAGE_CAPTURE = 2; + +const uint32_t MessageNotifier::EVENT_BIT_FIELD_POSITION = 0; +const uint32_t MessageNotifier::FRAME_BIT_FIELD_POSITION = 0; + +/******************************************************************************/ + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +struct timeval CameraHal::mStartPreview; +struct timeval CameraHal::mStartFocus; +struct timeval CameraHal::mStartCapture; + +#endif + +static void orientation_cb(uint32_t orientation, uint32_t tilt, void* cookie) { + CameraHal *camera = NULL; + + if (cookie) { + camera = (CameraHal*) cookie; + camera->onOrientationEvent(orientation, tilt); + } + +} +/*-------------Camera Hal Interface Method definitions STARTS here--------------------*/ + +/** + Callback function to receive orientation events from SensorListener + */ +void CameraHal::onOrientationEvent(uint32_t orientation, uint32_t tilt) { + LOG_FUNCTION_NAME; + + if ( NULL != mCameraAdapter ) { + mCameraAdapter->onOrientationEvent(orientation, tilt); + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Set the notification and data callbacks + + @param[in] notify_cb Notify callback for notifying the app about events and errors + @param[in] data_cb Buffer callback for sending the preview/raw frames to the app + @param[in] data_cb_timestamp Buffer callback for sending the video frames w/ timestamp + @param[in] user Callback cookie + @return none + + */ +void CameraHal::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) +{ + LOG_FUNCTION_NAME; + + if ( NULL != mAppCallbackNotifier.get() ) + { + mAppCallbackNotifier->setCallbacks(this, + notify_cb, + data_cb, + data_cb_timestamp, + get_memory, + user); + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Enable a message, or set of messages. + + @param[in] msgtype Bitmask of the messages to enable (defined in include/ui/Camera.h) + @return none + + */ +void CameraHal::enableMsgType(int32_t msgType) +{ + LOG_FUNCTION_NAME; + + if ( ( msgType & CAMERA_MSG_SHUTTER ) && ( !mShutterEnabled ) ) + { + msgType &= ~CAMERA_MSG_SHUTTER; + } + + { + Mutex::Autolock lock(mLock); + mMsgEnabled |= msgType; + } + + if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + { + if(mDisplayPaused) + { + CAMHAL_LOGDA("Preview currently paused...will enable preview callback when restarted"); + msgType &= ~CAMERA_MSG_PREVIEW_FRAME; + }else + { + CAMHAL_LOGDA("Enabling Preview Callback"); + } + } + else + { + CAMHAL_LOGDB("Preview callback not enabled %x", msgType); + } + + + ///Configure app callback notifier with the message callback required + mAppCallbackNotifier->enableMsgType (msgType); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Disable a message, or set of messages. + + @param[in] msgtype Bitmask of the messages to disable (defined in include/ui/Camera.h) + @return none + + */ +void CameraHal::disableMsgType(int32_t msgType) +{ + LOG_FUNCTION_NAME; + + { + Mutex::Autolock lock(mLock); + mMsgEnabled &= ~msgType; + } + + if( msgType & CAMERA_MSG_PREVIEW_FRAME) + { + CAMHAL_LOGDA("Disabling Preview Callback"); + } + + ///Configure app callback notifier + mAppCallbackNotifier->disableMsgType (msgType); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief 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. + + @param[in] msgtype Bitmask of the messages to query (defined in include/ui/Camera.h) + @return true If all message types are enabled + false If any message type + + */ +int CameraHal::msgTypeEnabled(int32_t msgType) +{ + LOG_FUNCTION_NAME; + Mutex::Autolock lock(mLock); + LOG_FUNCTION_NAME_EXIT; + return (mMsgEnabled & msgType); +} + +/** + @brief Set the camera parameters. + + @param[in] params Camera parameters to configure the camera + @return NO_ERROR + @todo Define error codes + + */ +int CameraHal::setParameters(const char* parameters) +{ + + LOG_FUNCTION_NAME; + + CameraParameters params; + + String8 str_params(parameters); + params.unflatten(str_params); + + LOG_FUNCTION_NAME_EXIT; + + return setParameters(params); +} + +/** + @brief Set the camera parameters. + + @param[in] params Camera parameters to configure the camera + @return NO_ERROR + @todo Define error codes + + */ +int CameraHal::setParameters(const CameraParameters& params) +{ + + LOG_FUNCTION_NAME; + + int w, h; + int w_orig, h_orig; + int framerate,minframerate; + bool framerateUpdated = true; + int maxFPS, minFPS; + int error; + int base; + const char *valstr = NULL; + const char *prevFormat; + char *af_coord; + TIUTILS::Message msg; + status_t ret = NO_ERROR; + + Mutex::Autolock lock(mLock); + + ///Ensure that preview is not enabled when the below parameters are changed. + if(!previewEnabled()) + { + + CAMHAL_LOGDB("PreviewFormat %s", params.getPreviewFormat()); + + if ( !isParameterValid(params.getPreviewFormat(), mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FORMATS))) + { + CAMHAL_LOGEB("Invalid preview format %s", mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FORMATS)); + return -EINVAL; + } + else + { + if ( (valstr = params.getPreviewFormat()) != NULL) + mParameters.setPreviewFormat(valstr); + } + + params.getPreviewSize(&w, &h); + if (w == -1 && h == -1) { + CAMHAL_LOGEA("Unable to get preview size"); + return ret; + } + + int orientation =0; + if((valstr = params.get(TICameraParameters::KEY_SENSOR_ORIENTATION)) != NULL) + { + CAMHAL_LOGDB("Sensor Orientation is set to %s", params.get(TICameraParameters::KEY_SENSOR_ORIENTATION)); + mParameters.set(TICameraParameters::KEY_SENSOR_ORIENTATION, valstr); + orientation = params.getInt(TICameraParameters::KEY_SENSOR_ORIENTATION); + } + + if(orientation ==90 || orientation ==270) + { + if ( !isResolutionValid(h,w, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIZES))) + { + CAMHAL_LOGEB("Invalid preview resolution %d x %d", w, h); + return -EINVAL; + } + else + { + mParameters.setPreviewSize(w, h); + } + } + else + { + if ( !isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIZES))) + { + CAMHAL_LOGEB("Invalid preview resolution %d x %d", w, h); + return -EINVAL; + } + else + { + mParameters.setPreviewSize(w, h); + } + } + + CAMHAL_LOGDB("PreviewResolution by App %d x %d", w, h); + + if(( (valstr = params.get(TICameraParameters::KEY_VNF)) != NULL) + && ((params.getInt(TICameraParameters::KEY_VNF)==0) || (params.getInt(TICameraParameters::KEY_VNF)==1))) + { + CAMHAL_LOGDB("VNF set %s", params.get(TICameraParameters::KEY_VNF)); + mParameters.set(TICameraParameters::KEY_VNF, valstr); + } + + if(( (valstr = params.get(TICameraParameters::KEY_VSTAB)) != NULL) + && ((params.getInt(TICameraParameters::KEY_VSTAB)==0) || (params.getInt(TICameraParameters::KEY_VSTAB)==1))) + { + CAMHAL_LOGDB("VSTAB set %s", params.get(TICameraParameters::KEY_VSTAB)); + mParameters.set(TICameraParameters::KEY_VSTAB, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_CAP_MODE)) != NULL) + { + CAMHAL_LOGDB("Capture mode set %s", params.get(TICameraParameters::KEY_CAP_MODE)); + mParameters.set(TICameraParameters::KEY_CAP_MODE, valstr); + } + + if((valstr = params.get(TICameraParameters::KEY_IPP)) != NULL) + { + CAMHAL_LOGDB("IPP mode set %s", params.get(TICameraParameters::KEY_IPP)); + mParameters.set(TICameraParameters::KEY_IPP, valstr); + } + + if((valstr = params.get(TICameraParameters::KEY_S3D2D_PREVIEW)) != NULL) + { + CAMHAL_LOGDB("Stereo 3D->2D Preview mode is %s", params.get(TICameraParameters::KEY_S3D2D_PREVIEW)); + mParameters.set(TICameraParameters::KEY_S3D2D_PREVIEW, valstr); + } + + if((valstr = params.get(TICameraParameters::KEY_AUTOCONVERGENCE)) != NULL) + { + CAMHAL_LOGDB("AutoConvergence mode is %s", params.get(TICameraParameters::KEY_AUTOCONVERGENCE)); + mParameters.set(TICameraParameters::KEY_AUTOCONVERGENCE, valstr); + } + if((valstr = params.get(TICameraParameters::KEY_SENSOR_ORIENTATION)) != NULL) + { + CAMHAL_LOGDB("Sensor Orientation is set to %s", params.get(TICameraParameters::KEY_SENSOR_ORIENTATION)); + mParameters.set(TICameraParameters::KEY_SENSOR_ORIENTATION, valstr); + } + + } + + ///Below parameters can be changed when the preview is running + if ( !isParameterValid(params.getPictureFormat(), + mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_FORMATS))) + { + CAMHAL_LOGEA("Invalid picture format"); + return -EINVAL; + } + else + { + valstr = params.getPictureFormat(); + if (valstr) + mParameters.setPictureFormat(valstr); + } + + params.getPictureSize(&w, &h); + if ( !isResolutionValid(w, h, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SIZES))) + { + CAMHAL_LOGEB("Invalid picture resolution %dx%d", w, h); + return -EINVAL; + } + else + { + mParameters.setPictureSize(w, h); + } + + CAMHAL_LOGDB("Picture Size by App %d x %d", w, h); + + if(( (valstr = params.get(TICameraParameters::KEY_BURST)) != NULL) + && (params.getInt(TICameraParameters::KEY_BURST) >=0)) + { + CAMHAL_LOGDB("Burst set %s", params.get(TICameraParameters::KEY_BURST)); + mParameters.set(TICameraParameters::KEY_BURST, valstr); + } + + framerate = params.getPreviewFrameRate(); + if ( isParameterValid(framerate, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES))) + { + if ( mLastPreviewFramerate != framerate ) + { + mLastPreviewFramerate = framerate; + mParameters.setPreviewFrameRate(framerate); + framerateUpdated = true; + } + else + { + framerateUpdated = false; + } + } + else + { + framerateUpdated = false; + } + + CAMHAL_LOGDB("FRAMERATE %d", framerate); + + //If client uses fixed framerate than + //give it a higher piority than VFR. + if ( framerateUpdated ) + { + + minFPS = framerate; + maxFPS = framerate; + + CAMHAL_LOGDB("FPS Range [%d, %d]", minFPS, maxFPS); + mParameters.set(TICameraParameters::KEY_MINFRAMERATE, minFPS); + mParameters.set(TICameraParameters::KEY_MAXFRAMERATE, maxFPS); + mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, params.get(CameraParameters::KEY_PREVIEW_FPS_RANGE)); + } + else if ( ( valstr = params.get(CameraParameters::KEY_PREVIEW_FPS_RANGE) ) != NULL ) + { + CAMHAL_LOGDB("FPS Range = %s", valstr); + params.getPreviewFpsRange(&minFPS, &maxFPS); + + if ( ( 0 > minFPS ) || ( 0 > maxFPS ) ) + { + CAMHAL_LOGEA("FPS Range is negative!"); + return -EINVAL; + } + + minFPS /= CameraHal::VFR_SCALE; + maxFPS /= CameraHal::VFR_SCALE; + + if ( ( 0 == minFPS ) || ( 0 == maxFPS ) ) + { + CAMHAL_LOGEA("FPS Range is invalid!"); + return -EINVAL; + } + + if ( maxFPS < minFPS ) + { + CAMHAL_LOGEA("Max FPS is smaller than Min FPS!"); + return -EINVAL; + } + + if ( maxFPS > framerate ) + { + framerate = maxFPS; + mParameters.setPreviewFrameRate(framerate); + } + + CAMHAL_LOGDB("FPS Range [%d, %d]", minFPS, maxFPS); + mParameters.set(TICameraParameters::KEY_MINFRAMERATE, minFPS); + mParameters.set(TICameraParameters::KEY_MAXFRAMERATE, maxFPS); + mParameters.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, valstr); + } + + if( ( valstr = params.get(TICameraParameters::KEY_GBCE) ) != NULL ) + { + CAMHAL_LOGDB("GBCE Value = %s", valstr); + mParameters.set(TICameraParameters::KEY_GBCE, valstr); + } + + if( ( valstr = params.get(TICameraParameters::KEY_GLBCE) ) != NULL ) + { + CAMHAL_LOGDB("GLBCE Value = %s", valstr); + mParameters.set(TICameraParameters::KEY_GLBCE, valstr); + } + + ///Update the current parameter set + if( (valstr = params.get(TICameraParameters::KEY_AUTOCONVERGENCE)) != NULL) + { + CAMHAL_LOGDB("AutoConvergence Mode is set = %s", params.get(TICameraParameters::KEY_AUTOCONVERGENCE)); + mParameters.set(TICameraParameters::KEY_AUTOCONVERGENCE, valstr); + } + +// if(params.get(TICameraParameters::KEY_AUTOCONVERGENCE_MODE)!=NULL) +// { +// CAMHAL_LOGDB("AutoConvergence Mode is set = %s", params.get(TICameraParameters::KEY_AUTOCONVERGENCE_MODE)); +// mParameters.set(TICameraParameters::KEY_AUTOCONVERGENCE_MODE, params.get(TICameraParameters::KEY_AUTOCONVERGENCE_MODE)); +// } + + if( (valstr = params.get(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES)) !=NULL ) + { + CAMHAL_LOGDB("ManualConvergence Value = %s", params.get(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES)); + mParameters.set(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES, valstr); + } + + if( ((valstr = params.get(TICameraParameters::KEY_EXPOSURE_MODE)) != NULL) + && isParameterValid(params.get(TICameraParameters::KEY_EXPOSURE_MODE), + mCameraProperties->get(CameraProperties::SUPPORTED_EXPOSURE_MODES))) + { + CAMHAL_LOGDB("Exposure set = %s", params.get(TICameraParameters::KEY_EXPOSURE_MODE)); + mParameters.set(TICameraParameters::KEY_EXPOSURE_MODE, valstr); + } + + if( ((valstr = params.get(CameraParameters::KEY_WHITE_BALANCE)) != NULL) + && isParameterValid(params.get(CameraParameters::KEY_WHITE_BALANCE), + mCameraProperties->get(CameraProperties::SUPPORTED_WHITE_BALANCE))) + { + CAMHAL_LOGDB("White balance set %s", params.get(CameraParameters::KEY_WHITE_BALANCE)); + mParameters.set(CameraParameters::KEY_WHITE_BALANCE, valstr); + } + + if( ((valstr = params.get(TICameraParameters::KEY_CONTRAST)) != NULL) + && (params.getInt(TICameraParameters::KEY_CONTRAST) >= 0 )) + { + CAMHAL_LOGDB("Contrast set %s", params.get(TICameraParameters::KEY_CONTRAST)); + mParameters.set(TICameraParameters::KEY_CONTRAST, valstr); + } + + if( ((valstr =params.get(TICameraParameters::KEY_SHARPNESS)) != NULL) && params.getInt(TICameraParameters::KEY_SHARPNESS) >= 0 ) + { + CAMHAL_LOGDB("Sharpness set %s", params.get(TICameraParameters::KEY_SHARPNESS)); + mParameters.set(TICameraParameters::KEY_SHARPNESS, valstr); + } + + + if( ((valstr = params.get(TICameraParameters::KEY_SATURATION)) != NULL) + && (params.getInt(TICameraParameters::KEY_SATURATION) >= 0 ) ) + { + CAMHAL_LOGDB("Saturation set %s", params.get(TICameraParameters::KEY_SATURATION)); + mParameters.set(TICameraParameters::KEY_SATURATION, valstr); + } + + if( ((valstr = params.get(TICameraParameters::KEY_BRIGHTNESS)) != NULL) + && (params.getInt(TICameraParameters::KEY_BRIGHTNESS) >= 0 )) + { + CAMHAL_LOGDB("Brightness set %s", params.get(TICameraParameters::KEY_BRIGHTNESS)); + mParameters.set(TICameraParameters::KEY_BRIGHTNESS, valstr); + } + + + if( ((valstr = params.get(CameraParameters::KEY_ANTIBANDING)) != NULL) + && isParameterValid(params.get(CameraParameters::KEY_ANTIBANDING), + mCameraProperties->get(CameraProperties::SUPPORTED_ANTIBANDING))) + { + CAMHAL_LOGDB("Antibanding set %s", params.get(CameraParameters::KEY_ANTIBANDING)); + mParameters.set(CameraParameters::KEY_ANTIBANDING, valstr); + } + + if( ((valstr = params.get(TICameraParameters::KEY_ISO)) != NULL) + && isParameterValid(params.get(TICameraParameters::KEY_ISO), + mCameraProperties->get(CameraProperties::SUPPORTED_ISO_VALUES))) + { + CAMHAL_LOGDB("ISO set %s", params.get(TICameraParameters::KEY_ISO)); + mParameters.set(TICameraParameters::KEY_ISO, valstr); + } + + if( ((valstr = params.get(CameraParameters::KEY_FOCUS_MODE)) != NULL) + && isParameterValid(params.get(CameraParameters::KEY_FOCUS_MODE), + mCameraProperties->get(CameraProperties::SUPPORTED_FOCUS_MODES))) + { + CAMHAL_LOGDB("Focus mode set %s", params.get(CameraParameters::KEY_FOCUS_MODE)); + mParameters.set(CameraParameters::KEY_FOCUS_MODE, valstr); + } + + if( (valstr = params.get(CameraParameters::KEY_FOCUS_AREAS)) != NULL ) + { + CAMHAL_LOGEB("Focus areas position set %s", params.get(CameraParameters::KEY_FOCUS_AREAS)); + mParameters.set(CameraParameters::KEY_FOCUS_AREAS, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_MEASUREMENT_ENABLE)) != NULL ) + { + CAMHAL_LOGDB("Measurements set to %s", params.get(TICameraParameters::KEY_MEASUREMENT_ENABLE)); + mParameters.set(TICameraParameters::KEY_MEASUREMENT_ENABLE, valstr); + + if (strcmp(valstr, (const char *) TICameraParameters::MEASUREMENT_ENABLE) == 0) + { + mMeasurementEnabled = true; + } + else if (strcmp(valstr, (const char *) TICameraParameters::MEASUREMENT_DISABLE) == 0) + { + mMeasurementEnabled = false; + } + else + { + mMeasurementEnabled = false; + } + + } + + if( (valstr = params.get(CameraParameters::KEY_EXPOSURE_COMPENSATION)) != NULL) + { + CAMHAL_LOGDB("Exposure compensation set %s", params.get(CameraParameters::KEY_EXPOSURE_COMPENSATION)); + mParameters.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_SCENE_MODE)) != NULL) + && isParameterValid(params.get(CameraParameters::KEY_SCENE_MODE), + mCameraProperties->get(CameraProperties::SUPPORTED_SCENE_MODES))) + { + CAMHAL_LOGDB("Scene mode set %s", params.get(CameraParameters::KEY_SCENE_MODE)); + mParameters.set(CameraParameters::KEY_SCENE_MODE, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_FLASH_MODE)) != NULL) + && isParameterValid(params.get(CameraParameters::KEY_FLASH_MODE), + mCameraProperties->get(CameraProperties::SUPPORTED_FLASH_MODES))) + { + CAMHAL_LOGDB("Flash mode set %s", params.get(CameraParameters::KEY_FLASH_MODE)); + mParameters.set(CameraParameters::KEY_FLASH_MODE, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_EFFECT)) != NULL) + && isParameterValid(params.get(CameraParameters::KEY_EFFECT), + mCameraProperties->get(CameraProperties::SUPPORTED_EFFECTS))) + { + CAMHAL_LOGDB("Effect set %s", params.get(CameraParameters::KEY_EFFECT)); + mParameters.set(CameraParameters::KEY_EFFECT, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_ROTATION)) != NULL) + && (params.getInt(CameraParameters::KEY_ROTATION) >=0)) + { + CAMHAL_LOGDB("Rotation set %s", params.get(CameraParameters::KEY_ROTATION)); + mParameters.set(CameraParameters::KEY_ROTATION, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_JPEG_QUALITY)) != NULL) + && (params.getInt(CameraParameters::KEY_JPEG_QUALITY) >=0)) + { + CAMHAL_LOGDB("Jpeg quality set %s", params.get(CameraParameters::KEY_JPEG_QUALITY)); + mParameters.set(CameraParameters::KEY_JPEG_QUALITY, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH)) != NULL) + && (params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH) >=0)) + { + CAMHAL_LOGDB("Thumbnail width set %s", params.get(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH)); + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT)) != NULL) + && (params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT) >=0)) + { + CAMHAL_LOGDB("Thumbnail width set %s", params.get(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT)); + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, valstr); + } + + if(( (valstr = params.get(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY)) != NULL ) + && (params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY) >=0)) + { + CAMHAL_LOGDB("Thumbnail quality set %s", params.get(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY)); + mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, valstr); + } + + if( (valstr = params.get(CameraParameters::KEY_GPS_LATITUDE)) != NULL ) + { + CAMHAL_LOGDB("GPS latitude set %s", params.get(CameraParameters::KEY_GPS_LATITUDE)); + mParameters.set(CameraParameters::KEY_GPS_LATITUDE, valstr); + }else{ + mParameters.remove(CameraParameters::KEY_GPS_LATITUDE); + } + + if( (valstr = params.get(CameraParameters::KEY_GPS_LONGITUDE)) != NULL ) + { + CAMHAL_LOGDB("GPS longitude set %s", params.get(CameraParameters::KEY_GPS_LONGITUDE)); + mParameters.set(CameraParameters::KEY_GPS_LONGITUDE, valstr); + }else{ + mParameters.remove(CameraParameters::KEY_GPS_LONGITUDE); + } + + if( (valstr = params.get(CameraParameters::KEY_GPS_ALTITUDE)) != NULL ) + { + CAMHAL_LOGDB("GPS altitude set %s", params.get(CameraParameters::KEY_GPS_ALTITUDE)); + mParameters.set(CameraParameters::KEY_GPS_ALTITUDE, valstr); + }else{ + mParameters.remove(CameraParameters::KEY_GPS_ALTITUDE); + } + + if( (valstr = params.get(CameraParameters::KEY_GPS_TIMESTAMP)) != NULL ) + { + CAMHAL_LOGDB("GPS timestamp set %s", params.get(CameraParameters::KEY_GPS_TIMESTAMP)); + mParameters.set(CameraParameters::KEY_GPS_TIMESTAMP, valstr); + }else{ + mParameters.remove(CameraParameters::KEY_GPS_TIMESTAMP); + } + + if( (valstr = params.get(TICameraParameters::KEY_GPS_DATESTAMP)) != NULL ) + { + CAMHAL_LOGDB("GPS datestamp set %s", params.get(TICameraParameters::KEY_GPS_DATESTAMP)); + mParameters.set(TICameraParameters::KEY_GPS_DATESTAMP, valstr); + }else{ + mParameters.remove(TICameraParameters::KEY_GPS_DATESTAMP); + } + + if( (valstr = params.get(CameraParameters::KEY_GPS_PROCESSING_METHOD)) != NULL ) + { + CAMHAL_LOGDB("GPS processing method set %s", params.get(CameraParameters::KEY_GPS_PROCESSING_METHOD)); + mParameters.set(CameraParameters::KEY_GPS_PROCESSING_METHOD, valstr); + }else{ + mParameters.remove(CameraParameters::KEY_GPS_PROCESSING_METHOD); + } + + if( (valstr = params.get(TICameraParameters::KEY_GPS_MAPDATUM )) != NULL ) + { + CAMHAL_LOGDB("GPS MAPDATUM set %s", params.get(TICameraParameters::KEY_GPS_MAPDATUM)); + mParameters.set(TICameraParameters::KEY_GPS_MAPDATUM, valstr); + }else{ + mParameters.remove(TICameraParameters::KEY_GPS_MAPDATUM); + } + + if( (valstr = params.get(TICameraParameters::KEY_GPS_VERSION)) != NULL ) + { + CAMHAL_LOGDB("GPS MAPDATUM set %s", params.get(TICameraParameters::KEY_GPS_VERSION)); + mParameters.set(TICameraParameters::KEY_GPS_VERSION, valstr); + }else{ + mParameters.remove(TICameraParameters::KEY_GPS_VERSION); + } + + if( (valstr = params.get(TICameraParameters::KEY_EXIF_MODEL)) != NULL ) + { + CAMHAL_LOGDB("EXIF Model set %s", params.get(TICameraParameters::KEY_EXIF_MODEL)); + mParameters.set(TICameraParameters::KEY_EXIF_MODEL, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_EXIF_MAKE)) != NULL ) + { + CAMHAL_LOGDB("EXIF Make set %s", params.get(TICameraParameters::KEY_EXIF_MAKE)); + mParameters.set(TICameraParameters::KEY_EXIF_MAKE, valstr); + } + + if( (valstr = params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE)) != NULL ) + { + CAMHAL_LOGDB("Exposure Bracketing set %s", params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE)); + mParameters.set(TICameraParameters::KEY_EXP_BRACKETING_RANGE, valstr); + } + else + { + mParameters.remove(TICameraParameters::KEY_EXP_BRACKETING_RANGE); + } + + if( ( (valstr = params.get(CameraParameters::KEY_ZOOM)) != NULL ) + && (params.getInt(CameraParameters::KEY_ZOOM) >= 0 ) + && (params.getInt(CameraParameters::KEY_ZOOM) <= mMaxZoomSupported ) ) + { + CAMHAL_LOGDB("Zoom set %s", params.get(CameraParameters::KEY_ZOOM)); + mParameters.set(CameraParameters::KEY_ZOOM, valstr); + } + else + { + //CTS requirement: Invalid zoom values should always return an error. + ret = -EINVAL; + } + + if( (valstr = params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK)) != NULL ) + { + CAMHAL_LOGDB("Auto Exposure Lock set %s", params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK)); + mParameters.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, valstr); + } + + if( (valstr = params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK)) != NULL ) + { + CAMHAL_LOGDB("Auto WhiteBalance Lock set %s", params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK)); + mParameters.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, valstr); + } + + CameraParameters adapterParams = mParameters; + + //If the app has not set the capture mode, set the capture resolution as preview resolution + //so that black bars are not displayed in preview. + //Later in takePicture we will configure the correct picture size + if(params.get(TICameraParameters::KEY_CAP_MODE) == NULL) + { + CAMHAL_LOGDA("Capture mode not set by app, setting picture res to preview res"); + mParameters.getPreviewSize(&w, &h); + adapterParams.setPictureSize(w,h); + } + + // Only send parameters to adapter if preview is already + // enabled. Initial setParameters to camera adapter, will + // be called in startPreview() + if ( NULL != mCameraAdapter && mPreviewEnabled ) { + ret |= mCameraAdapter->setParameters(adapterParams); + } + + if( NULL != params.get(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_POS) ) + { + int posBracketRange = params.getInt(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_POS); + if ( 0 < posBracketRange ) + { + mBracketRangePositive = posBracketRange; + } + } + CAMHAL_LOGDB("Positive bracketing range %d", mBracketRangePositive); + + + if( NULL != params.get(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_NEG) ) + { + int negBracketRange = params.getInt(TICameraParameters::KEY_TEMP_BRACKETING_RANGE_NEG); + if ( 0 < negBracketRange ) + { + mBracketRangeNegative = negBracketRange; + } + } + CAMHAL_LOGDB("Negative bracketing range %d", mBracketRangeNegative); + + if( ( (valstr = params.get(TICameraParameters::KEY_TEMP_BRACKETING)) != NULL) && + ( strcmp(valstr, TICameraParameters::BRACKET_ENABLE) == 0 )) + { + if ( !mBracketingEnabled ) + { + CAMHAL_LOGDA("Enabling bracketing"); + mBracketingEnabled = true; + + //Wait for AF events to enable bracketing + if ( NULL != mCameraAdapter ) + { + setEventProvider( CameraHalEvent::ALL_EVENTS, mCameraAdapter ); + } + } + else + { + CAMHAL_LOGDA("Bracketing already enabled"); + } + } + else if ( ( (valstr = params.get(TICameraParameters::KEY_TEMP_BRACKETING)) != NULL ) && + ( strcmp(valstr, TICameraParameters::BRACKET_DISABLE) == 0 )) + { + CAMHAL_LOGDA("Disabling bracketing"); + + mBracketingEnabled = false; + stopImageBracketing(); + + //Remove AF events subscription + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification( CameraHalEvent::ALL_EVENTS ); + delete mEventProvider; + mEventProvider = NULL; + } + + } + + if( ( (valstr = params.get(TICameraParameters::KEY_SHUTTER_ENABLE)) != NULL ) && + ( strcmp(valstr, TICameraParameters::SHUTTER_ENABLE) == 0 )) + { + CAMHAL_LOGDA("Enabling shutter sound"); + + mShutterEnabled = true; + mMsgEnabled |= CAMERA_MSG_SHUTTER; + mParameters.set(TICameraParameters::KEY_SHUTTER_ENABLE, valstr); + } + else if ( ( (valstr = params.get(TICameraParameters::KEY_SHUTTER_ENABLE)) != NULL ) && + ( strcmp(valstr, TICameraParameters::SHUTTER_DISABLE) == 0 )) + { + CAMHAL_LOGDA("Disabling shutter sound"); + + mShutterEnabled = false; + mMsgEnabled &= ~CAMERA_MSG_SHUTTER; + mParameters.set(TICameraParameters::KEY_SHUTTER_ENABLE, valstr); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; + + } + +status_t CameraHal::allocPreviewBufs(int width, int height, const char* previewFormat, + unsigned int buffercount, unsigned int &max_queueable) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if(mDisplayAdapter.get() == NULL) + { + // Memory allocation of preview buffers is now placed in gralloc + // CameraHal should not allocate preview buffers without DisplayAdapter + return NO_MEMORY; + } + + if(!mPreviewBufs) + { + ///@todo Pluralise the name of this method to allocateBuffers + mPreviewLength = 0; + mPreviewBufs = (int32_t *) mDisplayAdapter->allocateBuffer(width, height, + previewFormat, + mPreviewLength, + buffercount); + + if (NULL == mPreviewBufs ) { + CAMHAL_LOGEA("Couldn't allocate preview buffers"); + return NO_MEMORY; + } + + mPreviewOffsets = (uint32_t *) mDisplayAdapter->getOffsets(); + if ( NULL == mPreviewOffsets ) { + CAMHAL_LOGEA("Buffer mapping failed"); + return BAD_VALUE; + } + + mPreviewFd = mDisplayAdapter->getFd(); + if ( -1 == mPreviewFd ) { + CAMHAL_LOGEA("Invalid handle"); + return BAD_VALUE; + } + + mBufProvider = (BufferProvider*) mDisplayAdapter.get(); + + ret = mDisplayAdapter->maxQueueableBuffers(max_queueable); + if (ret != NO_ERROR) { + return ret; + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; + +} + +status_t CameraHal::freePreviewBufs() +{ + status_t ret = NO_ERROR; + LOG_FUNCTION_NAME; + + CAMHAL_LOGDB("mPreviewBufs = 0x%x", (unsigned int)mPreviewBufs); + if(mPreviewBufs) + { + ///@todo Pluralise the name of this method to freeBuffers + ret = mBufProvider->freeBuffer(mPreviewBufs); + mPreviewBufs = NULL; + LOG_FUNCTION_NAME_EXIT; + return ret; + } + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +status_t CameraHal::allocPreviewDataBufs(size_t size, size_t bufferCount) +{ + status_t ret = NO_ERROR; + int bytes; + + LOG_FUNCTION_NAME; + + bytes = size; + + if ( NO_ERROR == ret ) + { + if( NULL != mPreviewDataBufs ) + { + ret = freePreviewDataBufs(); + } + } + + if ( NO_ERROR == ret ) + { + mPreviewDataBufs = (int32_t *)mMemoryManager->allocateBuffer(0, 0, NULL, bytes, bufferCount); + + CAMHAL_LOGDB("Size of Preview data buffer = %d", bytes); + if( NULL == mPreviewDataBufs ) + { + CAMHAL_LOGEA("Couldn't allocate image buffers using memory manager"); + ret = -NO_MEMORY; + } + else + { + bytes = size; + } + } + + if ( NO_ERROR == ret ) + { + mPreviewDataFd = mMemoryManager->getFd(); + mPreviewDataLength = bytes; + mPreviewDataOffsets = mMemoryManager->getOffsets(); + } + else + { + mPreviewDataFd = -1; + mPreviewDataLength = 0; + mPreviewDataOffsets = NULL; + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t CameraHal::freePreviewDataBufs() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + + if( NULL != mPreviewDataBufs ) + { + + ///@todo Pluralise the name of this method to freeBuffers + ret = mMemoryManager->freeBuffer(mPreviewDataBufs); + mPreviewDataBufs = NULL; + + } + else + { + CAMHAL_LOGEA("Couldn't free PreviewDataBufs allocated by memory manager"); + ret = -EINVAL; + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::allocImageBufs(unsigned int width, unsigned int height, size_t size, const char* previewFormat, unsigned int bufferCount) +{ + status_t ret = NO_ERROR; + int bytes; + + LOG_FUNCTION_NAME; + + bytes = size; + + ///Always allocate the buffers for image capture using MemoryManager + if ( NO_ERROR == ret ) + { + if( ( NULL != mImageBufs ) ) + { + ret = freeImageBufs(); + } + } + + if ( NO_ERROR == ret ) + { + mImageBufs = (int32_t *)mMemoryManager->allocateBuffer(0, 0, previewFormat, bytes, bufferCount); + + CAMHAL_LOGDB("Size of Image cap buffer = %d", bytes); + if( NULL == mImageBufs ) + { + CAMHAL_LOGEA("Couldn't allocate image buffers using memory manager"); + ret = -NO_MEMORY; + } + else + { + bytes = size; + } + } + + if ( NO_ERROR == ret ) + { + mImageFd = mMemoryManager->getFd(); + mImageLength = bytes; + mImageOffsets = mMemoryManager->getOffsets(); + } + else + { + mImageFd = -1; + mImageLength = 0; + mImageOffsets = NULL; + } + + LOG_FUNCTION_NAME; + + return ret; +} + +void endImageCapture( void *userData) +{ + LOG_FUNCTION_NAME; + + if ( NULL != userData ) + { + CameraHal *c = reinterpret_cast<CameraHal *>(userData); + c->signalEndImageCapture(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void releaseImageBuffers(void *userData) +{ + LOG_FUNCTION_NAME; + + if ( NULL != userData ) + { + CameraHal *c = reinterpret_cast<CameraHal *>(userData); + c->freeImageBufs(); + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t CameraHal::signalEndImageCapture() +{ + status_t ret = NO_ERROR; + int w,h; + CameraParameters adapterParams = mParameters; + Mutex::Autolock lock(mLock); + + LOG_FUNCTION_NAME; + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE); + + //If the app has not set the capture mode, restore the capture resolution + //back to the preview resolution to get rid of the black bars issue + if (mParameters.get(TICameraParameters::KEY_CAP_MODE) == NULL) { + CAMHAL_LOGDA("Capture mode not set by app, setting picture res back to preview res"); + mParameters.getPreviewSize(&w, &h); + adapterParams.setPictureSize(w,h); + ret = mCameraAdapter->setParameters(adapterParams); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::freeImageBufs() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + + if( NULL != mImageBufs ) + { + + ///@todo Pluralise the name of this method to freeBuffers + ret = mMemoryManager->freeBuffer(mImageBufs); + mImageBufs = NULL; + + } + else + { + ret = -EINVAL; + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + + + +/** + @brief Start preview mode. + + @param none + @return NO_ERROR Camera switched to VF mode + @todo Update function header with the different errors that are possible + + */ +status_t CameraHal::startPreview() +{ + + status_t ret = NO_ERROR; + CameraAdapter::BuffersDescriptor desc; + CameraFrame frame; + const char *valstr = NULL; + unsigned int required_buffer_count; + unsigned int max_queueble_buffers; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartPreview, NULL); + +#endif + + LOG_FUNCTION_NAME; + + if( (mDisplayAdapter.get() != NULL) && ( !mPreviewEnabled ) && ( mDisplayPaused ) ) + { + CAMHAL_LOGDA("Preview is in paused state"); + + mDisplayPaused = false; + mPreviewEnabled = true; + if ( NO_ERROR == ret ) + { + ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Display adapter resume failed %x", ret); + } + } + //restart preview callbacks + if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + { + mAppCallbackNotifier->enableMsgType (CAMERA_MSG_PREVIEW_FRAME); + } + return ret; + + } + else if ( mPreviewEnabled ) + { + CAMHAL_LOGDA("Preview already running"); + + LOG_FUNCTION_NAME_EXIT; + + return ALREADY_EXISTS; + } + + ///If we don't have the preview callback enabled and display adapter, + if(!mSetPreviewWindowCalled || (mDisplayAdapter.get() == NULL)) + { + CAMHAL_LOGEA("Preview not started. Preview in progress flag set"); + mPreviewStartInProgress = true; + return NO_ERROR; + } + + if ( NULL != mCameraAdapter ) { + + CameraParameters adapterParams = mParameters; + + //If the app has not set the capture mode, set the capture resolution as preview resolution + //so that black bars are not displayed in preview. + //Later in takePicture we will configure the correct picture size + if(mParameters.get(TICameraParameters::KEY_CAP_MODE) == NULL) + { + int w,h; + CAMHAL_LOGDA("Capture mode not set by app, setting picture res to preview res"); + mParameters.getPreviewSize(&w, &h); + adapterParams.setPictureSize(w,h); + } + + ret = mCameraAdapter->setParameters(adapterParams); + } + + /// Ensure that buffers for preview are allocated before we start the camera + ///Get the updated size from Camera Adapter, to account for padding etc + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW, + ( int ) &frame); + if ( NO_ERROR != ret ) + { + return ret; + } + + ///Update the current preview width and height + mPreviewWidth = frame.mWidth; + mPreviewHeight = frame.mHeight; + + //Update the padded width and height - required for VNF and VSTAB + mParameters.set(TICameraParameters::KEY_PADDED_WIDTH, mPreviewWidth); + mParameters.set(TICameraParameters::KEY_PADDED_HEIGHT, mPreviewHeight); + + required_buffer_count = atoi(mCameraProperties->get(CameraProperties::REQUIRED_PREVIEW_BUFS)); + + ///Allocate the preview buffers + ret = allocPreviewBufs(frame.mWidth, frame.mHeight, mParameters.getPreviewFormat(), required_buffer_count, max_queueble_buffers); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEA("Couldn't allocate buffers for Preview"); + goto error; + } + + if ( mMeasurementEnabled ) + { + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA, + ( int ) &frame, + required_buffer_count); + if ( NO_ERROR != ret ) + { + return ret; + } + + ///Allocate the preview data buffers + ret = allocPreviewDataBufs(frame.mLength, required_buffer_count); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEA("Couldn't allocate preview data buffers"); + goto error; + } + + if ( NO_ERROR == ret ) + { + desc.mBuffers = mPreviewDataBufs; + desc.mOffsets = mPreviewDataOffsets; + desc.mFd = mPreviewDataFd; + desc.mLength = mPreviewDataLength; + desc.mCount = ( size_t ) required_buffer_count; + desc.mMaxQueueable = (size_t) required_buffer_count; + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA, + ( int ) &desc); + } + + } + + ///Pass the buffers to Camera Adapter + desc.mBuffers = mPreviewBufs; + desc.mOffsets = mPreviewOffsets; + desc.mFd = mPreviewFd; + desc.mLength = mPreviewLength; + desc.mCount = ( size_t ) required_buffer_count; + desc.mMaxQueueable = (size_t) max_queueble_buffers; + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW, + ( int ) &desc); + + mAppCallbackNotifier->startPreviewCallbacks(mParameters, mPreviewBufs, mPreviewOffsets, mPreviewFd, mPreviewLength, required_buffer_count); + + ///Start the callback notifier + ret = mAppCallbackNotifier->start(); + + if( ALREADY_EXISTS == ret ) + { + //Already running, do nothing + CAMHAL_LOGDA("AppCallbackNotifier already running"); + ret = NO_ERROR; + } + else if ( NO_ERROR == ret ) { + CAMHAL_LOGDA("Started AppCallbackNotifier.."); + mAppCallbackNotifier->setMeasurements(mMeasurementEnabled); + } + else + { + CAMHAL_LOGDA("Couldn't start AppCallbackNotifier"); + goto error; + } + + ///Enable the display adapter if present, actual overlay enable happens when we post the buffer + if(mDisplayAdapter.get() != NULL) + { + CAMHAL_LOGDA("Enabling display"); + bool isS3d = false; + DisplayAdapter::S3DParameters s3dParams; + int width, height; + mParameters.getPreviewSize(&width, &height); +#if 0 //TODO: s3d is not part of bringup...will reenable + if ( (valstr = mParameters.get(TICameraParameters::KEY_S3D_SUPPORTED)) != NULL) { + isS3d = (strcmp(valstr, "true") == 0); + } + if ( (valstr = mParameters.get(TICameraParameters::KEY_S3D2D_PREVIEW)) != NULL) { + if (strcmp(valstr, "off") == 0) + { + CAMHAL_LOGEA("STEREO 3D->2D PREVIEW MODE IS OFF"); + //TODO: obtain the frame packing configuration from camera or user settings + //once side by side configuration is supported + s3dParams.mode = OVERLAY_S3D_MODE_ON; + s3dParams.framePacking = OVERLAY_S3D_FORMAT_OVERUNDER; + s3dParams.order = OVERLAY_S3D_ORDER_LF; + s3dParams.subSampling = OVERLAY_S3D_SS_NONE; + } + else + { + CAMHAL_LOGEA("STEREO 3D->2D PREVIEW MODE IS ON"); + s3dParams.mode = OVERLAY_S3D_MODE_OFF; + s3dParams.framePacking = OVERLAY_S3D_FORMAT_OVERUNDER; + s3dParams.order = OVERLAY_S3D_ORDER_LF; + s3dParams.subSampling = OVERLAY_S3D_SS_NONE; + } + } +#endif //if 0 + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + ret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview, isS3d ? &s3dParams : NULL); + +#else + + ret = mDisplayAdapter->enableDisplay(width, height, NULL, isS3d ? &s3dParams : NULL); + +#endif + + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEA("Couldn't enable display"); + goto error; + } + + } + + ///Send START_PREVIEW command to adapter + CAMHAL_LOGDA("Starting CameraAdapter preview mode"); + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEA("Couldn't start preview w/ CameraAdapter"); + goto error; + } + CAMHAL_LOGDA("Started preview"); + + + mPreviewEnabled = true; + mPreviewStartInProgress = false; + return ret; + + error: + + CAMHAL_LOGEA("Performing cleanup after error"); + + //Do all the cleanup + freePreviewBufs(); + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW); + if(mDisplayAdapter.get() != NULL) + { + mDisplayAdapter->disableDisplay(); + } + mAppCallbackNotifier->stop(); + mPreviewStartInProgress = false; + mPreviewEnabled = false; + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Sets ANativeWindow object. + + Preview buffers provided to CameraHal via this object. DisplayAdapter will be interfacing with it + to render buffers to display. + + @param[in] window The ANativeWindow object created by Surface flinger + @return NO_ERROR If the ANativeWindow object passes validation criteria + @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios + + */ +status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window) +{ + status_t ret = NO_ERROR; + CameraAdapter::BuffersDescriptor desc; + + LOG_FUNCTION_NAME; + mSetPreviewWindowCalled = true; + + ///If the Camera service passes a null window, we destroy existing window and free the DisplayAdapter + if(!window) + { + if(mDisplayAdapter.get() != NULL) + { + ///NULL window passed, destroy the display adapter if present + CAMHAL_LOGEA("NULL window passed, destroying display adapter"); + mDisplayAdapter.clear(); + ///@remarks If there was a window previously existing, we usually expect another valid window to be passed by the client + ///@remarks so, we will wait until it passes a valid window to begin the preview again + mSetPreviewWindowCalled = false; + } + CAMHAL_LOGEA("NULL ANativeWindow passed to setPreviewWindow"); + return NO_ERROR; + }else if(mDisplayAdapter.get() == NULL) + { + // Need to create the display adapter since it has not been created + // Create display adapter + mDisplayAdapter = new ANativeWindowDisplayAdapter(); + ret = NO_ERROR; + if(!mDisplayAdapter.get() || ((ret=mDisplayAdapter->initialize())!=NO_ERROR)) + { + if(ret!=NO_ERROR) + { + mDisplayAdapter.clear(); + CAMHAL_LOGEA("DisplayAdapter initialize failed"); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + else + { + CAMHAL_LOGEA("Couldn't create DisplayAdapter"); + LOG_FUNCTION_NAME_EXIT; + return NO_MEMORY; + } + } + + // DisplayAdapter needs to know where to get the CameraFrames from inorder to display + // Since CameraAdapter is the one that provides the frames, set it as the frame provider for DisplayAdapter + mDisplayAdapter->setFrameProvider(mCameraAdapter); + + // Any dynamic errors that happen during the camera use case has to be propagated back to the application + // via CAMERA_MSG_ERROR. AppCallbackNotifier is the class that notifies such errors to the application + // Set it as the error handler for the DisplayAdapter + mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get()); + + // Update the display adapter with the new window that is passed from CameraService + ret = mDisplayAdapter->setPreviewWindow(window); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret); + } + + if(mPreviewStartInProgress) + { + CAMHAL_LOGDA("setPreviewWindow called when preview running"); + // Start the preview since the window is now available + ret = startPreview(); + } + }else + { + /* If mDisplayAdpater is already created. No need to do anything. + * We get a surface handle directly now, so we can reconfigure surface + * itself in DisplayAdapter if dimensions have changed + */ + } + LOG_FUNCTION_NAME_EXIT; + + return ret; + +} + + +/** + @brief Stop a previously started preview. + + @param none + @return none + + */ +void CameraHal::stopPreview() +{ + LOG_FUNCTION_NAME; + + if(!previewEnabled() && !mDisplayPaused) + { + LOG_FUNCTION_NAME_EXIT; + return; + } + + if(mDisplayPaused) + { + // Display is paused, which essentially means there is no preview active. + // Note: this is done so that when stopPreview is called by client after + // an image capture, we do not de-initialize the camera adapter and + // restart over again. + return; + } + + forceStopPreview(); + + CAMHAL_LOGDA("Resetting Capture-Mode to default"); + mParameters.set(TICameraParameters::KEY_CAP_MODE, ""); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Returns true if preview is enabled + + @param none + @return true If preview is running currently + false If preview has been stopped + + */ +bool CameraHal::previewEnabled() +{ + LOG_FUNCTION_NAME; + + return (mPreviewEnabled || mPreviewStartInProgress); +} + +/** + @brief 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 calling + releaseRecordingFrame(). + + @param none + @return NO_ERROR If recording could be started without any issues + @todo Update the header with possible error values in failure scenarios + + */ +status_t CameraHal::startRecording( ) +{ + int w, h; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartPreview, NULL); + +#endif + + if(!previewEnabled()) + { + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + ret = setVideoModeParameters(); + } + + if ( NO_ERROR == ret ) + { + ret = mAppCallbackNotifier->initSharedVideoBuffers(mPreviewBufs, mPreviewOffsets, mPreviewFd, mPreviewLength, atoi(mCameraProperties->get(CameraProperties::REQUIRED_PREVIEW_BUFS))); + } + + if ( NO_ERROR == ret ) + { + ret = mAppCallbackNotifier->startRecording(); + } + + if ( NO_ERROR == ret ) + { + ///Buffers for video capture (if different from preview) are expected to be allocated within CameraAdapter + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_VIDEO); + } + + if ( NO_ERROR == ret ) + { + mRecordingEnabled = true; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Set the camera parameters specific to Video Recording. + + This function checks for the camera parameters which have to be set for recording. + Video Recording needs CAPTURE_MODE to be VIDEO_MODE. This function sets it. + This function also enables Video Recording specific functions like VSTAB & VNF. + + @param none + @return NO_ERROR If recording parameters could be set without any issues + @todo Modify the policies for enabling VSTAB & VNF usecase based later. + + */ +status_t CameraHal::setVideoModeParameters() +{ + const char *valstr = NULL; + bool restartPreviewRequired = false; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + // Set CAPTURE_MODE to VIDEO_MODE, if not set already and Restart Preview + valstr = mParameters.get(TICameraParameters::KEY_CAP_MODE); + if ( (valstr == NULL) || + ( (valstr != NULL) && (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) != 0) ) ) + { + CAMHAL_LOGDA("Set CAPTURE_MODE to VIDEO_MODE"); + mParameters.set(TICameraParameters::KEY_CAP_MODE, (const char *) TICameraParameters::VIDEO_MODE); + restartPreviewRequired = true; + } + + // FIXME: This check is put since currently VSTAB and VNF are functional only for Primary Camera. + // Remove this check once VSTAB and VNF are functional for Secondary Camera as well. + if(mCameraIndex == 0) + { + // Check if CAPTURE_MODE is VIDEO_MODE, since VSTAB & VNF work only in VIDEO_MODE. + valstr = mParameters.get(TICameraParameters::KEY_CAP_MODE); + if (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) == 0) + { + // Enable VSTAB, if not enabled already + valstr = mParameters.get(TICameraParameters::KEY_VSTAB); + if ( (valstr == NULL) || + ( (valstr != NULL) && (strcmp(valstr, "1") != 0) ) ) + { + CAMHAL_LOGDA("Enable VSTAB"); + mParameters.set(TICameraParameters::KEY_VSTAB, "1"); + restartPreviewRequired = true; + } + + // Enable VNF, if not enabled already + valstr = mParameters.get(TICameraParameters::KEY_VNF); + if ( (valstr == NULL) || + ( (valstr != NULL) && (strcmp(valstr, "1") != 0) ) ) + { + CAMHAL_LOGDA("Enable VNF"); + mParameters.set(TICameraParameters::KEY_VNF, "1"); + restartPreviewRequired = true; + } + + // For VSTAB alone for 1080p resolution, padded width goes > 2048, which cannot be rendered by GPU. + // In such case, there is support in Ducati for combination of VSTAB & VNF requiring padded width < 2048. + // So we are forcefully enabling VNF, if VSTAB is enabled for 1080p resolution. + valstr = mParameters.get(TICameraParameters::KEY_VSTAB); + if ((valstr != NULL) && (strcmp(valstr, "1") == 0) && (mPreviewWidth == 1920)) + { + CAMHAL_LOGDA("Force Enable VNF for 1080p"); + mParameters.set(TICameraParameters::KEY_VNF, "1"); + restartPreviewRequired = true; + } + } + } + + if (restartPreviewRequired) + { + CAMHAL_LOGDA("Restarting preview"); + stopPreview(); + // Setting CAPTURE_MODE to VIDEO_MODE again, since it is reset in stopPreview() + mParameters.set(TICameraParameters::KEY_CAP_MODE, (const char *) TICameraParameters::VIDEO_MODE); + mCameraAdapter->setParameters(mParameters); + ret = startPreview(); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Stop a previously started recording. + + @param none + @return none + + */ +void CameraHal::stopRecording() +{ + LOG_FUNCTION_NAME; + + if (!mRecordingEnabled ) + { + return; + } + + mAppCallbackNotifier->stopRecording(); + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_VIDEO); + + mRecordingEnabled = false; + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Returns true if recording is enabled. + + @param none + @return true If recording is currently running + false If recording has been stopped + + */ +int CameraHal::recordingEnabled() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return mRecordingEnabled; +} + +/** + @brief Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + + @param[in] mem MemoryBase pointer to the frame being released. Must be one of the buffers + previously given by CameraHal + @return none + + */ +void CameraHal::releaseRecordingFrame(const void* mem) +{ + LOG_FUNCTION_NAME; + + //CAMHAL_LOGDB(" 0x%x", mem->pointer()); + + if ( ( mRecordingEnabled ) && mem != NULL) + { + mAppCallbackNotifier->releaseRecordingFrame(mem); + } + + LOG_FUNCTION_NAME_EXIT; + + return; +} + +/** + @brief Start auto focus + + This call asynchronous. + 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. + + @param none + @return NO_ERROR + @todo Define the error codes if the focus is not locked + + */ +status_t CameraHal::autoFocus() +{ + status_t ret = NO_ERROR; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartFocus, NULL); + +#endif + + + LOG_FUNCTION_NAME; + + if ( NULL != mCameraAdapter ) + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //pass the autoFocus timestamp along with the command to camera adapter + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_PERFORM_AUTOFOCUS, ( int ) &mStartFocus); + +#else + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_PERFORM_AUTOFOCUS); + +#endif + + } + else + { + ret = -1; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief 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. + + + @param none + @return NO_ERROR If the cancel succeeded + @todo Define error codes if cancel didnt succeed + + */ +status_t CameraHal::cancelAutoFocus() +{ + LOG_FUNCTION_NAME; + if( NULL != mCameraAdapter ) + { + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_CANCEL_AUTOFOCUS); + } + LOG_FUNCTION_NAME_EXIT; + return NO_ERROR; +} + +void CameraHal::setEventProvider(int32_t eventMask, MessageNotifier * eventNotifier) +{ + + LOG_FUNCTION_NAME; + + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification(CameraHalEvent::ALL_EVENTS); + delete mEventProvider; + mEventProvider = NULL; + } + + mEventProvider = new EventProvider(eventNotifier, this, eventCallbackRelay); + if ( NULL == mEventProvider ) + { + CAMHAL_LOGEA("Error in creating EventProvider"); + } + else + { + mEventProvider->enableEventNotification(eventMask); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void CameraHal::eventCallbackRelay(CameraHalEvent* event) +{ + LOG_FUNCTION_NAME; + + CameraHal *appcbn = ( CameraHal * ) (event->mCookie); + appcbn->eventCallback(event ); + + LOG_FUNCTION_NAME_EXIT; +} + +void CameraHal::eventCallback(CameraHalEvent* event) +{ + LOG_FUNCTION_NAME; + + if ( NULL != event ) + { + switch( event->mEventType ) + { + case CameraHalEvent::EVENT_FOCUS_LOCKED: + case CameraHalEvent::EVENT_FOCUS_ERROR: + { + if ( mBracketingEnabled ) + { + startImageBracketing(); + } + break; + } + default: + { + break; + } + }; + } + + LOG_FUNCTION_NAME_EXIT; +} + +status_t CameraHal::startImageBracketing() +{ + status_t ret = NO_ERROR; + CameraFrame frame; + CameraAdapter::BuffersDescriptor desc; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartCapture, NULL); + +#endif + + LOG_FUNCTION_NAME; + + if(!previewEnabled() && !mDisplayPaused) + { + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if ( !mBracketingEnabled ) + { + return ret; + } + + if ( NO_ERROR == ret ) + { + mBracketingRunning = true; + } + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE, + ( int ) &frame, + ( mBracketRangeNegative + 1 )); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE returned error 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + if ( NULL != mAppCallbackNotifier.get() ) + { + mAppCallbackNotifier->setBurst(true); + } + } + + if ( NO_ERROR == ret ) + { + mParameters.getPictureSize(( int * ) &frame.mWidth, + ( int * ) &frame.mHeight); + + ret = allocImageBufs(frame.mWidth, + frame.mHeight, + frame.mLength, + mParameters.getPictureFormat(), + ( mBracketRangeNegative + 1 )); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("allocImageBufs returned error 0x%x", ret); + } + } + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + + desc.mBuffers = mImageBufs; + desc.mOffsets = mImageOffsets; + desc.mFd = mImageFd; + desc.mLength = mImageLength; + desc.mCount = ( size_t ) ( mBracketRangeNegative + 1 ); + desc.mMaxQueueable = ( size_t ) ( mBracketRangeNegative + 1 ); + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE, + ( int ) &desc); + + if ( NO_ERROR == ret ) + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //pass capture timestamp along with the camera adapter command + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_BRACKET_CAPTURE, ( mBracketRangePositive + 1 ), (int) &mStartCapture); + +#else + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_BRACKET_CAPTURE, ( mBracketRangePositive + 1 )); + +#endif + + } + } + + return ret; +} + +status_t CameraHal::stopImageBracketing() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( !mBracketingRunning ) + { + return ret; + } + + if ( NO_ERROR == ret ) + { + mBracketingRunning = false; + } + + if(!previewEnabled() && !mDisplayPaused) + { + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Take a picture. + + @param none + @return NO_ERROR If able to switch to image capture + @todo Define error codes if unable to switch to image capture + + */ +status_t CameraHal::takePicture( ) +{ + status_t ret = NO_ERROR; + CameraFrame frame; + CameraAdapter::BuffersDescriptor desc; + int burst; + unsigned int bufferCount = 1; + + Mutex::Autolock lock(mLock); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + gettimeofday(&mStartCapture, NULL); + +#endif + + LOG_FUNCTION_NAME; + + if(!previewEnabled() && !mDisplayPaused) + { + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + //If capture has already started, then queue this call for later execution + if ( mCameraAdapter->getState() == CameraAdapter::CAPTURE_STATE && + mCameraAdapter->getNextState() != CameraAdapter::PREVIEW_STATE) { + return NO_INIT; + } + + if ( !mBracketingRunning ) + { + + if ( NO_ERROR == ret ) + { + burst = mParameters.getInt(TICameraParameters::KEY_BURST); + } + + //Allocate all buffers only in burst capture case + if ( burst > 1 ) + { + bufferCount = CameraHal::NO_BUFFERS_IMAGE_CAPTURE; + if ( NULL != mAppCallbackNotifier.get() ) + { + mAppCallbackNotifier->setBurst(true); + } + } + else + { + if ( NULL != mAppCallbackNotifier.get() ) + { + mAppCallbackNotifier->setBurst(false); + } + } + + //Pause Preview during capture + if ( (NO_ERROR == ret) && ( NULL != mDisplayAdapter.get() ) && ( burst < 1 ) ) + { + mDisplayPaused = true; + mPreviewEnabled = false; + ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + mDisplayAdapter->setSnapshotTimeRef(&mStartCapture); + +#endif + // since preview is paused we should stop sending preview frames too + if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + { + mAppCallbackNotifier->disableMsgType (CAMERA_MSG_PREVIEW_FRAME); + } + } + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + + //Configure the correct picture resolution now if the capture mode is not set + if(mParameters.get(TICameraParameters::KEY_CAP_MODE) == NULL) + { + ret = mCameraAdapter->setParameters(mParameters); + } + + if ( NO_ERROR == ret ) + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE, + ( int ) &frame, + bufferCount); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE returned error 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + mParameters.getPictureSize(( int * ) &frame.mWidth, + ( int * ) &frame.mHeight); + + ret = allocImageBufs(frame.mWidth, + frame.mHeight, + frame.mLength, + mParameters.getPictureFormat(), + bufferCount); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("allocImageBufs returned error 0x%x", ret); + } + } + + if ( (NO_ERROR == ret) && ( NULL != mCameraAdapter ) ) + { + desc.mBuffers = mImageBufs; + desc.mOffsets = mImageOffsets; + desc.mFd = mImageFd; + desc.mLength = mImageLength; + desc.mCount = ( size_t ) bufferCount; + desc.mMaxQueueable = ( size_t ) bufferCount; + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE, + ( int ) &desc); + } + } + else + { + mBracketingRunning = false; + } + + if ( ( NO_ERROR == ret ) && ( NULL != mCameraAdapter ) ) + { + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //pass capture timestamp along with the camera adapter command + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE, (int) &mStartCapture); + +#else + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE); + +#endif + + } + + return ret; +} + +/** + @brief Cancel a picture that was started with takePicture. + + Calling this method when no picture is being taken is a no-op. + + @param none + @return NO_ERROR If cancel succeeded. Cancel can succeed if image callback is not sent + @todo Define error codes + + */ +status_t CameraHal::cancelPicture( ) +{ + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mLock); + + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE); + + return NO_ERROR; +} + +/** + @brief Return the camera parameters. + + @param none + @return Currently configured camera parameters + + */ +char* CameraHal::getParameters() +{ + CameraParameters params; + String8 params_str8; + char* params_string; + + LOG_FUNCTION_NAME; + + params = mParameters; + if( NULL != mCameraAdapter ) + { + mCameraAdapter->getParameters(params); + } + + params_str8 = params.flatten(); + // camera service frees this string... + params_string = (char*) malloc(sizeof(char) * (params_str8.length()+1)); + strcpy(params_string, params_str8.string()); + + LOG_FUNCTION_NAME_EXIT; + + ///Return the current set of parameters + + return params_string; +} + +void CameraHal::putParameters(char *parms) +{ + free(parms); +} + +/** + @brief Send command to camera driver. + + @param none + @return NO_ERROR If the command succeeds + @todo Define the error codes that this function can return + + */ +status_t CameraHal::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + + if ( ( NO_ERROR == ret ) && ( NULL == mCameraAdapter ) ) + { + CAMHAL_LOGEA("No CameraAdapter instance"); + ret = -EINVAL; + } + + if ( ( NO_ERROR == ret ) && ( !previewEnabled() )) + { + CAMHAL_LOGEA("Preview is not running"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + switch(cmd) + { + case CAMERA_CMD_START_SMOOTH_ZOOM: + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_SMOOTH_ZOOM, arg1); + + break; + case CAMERA_CMD_STOP_SMOOTH_ZOOM: + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM); + + case CAMERA_CMD_START_FACE_DETECTION: + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_FD); + + break; + + case CAMERA_CMD_STOP_FACE_DETECTION: + + ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_FD); + + break; + + default: + break; + }; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/** + @brief Release the hardware resources owned by this object. + + Note that this is *not* done in the destructor. + + @param none + @return none + + */ +void CameraHal::release() +{ + LOG_FUNCTION_NAME; + ///@todo Investigate on how release is used by CameraService. Vaguely remember that this is called + ///just before CameraHal object destruction + deinitialize(); + LOG_FUNCTION_NAME_EXIT; +} + + +/** + @brief Dump state of the camera hardware + + @param[in] fd File descriptor + @param[in] args Arguments + @return NO_ERROR Dump succeeded + @todo Error codes for dump fail + + */ +status_t CameraHal::dump(int fd) const +{ + LOG_FUNCTION_NAME; + ///Implement this method when the h/w dump function is supported on Ducati side + return NO_ERROR; +} + +/*-------------Camera Hal Interface Method definitions ENDS here--------------------*/ + + + + +/*-------------Camera Hal Internal Method definitions STARTS here--------------------*/ + +/** + @brief Constructor of CameraHal + + Member variables are initialized here. No allocations should be done here as we + don't use c++ exceptions in the code. + + */ +CameraHal::CameraHal(int cameraId) +{ + LOG_FUNCTION_NAME; + + ///Initialize all the member variables to their defaults + mPreviewEnabled = false; + mPreviewBufs = NULL; + mImageBufs = NULL; + mBufProvider = NULL; + mPreviewStartInProgress = false; + mVideoBufs = NULL; + mVideoBufProvider = NULL; + mRecordingEnabled = false; + mDisplayPaused = false; + mSetPreviewWindowCalled = false; + mMsgEnabled = 0; + mAppCallbackNotifier = NULL; + mMemoryManager = NULL; + mCameraAdapter = NULL; + mBracketingEnabled = false; + mBracketingRunning = false; + mEventProvider = NULL; + mBracketRangePositive = 1; + mBracketRangeNegative = 1; + mMaxZoomSupported = 0; + mShutterEnabled = true; + mMeasurementEnabled = false; + mPreviewDataBufs = NULL; + mCameraProperties = NULL; + mCurrentTime = 0; + mFalsePreview = 0; + mImageOffsets = NULL; + mImageLength = 0; + mImageFd = 0; + mVideoOffsets = NULL; + mVideoFd = 0; + mVideoLength = 0; + mPreviewDataOffsets = NULL; + mPreviewDataFd = 0; + mPreviewDataLength = 0; + mPreviewFd = 0; + mPreviewWidth = 0; + mPreviewHeight = 0; + mPreviewLength = 0; + mPreviewOffsets = NULL; + mPreviewRunning = 0; + mPreviewStateOld = 0; + mRecordingEnabled = 0; + mRecordEnabled = 0; + mSensorListener = NULL; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Initialize the CameraHAL constructor timestamp, which is used in the + // PPM() method as time reference if the user does not supply one. + gettimeofday(&ppm_start, NULL); + +#endif + + mCameraIndex = cameraId; + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Destructor of CameraHal + + This function simply calls deinitialize() to free up memory allocate during construct + phase + */ +CameraHal::~CameraHal() +{ + LOG_FUNCTION_NAME; + + ///Call de-initialize here once more - it is the last chance for us to relinquish all the h/w and s/w resources + deinitialize(); + + if ( NULL != mEventProvider ) + { + mEventProvider->disableEventNotification(CameraHalEvent::ALL_EVENTS); + delete mEventProvider; + mEventProvider = NULL; + } + + /// Free the callback notifier + mAppCallbackNotifier.clear(); + + /// Free the memory manager + mMemoryManager.clear(); + + /// Free the display adapter + mDisplayAdapter.clear(); + + if ( NULL != mCameraAdapter ) { + int strongCount = mCameraAdapter->getStrongCount(); + + mCameraAdapter->decStrong(mCameraAdapter); + + mCameraAdapter = NULL; + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Initialize the Camera HAL + + Creates CameraAdapter, AppCallbackNotifier, DisplayAdapter and MemoryManager + + @param None + @return NO_ERROR - On success + NO_MEMORY - On failure to allocate memory for any of the objects + @remarks Camera Hal internal function + + */ + +status_t CameraHal::initialize(CameraProperties::Properties* properties) +{ + LOG_FUNCTION_NAME; + + int sensor_index = 0; + + mLastPreviewFramerate = 0; + + ///Initialize the event mask used for registering an event provider for AppCallbackNotifier + ///Currently, registering all events as to be coming from CameraAdapter + int32_t eventMask = CameraHalEvent::ALL_EVENTS; + + // Get my camera properties + mCameraProperties = properties; + + if(!mCameraProperties) + { + goto fail_loop; + } + + // Dump the properties of this Camera + // will only print if DEBUG macro is defined + mCameraProperties->dump(); + + if (strcmp(CameraProperties::DEFAULT_VALUE, mCameraProperties->get(CameraProperties::CAMERA_SENSOR_INDEX)) != 0 ) + { + sensor_index = atoi(mCameraProperties->get(CameraProperties::CAMERA_SENSOR_INDEX)); + } + + CAMHAL_LOGDB("Sensor index %d", sensor_index); + + mCameraAdapter = CameraAdapter_Factory(); + if ( ( NULL == mCameraAdapter ) || (mCameraAdapter->initialize(properties, sensor_index)!=NO_ERROR)) + { + CAMHAL_LOGEA("Unable to create or initialize CameraAdapter"); + mCameraAdapter = NULL; + goto fail_loop; + } + + mCameraAdapter->incStrong(mCameraAdapter); + mCameraAdapter->registerImageReleaseCallback(releaseImageBuffers, (void *) this); + mCameraAdapter->registerEndCaptureCallback(endImageCapture, (void *)this); + + if(!mAppCallbackNotifier.get()) + { + /// Create the callback notifier + mAppCallbackNotifier = new AppCallbackNotifier(); + if( ( NULL == mAppCallbackNotifier.get() ) || ( mAppCallbackNotifier->initialize() != NO_ERROR)) + { + CAMHAL_LOGEA("Unable to create or initialize AppCallbackNotifier"); + goto fail_loop; + } + } + + if(!mMemoryManager.get()) + { + /// Create Memory Manager + mMemoryManager = new MemoryManager(); + if( ( NULL == mMemoryManager.get() ) || ( mMemoryManager->initialize() != NO_ERROR)) + { + CAMHAL_LOGEA("Unable to create or initialize MemoryManager"); + goto fail_loop; + } + } + + ///Setup the class dependencies... + + ///AppCallbackNotifier has to know where to get the Camera frames and the events like auto focus lock etc from. + ///CameraAdapter is the one which provides those events + ///Set it as the frame and event providers for AppCallbackNotifier + ///@remarks setEventProvider API takes in a bit mask of events for registering a provider for the different events + /// That way, if events can come from DisplayAdapter in future, we will be able to add it as provider + /// for any event + mAppCallbackNotifier->setEventProvider(eventMask, mCameraAdapter); + mAppCallbackNotifier->setFrameProvider(mCameraAdapter); + + ///Any dynamic errors that happen during the camera use case has to be propagated back to the application + ///via CAMERA_MSG_ERROR. AppCallbackNotifier is the class that notifies such errors to the application + ///Set it as the error handler for CameraAdapter + mCameraAdapter->setErrorHandler(mAppCallbackNotifier.get()); + + ///Start the callback notifier + if(mAppCallbackNotifier->start() != NO_ERROR) + { + CAMHAL_LOGEA("Couldn't start AppCallbackNotifier"); + goto fail_loop; + } + + CAMHAL_LOGDA("Started AppCallbackNotifier.."); + mAppCallbackNotifier->setMeasurements(mMeasurementEnabled); + + ///Initialize default parameters + initDefaultParameters(); + + + if ( setParameters(mParameters) != NO_ERROR ) + { + CAMHAL_LOGEA("Failed to set default parameters?!"); + } + + // register for sensor events + mSensorListener = new SensorListener(); + if (mSensorListener.get()) { + if (mSensorListener->initialize() == NO_ERROR) { + mSensorListener->setCallbacks(orientation_cb, this); + mSensorListener->enableSensor(SensorListener::SENSOR_ORIENTATION); + } else { + CAMHAL_LOGEA("Error initializing SensorListener. not fatal, continuing"); + mSensorListener.clear(); + mSensorListener = NULL; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; + + fail_loop: + + ///Free up the resources because we failed somewhere up + deinitialize(); + LOG_FUNCTION_NAME_EXIT; + + return NO_MEMORY; + +} + +bool CameraHal::isResolutionValid(unsigned int width, unsigned int height, const char *supportedResolutions) +{ + bool ret = true; + status_t status = NO_ERROR; + char tmpBuffer[PARAM_BUFFER + 1]; + char *pos = NULL; + + LOG_FUNCTION_NAME; + + if ( NULL == supportedResolutions ) + { + CAMHAL_LOGEA("Invalid supported resolutions string"); + ret = false; + goto exit; + } + + status = snprintf(tmpBuffer, PARAM_BUFFER, "%dx%d", width, height); + if ( 0 > status ) + { + CAMHAL_LOGEA("Error encountered while generating validation string"); + ret = false; + goto exit; + } + + pos = strstr(supportedResolutions, tmpBuffer); + if ( NULL == pos ) + { + ret = false; + } + else + { + ret = true; + } + +exit: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool CameraHal::isParameterValid(const char *param, const char *supportedParams) +{ + bool ret = true; + char *pos = NULL; + + LOG_FUNCTION_NAME; + + if ( NULL == supportedParams ) + { + CAMHAL_LOGEA("Invalid supported parameters string"); + ret = false; + goto exit; + } + + if ( NULL == param ) + { + CAMHAL_LOGEA("Invalid parameter string"); + ret = false; + goto exit; + } + + pos = strstr(supportedParams, param); + if ( NULL == pos ) + { + ret = false; + } + else + { + ret = true; + } + +exit: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool CameraHal::isParameterValid(int param, const char *supportedParams) +{ + bool ret = true; + char *pos = NULL; + status_t status; + char tmpBuffer[PARAM_BUFFER + 1]; + + LOG_FUNCTION_NAME; + + if ( NULL == supportedParams ) + { + CAMHAL_LOGEA("Invalid supported parameters string"); + ret = false; + goto exit; + } + + status = snprintf(tmpBuffer, PARAM_BUFFER, "%d", param); + if ( 0 > status ) + { + CAMHAL_LOGEA("Error encountered while generating validation string"); + ret = false; + goto exit; + } + + pos = strstr(supportedParams, tmpBuffer); + if ( NULL == pos ) + { + ret = false; + } + else + { + ret = true; + } + +exit: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t CameraHal::parseResolution(const char *resStr, int &width, int &height) +{ + status_t ret = NO_ERROR; + char *ctx, *pWidth, *pHeight; + const char *sep = "x"; + char *tmp = NULL; + + LOG_FUNCTION_NAME; + + if ( NULL == resStr ) + { + return -EINVAL; + } + + //This fixes "Invalid input resolution" + char *resStr_copy = (char *)malloc(strlen(resStr) + 1); + if ( NULL!=resStr_copy ) { + if ( NO_ERROR == ret ) + { + strcpy(resStr_copy, resStr); + pWidth = strtok_r( (char *) resStr_copy, sep, &ctx); + + if ( NULL != pWidth ) + { + width = atoi(pWidth); + } + else + { + CAMHAL_LOGEB("Invalid input resolution %s", resStr); + ret = -EINVAL; + } + } + + if ( NO_ERROR == ret ) + { + pHeight = strtok_r(NULL, sep, &ctx); + + if ( NULL != pHeight ) + { + height = atoi(pHeight); + } + else + { + CAMHAL_LOGEB("Invalid input resolution %s", resStr); + ret = -EINVAL; + } + } + + free(resStr_copy); + resStr_copy = NULL; + } + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void CameraHal::insertSupportedParams() +{ + char tmpBuffer[PARAM_BUFFER + 1]; + + LOG_FUNCTION_NAME; + + CameraParameters &p = mParameters; + + ///Set the name of the camera + p.set(TICameraParameters::KEY_CAMERA_NAME, mCameraProperties->get(CameraProperties::CAMERA_NAME)); + + mMaxZoomSupported = atoi(mCameraProperties->get(CameraProperties::SUPPORTED_ZOOM_STAGES)); + + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_SIZES)); + p.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS, mCameraProperties->get(CameraProperties::SUPPORTED_PICTURE_FORMATS)); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_SIZES)); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FORMATS)); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, mCameraProperties->get(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES)); + p.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES, mCameraProperties->get(CameraProperties::SUPPORTED_THUMBNAIL_SIZES)); + p.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, mCameraProperties->get(CameraProperties::SUPPORTED_WHITE_BALANCE)); + p.set(CameraParameters::KEY_SUPPORTED_EFFECTS, mCameraProperties->get(CameraProperties::SUPPORTED_EFFECTS)); + p.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_SCENE_MODES)); + p.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_FLASH_MODES)); + p.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_FOCUS_MODES)); + p.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING, mCameraProperties->get(CameraProperties::SUPPORTED_ANTIBANDING)); + p.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, mCameraProperties->get(CameraProperties::SUPPORTED_EV_MAX)); + p.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, mCameraProperties->get(CameraProperties::SUPPORTED_EV_MIN)); + p.set(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, mCameraProperties->get(CameraProperties::SUPPORTED_EV_STEP)); + p.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES, mCameraProperties->get(CameraProperties::SUPPORTED_SCENE_MODES)); + p.set(TICameraParameters::KEY_SUPPORTED_EXPOSURE, mCameraProperties->get(CameraProperties::SUPPORTED_EXPOSURE_MODES)); + p.set(TICameraParameters::KEY_SUPPORTED_ISO_VALUES, mCameraProperties->get(CameraProperties::SUPPORTED_ISO_VALUES)); + p.set(CameraParameters::KEY_ZOOM_RATIOS, mCameraProperties->get(CameraProperties::SUPPORTED_ZOOM_RATIOS)); + p.set(CameraParameters::KEY_MAX_ZOOM, mCameraProperties->get(CameraProperties::SUPPORTED_ZOOM_STAGES)); + p.set(CameraParameters::KEY_ZOOM_SUPPORTED, mCameraProperties->get(CameraProperties::ZOOM_SUPPORTED)); + p.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED, mCameraProperties->get(CameraProperties::SMOOTH_ZOOM_SUPPORTED)); + p.set(TICameraParameters::KEY_SUPPORTED_IPP, mCameraProperties->get(CameraProperties::SUPPORTED_IPP_MODES)); + p.set(TICameraParameters::KEY_S3D_SUPPORTED,mCameraProperties->get(CameraProperties::S3D_SUPPORTED)); + p.set(TICameraParameters::KEY_S3D2D_PREVIEW_MODE,mCameraProperties->get(CameraProperties::S3D2D_PREVIEW_MODES)); + p.set(TICameraParameters::KEY_AUTOCONVERGENCE_MODE, mCameraProperties->get(CameraProperties::AUTOCONVERGENCE_MODE)); + p.set(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES, mCameraProperties->get(CameraProperties::MANUALCONVERGENCE_VALUES)); + p.set(TICameraParameters::KEY_VSTAB,mCameraProperties->get(CameraProperties::VSTAB)); + p.set(TICameraParameters::KEY_VSTAB_VALUES,mCameraProperties->get(CameraProperties::VSTAB_VALUES)); + p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, mCameraProperties->get(CameraProperties::FRAMERATE_RANGE_SUPPORTED)); + p.set(TICameraParameters::KEY_SENSOR_ORIENTATION, mCameraProperties->get(CameraProperties::SENSOR_ORIENTATION)); + p.set(TICameraParameters::KEY_SENSOR_ORIENTATION_VALUES, mCameraProperties->get(CameraProperties::SENSOR_ORIENTATION_VALUES)); + p.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED, mCameraProperties->get(CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED)); + p.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED, mCameraProperties->get(CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED)); + + LOG_FUNCTION_NAME_EXIT; + +} + +void CameraHal::initDefaultParameters() +{ + //Purpose of this function is to initialize the default current and supported parameters for the currently + //selected camera. + + CameraParameters &p = mParameters; + int currentRevision, adapterRevision; + status_t ret = NO_ERROR; + int width, height; + + LOG_FUNCTION_NAME; + + ret = parseResolution(mCameraProperties->get(CameraProperties::PREVIEW_SIZE), width, height); + + if ( NO_ERROR == ret ) + { + p.setPreviewSize(width, height); + } + else + { + p.setPreviewSize(MIN_WIDTH, MIN_HEIGHT); + } + + ret = parseResolution(mCameraProperties->get(CameraProperties::PICTURE_SIZE), width, height); + + if ( NO_ERROR == ret ) + { + p.setPictureSize(width, height); + } + else + { + p.setPictureSize(PICTURE_WIDTH, PICTURE_HEIGHT); + } + + ret = parseResolution(mCameraProperties->get(CameraProperties::JPEG_THUMBNAIL_SIZE), width, height); + + if ( NO_ERROR == ret ) + { + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, width); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, height); + } + else + { + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, MIN_WIDTH); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, MIN_HEIGHT); + } + + insertSupportedParams(); + + //Insert default values + p.setPreviewFrameRate(atoi(mCameraProperties->get(CameraProperties::PREVIEW_FRAME_RATE))); + p.setPreviewFormat(mCameraProperties->get(CameraProperties::PREVIEW_FORMAT)); + p.setPictureFormat(mCameraProperties->get(CameraProperties::PICTURE_FORMAT)); + p.set(CameraParameters::KEY_JPEG_QUALITY, mCameraProperties->get(CameraProperties::JPEG_QUALITY)); + p.set(CameraParameters::KEY_WHITE_BALANCE, mCameraProperties->get(CameraProperties::WHITEBALANCE)); + p.set(CameraParameters::KEY_EFFECT, mCameraProperties->get(CameraProperties::EFFECT)); + p.set(CameraParameters::KEY_ANTIBANDING, mCameraProperties->get(CameraProperties::ANTIBANDING)); + p.set(CameraParameters::KEY_FLASH_MODE, mCameraProperties->get(CameraProperties::FLASH_MODE)); + p.set(CameraParameters::KEY_FOCUS_MODE, mCameraProperties->get(CameraProperties::FOCUS_MODE)); + p.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, mCameraProperties->get(CameraProperties::EV_COMPENSATION)); + p.set(CameraParameters::KEY_SCENE_MODE, mCameraProperties->get(CameraProperties::SCENE_MODE)); + p.set(CameraParameters::KEY_FLASH_MODE, mCameraProperties->get(CameraProperties::FLASH_MODE)); + p.set(CameraParameters::KEY_ZOOM, mCameraProperties->get(CameraProperties::ZOOM)); + p.set(TICameraParameters::KEY_CONTRAST, mCameraProperties->get(CameraProperties::CONTRAST)); + p.set(TICameraParameters::KEY_SATURATION, mCameraProperties->get(CameraProperties::SATURATION)); + p.set(TICameraParameters::KEY_BRIGHTNESS, mCameraProperties->get(CameraProperties::BRIGHTNESS)); + p.set(TICameraParameters::KEY_SHARPNESS, mCameraProperties->get(CameraProperties::SHARPNESS)); + p.set(TICameraParameters::KEY_EXPOSURE_MODE, mCameraProperties->get(CameraProperties::EXPOSURE_MODE)); + p.set(TICameraParameters::KEY_ISO, mCameraProperties->get(CameraProperties::ISO_MODE)); + p.set(TICameraParameters::KEY_IPP, mCameraProperties->get(CameraProperties::IPP)); + p.set(TICameraParameters::KEY_S3D2D_PREVIEW, mCameraProperties->get(CameraProperties::S3D2D_PREVIEW)); + p.set(TICameraParameters::KEY_AUTOCONVERGENCE, mCameraProperties->get(CameraProperties::AUTOCONVERGENCE)); + p.set(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES, mCameraProperties->get(CameraProperties::MANUALCONVERGENCE_VALUES)); + p.set(TICameraParameters::KEY_VSTAB,mCameraProperties->get(CameraProperties::VSTAB)); + p.set(TICameraParameters::KEY_VSTAB_VALUES,mCameraProperties->get(CameraProperties::VSTAB_VALUES)); + p.set(CameraParameters::KEY_FOCAL_LENGTH, mCameraProperties->get(CameraProperties::FOCAL_LENGTH)); + p.set(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, mCameraProperties->get(CameraProperties::HOR_ANGLE)); + p.set(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, mCameraProperties->get(CameraProperties::VER_ANGLE)); + p.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,mCameraProperties->get(CameraProperties::FRAMERATE_RANGE)); + p.set(TICameraParameters::KEY_SENSOR_ORIENTATION, mCameraProperties->get(CameraProperties::SENSOR_ORIENTATION)); + p.set(TICameraParameters::KEY_SENSOR_ORIENTATION_VALUES, mCameraProperties->get(CameraProperties::SENSOR_ORIENTATION_VALUES)); + p.set(TICameraParameters::KEY_EXIF_MAKE, mCameraProperties->get(CameraProperties::EXIF_MAKE)); + p.set(TICameraParameters::KEY_EXIF_MODEL, mCameraProperties->get(CameraProperties::EXIF_MODEL)); + p.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, mCameraProperties->get(CameraProperties::JPEG_THUMBNAIL_QUALITY)); + p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar"); + p.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW, mCameraProperties->get(CameraProperties::MAX_FD_HW_FACES)); + p.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW, mCameraProperties->get(CameraProperties::MAX_FD_SW_FACES)); + + // Only one area a.k.a Touch AF for now. + // TODO: Add support for multiple focus areas. + p.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, mCameraProperties->get(CameraProperties::MAX_FOCUS_AREAS)); + p.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK, mCameraProperties->get(CameraProperties::AUTO_EXPOSURE_LOCK)); + p.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK, mCameraProperties->get(CameraProperties::AUTO_WHITEBALANCE_LOCK)); + p.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS, mCameraProperties->get(CameraProperties::MAX_NUM_METERING_AREAS)); + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Stop a previously started preview. + @param none + @return none + + */ +void CameraHal::forceStopPreview() +{ + LOG_FUNCTION_NAME; + + // stop bracketing if it is running + stopImageBracketing(); + + if(mDisplayAdapter.get() != NULL) { + ///Stop the buffer display first + mDisplayAdapter->disableDisplay(); + } + + if(mAppCallbackNotifier.get() != NULL) { + //Stop the callback sending + mAppCallbackNotifier->stop(); + mAppCallbackNotifier->stopPreviewCallbacks(); + } + + // since prerequisite for capturing is for camera system + // to be previewing...cancel all captures before stopping + // preview + if ( mCameraAdapter->getState() == CameraAdapter::CAPTURE_STATE && + mCameraAdapter->getNextState() != CameraAdapter::PREVIEW_STATE) { + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE); + } + + if ( NULL != mCameraAdapter ) { + cancelAutoFocus(); + //Stop the source of frames + mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW); + } + + freePreviewBufs(); + freePreviewDataBufs(); + + mPreviewEnabled = false; + mDisplayPaused = false; + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Deallocates memory for all the resources held by Camera HAL. + + Frees the following objects- CameraAdapter, AppCallbackNotifier, DisplayAdapter, + and Memory Manager + + @param none + @return none + + */ +void CameraHal::deinitialize() +{ + LOG_FUNCTION_NAME; + + if ( mPreviewEnabled ) { + forceStopPreview(); + } + + freeImageBufs(); + + mSetPreviewWindowCalled = false; + + if (mSensorListener.get()) { + mSensorListener->disableSensor(SensorListener::SENSOR_ORIENTATION); + mSensorListener.clear(); + mSensorListener = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + +} + +status_t CameraHal::storeMetaDataInBuffers(bool enable) +{ + LOG_FUNCTION_NAME; + + return mAppCallbackNotifier->useMetaDataBufferMode(enable); + + LOG_FUNCTION_NAME_EXIT; +} + +}; + + diff --git a/camera/CameraHalCommon.cpp b/camera/CameraHalCommon.cpp new file mode 100644 index 0000000..6d4ea2c --- /dev/null +++ b/camera/CameraHalCommon.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + +#include "CameraHal.h" + +namespace android { + +const char CameraHal::PARAMS_DELIMITER []= ","; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +struct timeval CameraHal::ppm_start; + +#endif + +#if PPM_INSTRUMENTATION + +/** + @brief PPM instrumentation + + Dumps the current time offset. The time reference point + lies within the CameraHAL constructor. + + @param str - log message + @return none + + */ +void CameraHal::PPM(const char* str){ + struct timeval ppm; + + gettimeofday(&ppm, NULL); + ppm.tv_sec = ppm.tv_sec - ppm_start.tv_sec; + ppm.tv_sec = ppm.tv_sec * 1000000; + ppm.tv_sec = ppm.tv_sec + ppm.tv_usec - ppm_start.tv_usec; + + LOGD("PPM: %s :%ld.%ld ms", str, ( ppm.tv_sec /1000 ), ( ppm.tv_sec % 1000 )); +} + +#elif PPM_INSTRUMENTATION_ABS + +/** + @brief PPM instrumentation + + Dumps the current time offset. The time reference point + lies within the CameraHAL constructor. This implemetation + will also dump the abosolute timestamp, which is useful when + post calculation is done with data coming from the upper + layers (Camera application etc.) + + @param str - log message + @return none + + */ +void CameraHal::PPM(const char* str){ + struct timeval ppm; + + unsigned long long elapsed, absolute; + gettimeofday(&ppm, NULL); + elapsed = ppm.tv_sec - ppm_start.tv_sec; + elapsed *= 1000000; + elapsed += ppm.tv_usec - ppm_start.tv_usec; + absolute = ppm.tv_sec; + absolute *= 1000; + absolute += ppm.tv_usec /1000; + + LOGD("PPM: %s :%llu.%llu ms : %llu ms", str, ( elapsed /1000 ), ( elapsed % 1000 ), absolute); +} + +#endif + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + +/** + @brief PPM instrumentation + + Calculates and dumps the elapsed time using 'ppm_first' as + reference. + + @param str - log message + @return none + + */ +void CameraHal::PPM(const char* str, struct timeval* ppm_first, ...){ + char temp_str[256]; + struct timeval ppm; + unsigned long long absolute; + va_list args; + + va_start(args, ppm_first); + vsprintf(temp_str, str, args); + gettimeofday(&ppm, NULL); + absolute = ppm.tv_sec; + absolute *= 1000; + absolute += ppm.tv_usec /1000; + ppm.tv_sec = ppm.tv_sec - ppm_first->tv_sec; + ppm.tv_sec = ppm.tv_sec * 1000000; + ppm.tv_sec = ppm.tv_sec + ppm.tv_usec - ppm_first->tv_usec; + + LOGD("PPM: %s :%ld.%ld ms : %llu ms", temp_str, ( ppm.tv_sec /1000 ), ( ppm.tv_sec % 1000 ), absolute); + + va_end(args); +} + +#endif + +}; + + diff --git a/camera/CameraHalUtilClasses.cpp b/camera/CameraHalUtilClasses.cpp new file mode 100644 index 0000000..84eea38 --- /dev/null +++ b/camera/CameraHalUtilClasses.cpp @@ -0,0 +1,273 @@ +/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * 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 CameraHalUtilClasses.cpp
+*
+* This file maps the CameraHardwareInterface to the Camera interfaces on OMAP4 (mainly OMX).
+*
+*/
+
+#define LOG_TAG "CameraHAL"
+
+
+#include "CameraHal.h"
+
+namespace android {
+
+/*--------------------FrameProvider Class STARTS here-----------------------------*/
+
+int FrameProvider::enableFrameNotification(int32_t frameTypes)
+{
+ LOG_FUNCTION_NAME;
+ status_t ret = NO_ERROR;
+
+ ///Enable the frame notification to CameraAdapter (which implements FrameNotifier interface)
+ mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
+ , mFrameCallback
+ , NULL
+ , mCookie
+ );
+
+ LOG_FUNCTION_NAME_EXIT;
+ return ret;
+}
+
+int FrameProvider::disableFrameNotification(int32_t frameTypes)
+{
+ LOG_FUNCTION_NAME;
+ status_t ret = NO_ERROR;
+
+ mFrameNotifier->disableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
+ , mCookie
+ );
+
+ LOG_FUNCTION_NAME_EXIT;
+ return ret;
+}
+
+int FrameProvider::returnFrame(void *frameBuf, CameraFrame::FrameType frameType)
+{
+ status_t ret = NO_ERROR;
+
+ mFrameNotifier->returnFrame(frameBuf, frameType);
+
+ return ret;
+}
+
+
+/*--------------------FrameProvider Class ENDS here-----------------------------*/
+
+/*--------------------EventProvider Class STARTS here-----------------------------*/
+
+int EventProvider::enableEventNotification(int32_t frameTypes)
+{
+ LOG_FUNCTION_NAME;
+ status_t ret = NO_ERROR;
+
+ ///Enable the frame notification to CameraAdapter (which implements FrameNotifier interface)
+ mEventNotifier->enableMsgType(frameTypes<<MessageNotifier::EVENT_BIT_FIELD_POSITION
+ , NULL
+ , mEventCallback
+ , mCookie
+ );
+
+ LOG_FUNCTION_NAME_EXIT;
+ return ret;
+}
+
+int EventProvider::disableEventNotification(int32_t frameTypes)
+{
+ LOG_FUNCTION_NAME;
+ status_t ret = NO_ERROR;
+
+ mEventNotifier->disableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
+ , mCookie
+ );
+
+ LOG_FUNCTION_NAME_EXIT;
+ return ret;
+}
+
+/*--------------------EventProvider Class ENDS here-----------------------------*/
+
+/*--------------------CameraArea Class STARTS here-----------------------------*/
+
+status_t CameraArea::transfrom(size_t width,
+ size_t height,
+ size_t &top,
+ size_t &left,
+ size_t &areaWidth,
+ size_t &areaHeight)
+{
+ status_t ret = NO_ERROR;
+ size_t hRange, vRange;
+ double hScale, vScale;
+
+ LOG_FUNCTION_NAME
+
+ hRange = CameraArea::RIGHT - CameraArea::LEFT;
+ vRange = CameraArea::BOTTOM - CameraArea::TOP;
+ hScale = ( double ) width / ( double ) hRange;
+ vScale = ( double ) height / ( double ) vRange;
+
+ top = ( mTop + vRange / 2 ) * vScale;
+ left = ( mLeft + hRange / 2 ) * hScale;
+ areaHeight = ( mBottom + vRange / 2 ) * vScale;
+ areaHeight -= top;
+ areaWidth = ( mRight + hRange / 2) * hScale;
+ areaWidth -= left;
+
+ LOG_FUNCTION_NAME_EXIT
+
+ return ret;
+}
+
+status_t CameraArea::parseFocusArea(const char *area,
+ size_t areaLength,
+ Vector< sp<CameraArea> > &areas)
+{
+ status_t ret = NO_ERROR;
+ char *ctx;
+ char *pArea = NULL;
+ char *pStart = NULL;
+ char *pEnd = NULL;
+ const char *startToken = "(";
+ const char endToken = ')';
+ const char sep = ',';
+ ssize_t top, left, bottom, right, weight;
+ char *tmpBuffer = NULL;
+ sp<CameraArea> currentArea;
+
+ LOG_FUNCTION_NAME
+
+ if ( ( NULL == area ) ||
+ ( 0 >= areaLength ) )
+ {
+ return -EINVAL;
+ }
+
+ tmpBuffer = ( char * ) malloc(areaLength);
+ if ( NULL == tmpBuffer )
+ {
+ return -ENOMEM;
+ }
+
+ memcpy(tmpBuffer, area, areaLength);
+
+ pArea = strtok_r(tmpBuffer, startToken, &ctx);
+
+ do
+ {
+
+ pStart = pArea;
+ if ( NULL == pStart )
+ {
+ CAMHAL_LOGEA("Parsing of the left area coordinate failed!");
+ ret = -EINVAL;
+ break;
+ }
+ else
+ {
+ left = static_cast<ssize_t>(strtol(pStart, &pEnd, 10));
+ }
+
+ if ( sep != *pEnd )
+ {
+ CAMHAL_LOGEA("Parsing of the top area coordinate failed!");
+ ret = -EINVAL;
+ break;
+ }
+ else
+ {
+ top = static_cast<ssize_t>(strtol(pEnd+1, &pEnd, 10));
+ }
+
+ if ( sep != *pEnd )
+ {
+ CAMHAL_LOGEA("Parsing of the right area coordinate failed!");
+ ret = -EINVAL;
+ break;
+ }
+ else
+ {
+ right = static_cast<ssize_t>(strtol(pEnd+1, &pEnd, 10));
+ }
+
+ if ( sep != *pEnd )
+ {
+ CAMHAL_LOGEA("Parsing of the bottom area coordinate failed!");
+ ret = -EINVAL;
+ break;
+ }
+ else
+ {
+ bottom = static_cast<ssize_t>(strtol(pEnd+1, &pEnd, 10));
+ }
+
+ if ( sep != *pEnd )
+ {
+ CAMHAL_LOGEA("Parsing of the weight area coordinate failed!");
+ ret = -EINVAL;
+ break;
+ }
+ else
+ {
+ weight = static_cast<ssize_t>(strtol(pEnd+1, &pEnd, 10));
+ }
+
+ if ( endToken != *pEnd )
+ {
+ CAMHAL_LOGEA("Malformed area!");
+ ret = -EINVAL;
+ break;
+ }
+
+ currentArea = new CameraArea(top, left, bottom, right, weight);
+ CAMHAL_LOGDB("Area parsed [%dx%d, %dx%d] %d",
+ ( int ) top,
+ ( int ) left,
+ ( int ) bottom,
+ ( int ) right,
+ ( int )weight);
+ if ( NULL != currentArea.get() )
+ {
+ areas.add(currentArea);
+ }
+ else
+ {
+ ret = -ENOMEM;
+ break;
+ }
+
+ pArea = strtok_r(NULL, startToken, &ctx);
+
+ }
+ while ( NULL != pArea );
+
+ if ( NULL != tmpBuffer )
+ {
+ free(tmpBuffer);
+ }
+
+ LOG_FUNCTION_NAME_EXIT
+
+ return ret;
+}
+
+/*--------------------CameraArea Class ENDS here-----------------------------*/
+
+};
diff --git a/camera/CameraHal_Module.cpp b/camera/CameraHal_Module.cpp new file mode 100644 index 0000000..cf3ec60 --- /dev/null +++ b/camera/CameraHal_Module.cpp @@ -0,0 +1,676 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 CameraHal.cpp +* +* This file maps the Camera Hardware Interface to V4L2. +* +*/ + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "CameraProperties.h" +#include "TICameraParameters.h" + + +static android::CameraProperties gCameraProperties; +static android::CameraHal* gCameraHals[MAX_CAMERAS_SUPPORTED]; + +static int camera_device_open(const hw_module_t* module, const char* name, + hw_device_t** device); +static int camera_device_close(hw_device_t* device); +static int camera_get_number_of_cameras(void); +static int camera_get_camera_info(int camera_id, struct camera_info *info); + +static struct hw_module_methods_t camera_module_methods = { + open: camera_device_open +}; + +camera_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: CAMERA_HARDWARE_MODULE_ID, + name: "TI OMAP CameraHal Module", + author: "TI", + methods: &camera_module_methods, + dso: NULL, /* remove compilation warnings */ + reserved: {0}, /* remove compilation warnings */ + }, + get_number_of_cameras: camera_get_number_of_cameras, + get_camera_info: camera_get_camera_info, +}; + +typedef struct ti_camera_device { + camera_device_t base; + /* TI specific "private" data can go here (base.priv) */ + int cameraid; +} ti_camera_device_t; + + +/******************************************************************* + * implementation of camera_device_ops functions + *******************************************************************/ + +int camera_set_preview_window(struct camera_device * device, + struct preview_stream_ops *window) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->setPreviewWindow(window); + + return rv; +} + +void camera_set_callbacks(struct camera_device * device, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->setCallbacks(notify_cb, data_cb, data_cb_timestamp, get_memory, user); +} + +void camera_enable_msg_type(struct camera_device * device, int32_t msg_type) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->enableMsgType(msg_type); +} + +void camera_disable_msg_type(struct camera_device * device, int32_t msg_type) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->disableMsgType(msg_type); +} + +int camera_msg_type_enabled(struct camera_device * device, int32_t msg_type) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return 0; + + ti_dev = (ti_camera_device_t*) device; + + return gCameraHals[ti_dev->cameraid]->msgTypeEnabled(msg_type); +} + +int camera_start_preview(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->startPreview(); + + return rv; +} + +void camera_stop_preview(struct camera_device * device) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->stopPreview(); +} + +int camera_preview_enabled(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->previewEnabled(); + return rv; +} + +int camera_store_meta_data_in_buffers(struct camera_device * device, int enable) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + // TODO: meta data buffer not current supported + rv = gCameraHals[ti_dev->cameraid]->storeMetaDataInBuffers(enable); + return rv; + //return enable ? android::INVALID_OPERATION: android::OK; +} + +int camera_start_recording(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->startRecording(); + return rv; +} + +void camera_stop_recording(struct camera_device * device) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->stopRecording(); +} + +int camera_recording_enabled(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->recordingEnabled(); + return rv; +} + +void camera_release_recording_frame(struct camera_device * device, + const void *opaque) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->releaseRecordingFrame(opaque); +} + +int camera_auto_focus(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->autoFocus(); + return rv; +} + +int camera_cancel_auto_focus(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->cancelAutoFocus(); + return rv; +} + +int camera_take_picture(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->takePicture(); + return rv; +} + +int camera_cancel_picture(struct camera_device * device) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->cancelPicture(); + return rv; +} + +int camera_set_parameters(struct camera_device * device, const char *params) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->setParameters(params); + return rv; +} + +char* camera_get_parameters(struct camera_device * device) +{ + char* param = NULL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return NULL; + + ti_dev = (ti_camera_device_t*) device; + + param = gCameraHals[ti_dev->cameraid]->getParameters(); + + return param; +} + +static void camera_put_parameters(struct camera_device *device, char *parms) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->putParameters(parms); +} + +int camera_send_command(struct camera_device * device, + int32_t cmd, int32_t arg1, int32_t arg2) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->sendCommand(cmd, arg1, arg2); + return rv; +} + +void camera_release(struct camera_device * device) +{ + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if(!device) + return; + + ti_dev = (ti_camera_device_t*) device; + + gCameraHals[ti_dev->cameraid]->release(); +} + +int camera_dump(struct camera_device * device, int fd) +{ + int rv = -EINVAL; + ti_camera_device_t* ti_dev = NULL; + + if(!device) + return rv; + + ti_dev = (ti_camera_device_t*) device; + + rv = gCameraHals[ti_dev->cameraid]->dump(fd); + return rv; +} + +extern "C" void heaptracker_free_leaked_memory(void); + +int camera_device_close(hw_device_t* device) +{ + int ret = 0; + ti_camera_device_t* ti_dev = NULL; + + LOGV("%s", __FUNCTION__); + + if (!device) { + ret = -EINVAL; + goto done; + } + + ti_dev = (ti_camera_device_t*) device; + + if (gCameraHals[ti_dev->cameraid]) { + delete gCameraHals[ti_dev->cameraid]; + gCameraHals[ti_dev->cameraid] = NULL; + } + + if (ti_dev->base.ops) { + free(ti_dev->base.ops); + } + free(ti_dev); + +done: +#ifdef HEAPTRACKER + heaptracker_free_leaked_memory(); +#endif + return ret; +} + +/******************************************************************* + * implementation of camera_module functions + *******************************************************************/ + +/* open device handle to one of the cameras + * + * assume camera service will keep singleton of each camera + * so this function will always only be called once per camera instance + */ + +int camera_device_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + int rv = -EINVAL; + int num_cameras = 0; + int cameraid; + ti_camera_device_t* camera_device = NULL; + camera_device_ops_t* camera_ops = NULL; + android::CameraHal* camera = NULL; + android::CameraProperties::Properties* properties = NULL; + + LOGI("camera_device open"); + + if (name != NULL) { + cameraid = atoi(name); + num_cameras = gCameraProperties.camerasSupported(); + + if(cameraid > num_cameras) + { + LOGE("camera service provided cameraid out of bounds, " + "cameraid = %d, num supported = %d", + cameraid, num_cameras); + goto fail; + } + + camera_device = (ti_camera_device_t*)malloc(sizeof(*camera_device)); + if(!camera_device) + { + LOGE("camera_device allocation fail"); + rv = -ENOMEM; + goto fail; + } + + camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops)); + if(!camera_ops) + { + LOGE("camera_ops allocation fail"); + rv = -ENOMEM; + goto fail; + } + + memset(camera_device, 0, sizeof(*camera_device)); + memset(camera_ops, 0, sizeof(*camera_ops)); + + camera_device->base.common.tag = HARDWARE_DEVICE_TAG; + camera_device->base.common.version = 0; + camera_device->base.common.module = (hw_module_t *)(module); + camera_device->base.common.close = camera_device_close; + camera_device->base.ops = camera_ops; + + camera_ops->set_preview_window = camera_set_preview_window; + camera_ops->set_callbacks = camera_set_callbacks; + camera_ops->enable_msg_type = camera_enable_msg_type; + camera_ops->disable_msg_type = camera_disable_msg_type; + camera_ops->msg_type_enabled = camera_msg_type_enabled; + camera_ops->start_preview = camera_start_preview; + camera_ops->stop_preview = camera_stop_preview; + camera_ops->preview_enabled = camera_preview_enabled; + camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers; + camera_ops->start_recording = camera_start_recording; + camera_ops->stop_recording = camera_stop_recording; + camera_ops->recording_enabled = camera_recording_enabled; + camera_ops->release_recording_frame = camera_release_recording_frame; + camera_ops->auto_focus = camera_auto_focus; + camera_ops->cancel_auto_focus = camera_cancel_auto_focus; + camera_ops->take_picture = camera_take_picture; + camera_ops->cancel_picture = camera_cancel_picture; + camera_ops->set_parameters = camera_set_parameters; + camera_ops->get_parameters = camera_get_parameters; + camera_ops->put_parameters = camera_put_parameters; + camera_ops->send_command = camera_send_command; + camera_ops->release = camera_release; + camera_ops->dump = camera_dump; + + *device = &camera_device->base.common; + + // -------- TI specific stuff -------- + + camera_device->cameraid = cameraid; + + if(gCameraProperties.getProperties(cameraid, &properties) < 0) + { + LOGE("Couldn't get camera properties"); + rv = -ENOMEM; + goto fail; + } + + camera = new android::CameraHal(cameraid); + + if(!camera) + { + LOGE("Couldn't create instance of CameraHal class"); + rv = -ENOMEM; + goto fail; + } + + if(properties && (camera->initialize(properties) != android::NO_ERROR)) + { + LOGE("Couldn't initialize camera instance"); + rv = -ENODEV; + goto fail; + } + + gCameraHals[cameraid] = camera; + } + + return rv; + +fail: + + if(camera_device) + free(camera_device); + if(camera_ops) + free(camera_ops); + if(camera) + delete camera; + + return rv; +} + +int camera_get_number_of_cameras(void) +{ + int num_cameras = MAX_CAMERAS_SUPPORTED; + + // TODO(XXX): Ducati is not loaded yet when camera service gets here + // Lets revisit this later to see if we can somehow get this working +#if 0 + // this going to be the first call from camera service + // initialize camera properties here... + if(gCameraProperties.initialize() != android::NO_ERROR) + { + CAMHAL_LOGEA("Unable to create or initialize CameraProperties"); + return NULL; + } + + num_cameras = gCameraProperties.camerasSupported(); +#endif + + return num_cameras; +} + +int camera_get_camera_info(int camera_id, struct camera_info *info) +{ + int rv = 0; + int face_value = CAMERA_FACING_BACK; + int orientation = 0; + const char *valstr = NULL; + android::CameraProperties::Properties* properties = NULL; + + // this going to be the first call from camera service + // initialize camera properties here... + if(gCameraProperties.initialize() != android::NO_ERROR) + { + CAMHAL_LOGEA("Unable to create or initialize CameraProperties"); + return NULL; + } + + //Get camera properties for camera index + if(gCameraProperties.getProperties(camera_id, &properties) < 0) + { + LOGE("Couldn't get camera properties"); + rv = -EINVAL; + goto end; + } + + if(properties) + { + valstr = properties->get(android::CameraProperties::FACING_INDEX); + if(valstr != NULL) + { + if (strcmp(valstr, (const char *) android::TICameraParameters::FACING_FRONT) == 0) + { + face_value = CAMERA_FACING_FRONT; + } + else if (strcmp(valstr, (const char *) android::TICameraParameters::FACING_BACK) == 0) + { + face_value = CAMERA_FACING_BACK; + } + } + + valstr = properties->get(android::CameraProperties::ORIENTATION_INDEX); + if(valstr != NULL) + { + orientation = atoi(valstr); + } + } + else + { + CAMHAL_LOGEB("getProperties() returned a NULL property set for Camera id %d", camera_id); + } + + info->facing = face_value; + info->orientation = orientation; + +end: + return rv; +} + + + + + diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp new file mode 100644 index 0000000..f19a0fe --- /dev/null +++ b/camera/CameraParameters.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 CameraProperties.cpp +* +* This file maps the CameraHardwareInterface to the Camera interfaces on OMAP4 (mainly OMX). +* +*/ + +#include "CameraHal.h" +#include "CameraProperties.h" + +namespace android { + +const char CameraProperties::INVALID[]="prop-invalid-key"; +const char CameraProperties::CAMERA_NAME[]="prop-camera-name"; +const char CameraProperties::CAMERA_SENSOR_INDEX[]="prop-sensor-index"; +const char CameraProperties::ORIENTATION_INDEX[]="prop-orientation"; +const char CameraProperties::FACING_INDEX[]="prop-facing"; +const char CameraProperties::S3D_SUPPORTED[]="prop-s3d-supported"; +const char CameraProperties::SUPPORTED_PREVIEW_SIZES[] = "prop-preview-size-values"; +const char CameraProperties::SUPPORTED_PREVIEW_FORMATS[] = "prop-preview-format-values"; +const char CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES[] = "prop-preview-frame-rate-values"; +const char CameraProperties::SUPPORTED_PICTURE_SIZES[] = "prop-picture-size-values"; +const char CameraProperties::SUPPORTED_PICTURE_FORMATS[] = "prop-picture-format-values"; +const char CameraProperties::SUPPORTED_THUMBNAIL_SIZES[] = "prop-jpeg-thumbnail-size-values"; +const char CameraProperties::SUPPORTED_WHITE_BALANCE[] = "prop-whitebalance-values"; +const char CameraProperties::SUPPORTED_EFFECTS[] = "prop-effect-values"; +const char CameraProperties::SUPPORTED_ANTIBANDING[] = "prop-antibanding-values"; +const char CameraProperties::SUPPORTED_EXPOSURE_MODES[] = "prop-exposure-mode-values"; +const char CameraProperties::SUPPORTED_EV_MAX[] = "prop-ev-compensation-max"; +const char CameraProperties::SUPPORTED_EV_MIN[] = "prop-ev-compensation-min"; +const char CameraProperties::SUPPORTED_EV_STEP[] = "prop-ev-compensation-step"; +const char CameraProperties::SUPPORTED_ISO_VALUES[] = "prop-iso-mode-values"; +const char CameraProperties::SUPPORTED_SCENE_MODES[] = "prop-scene-mode-values"; +const char CameraProperties::SUPPORTED_FLASH_MODES[] = "prop-flash-mode-values"; +const char CameraProperties::SUPPORTED_FOCUS_MODES[] = "prop-focus-mode-values"; +const char CameraProperties::REQUIRED_PREVIEW_BUFS[] = "prop-required-preview-bufs"; +const char CameraProperties::REQUIRED_IMAGE_BUFS[] = "prop-required-image-bufs"; +const char CameraProperties::SUPPORTED_ZOOM_RATIOS[] = "prop-zoom-ratios"; +const char CameraProperties::SUPPORTED_ZOOM_STAGES[] = "prop-zoom-stages"; +const char CameraProperties::SUPPORTED_IPP_MODES[] = "prop-ipp-values"; +const char CameraProperties::SMOOTH_ZOOM_SUPPORTED[] = "prop-smooth-zoom-supported"; +const char CameraProperties::ZOOM_SUPPORTED[] = "prop-zoom-supported"; +const char CameraProperties::PREVIEW_SIZE[] = "prop-preview-size-default"; +const char CameraProperties::PREVIEW_FORMAT[] = "prop-preview-format-default"; +const char CameraProperties::PREVIEW_FRAME_RATE[] = "prop-preview-frame-rate-default"; +const char CameraProperties::ZOOM[] = "prop-zoom-default"; +const char CameraProperties::PICTURE_SIZE[] = "prop-picture-size-default"; +const char CameraProperties::PICTURE_FORMAT[] = "prop-picture-format-default"; +const char CameraProperties::JPEG_THUMBNAIL_SIZE[] = "prop-jpeg-thumbnail-size-default"; +const char CameraProperties::WHITEBALANCE[] = "prop-whitebalance-default"; +const char CameraProperties::EFFECT[] = "prop-effect-default"; +const char CameraProperties::ANTIBANDING[] = "prop-antibanding-default"; +const char CameraProperties::EXPOSURE_MODE[] = "prop-exposure-mode-default"; +const char CameraProperties::EV_COMPENSATION[] = "prop-ev-compensation-default"; +const char CameraProperties::ISO_MODE[] = "prop-iso-mode-default"; +const char CameraProperties::FOCUS_MODE[] = "prop-focus-mode-default"; +const char CameraProperties::SCENE_MODE[] = "prop-scene-mode-default"; +const char CameraProperties::FLASH_MODE[] = "prop-flash-mode-default"; +const char CameraProperties::JPEG_QUALITY[] = "prop-jpeg-quality-default"; +const char CameraProperties::CONTRAST[] = "prop-contrast-default"; +const char CameraProperties::BRIGHTNESS[] = "prop-brightness-default"; +const char CameraProperties::SATURATION[] = "prop-saturation-default"; +const char CameraProperties::SHARPNESS[] = "prop-sharpness-default"; +const char CameraProperties::IPP[] = "prop-ipp-default"; +const char CameraProperties::S3D2D_PREVIEW[] = "prop-s3d2d-preview"; +const char CameraProperties::S3D2D_PREVIEW_MODES[] = "prop-s3d2d-preview-values"; +const char CameraProperties::AUTOCONVERGENCE[] = "prop-auto-convergence"; +const char CameraProperties::AUTOCONVERGENCE_MODE[] = "prop-auto-convergence-mode"; +const char CameraProperties::MANUALCONVERGENCE_VALUES[] = "prop-manual-convergence-values"; +const char CameraProperties::VSTAB[] = "prop-vstab-default"; +const char CameraProperties::VSTAB_VALUES[] = "prop-vstab-values"; +const char CameraProperties::REVISION[] = "prop-revision"; +const char CameraProperties::FOCAL_LENGTH[] = "prop-focal-length"; +const char CameraProperties::HOR_ANGLE[] = "prop-horizontal-angle"; +const char CameraProperties::VER_ANGLE[] = "prop-vertical-angle"; +const char CameraProperties::FRAMERATE_RANGE[]="prop-framerate-range-default"; +const char CameraProperties::FRAMERATE_RANGE_SUPPORTED[]="prop-framerate-range-values"; +const char CameraProperties::SENSOR_ORIENTATION[]= "sensor-orientation"; +const char CameraProperties::SENSOR_ORIENTATION_VALUES[]= "sensor-orientation-values"; +const char CameraProperties::EXIF_MAKE[] = "prop-exif-make"; +const char CameraProperties::EXIF_MODEL[] = "prop-exif-model"; +const char CameraProperties::JPEG_THUMBNAIL_QUALITY[] = "prop-jpeg-thumbnail-quality-default"; +const char CameraProperties::MAX_FOCUS_AREAS[] = "prop-max-focus-areas"; +const char CameraProperties::MAX_FD_HW_FACES[] = "prop-max-fd-hw-faces"; +const char CameraProperties::MAX_FD_SW_FACES[] = "prop-max-fd-sw-faces"; +const char CameraProperties::AUTO_EXPOSURE_LOCK[] = "prop-auto-exposure-lock"; +const char CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED[] = "prop-auto-exposure-lock-supported"; +const char CameraProperties::AUTO_WHITEBALANCE_LOCK[] = "prop-auto-whitebalance-lock"; +const char CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "prop-auto-whitebalance-lock-supported"; +const char CameraProperties::MAX_NUM_METERING_AREAS[] = "prop-max-num-metering-areas"; +const char CameraProperties::METERING_AREAS[] = "prop-metering-areas"; + +const char CameraProperties::DEFAULT_VALUE[] = ""; + +const char CameraProperties::PARAMS_DELIMITER []= ","; + +// Returns the properties class for a specific Camera +// Each value is indexed by the CameraProperties::CameraPropertyIndex enum +int CameraProperties::getProperties(int cameraIndex, CameraProperties::Properties** properties) +{ + LOG_FUNCTION_NAME; + + if((unsigned int)cameraIndex >= mCamerasSupported) + { + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + *properties = mCameraProps+cameraIndex; + + LOG_FUNCTION_NAME_EXIT; + return 0; +} + +ssize_t CameraProperties::Properties::set(const char *prop, const char *value) +{ + if(!prop) + return -EINVAL; + if(!value) + value = DEFAULT_VALUE; + + return mProperties->replaceValueFor(String8(prop), String8(value)); +} + +ssize_t CameraProperties::Properties::set(const char *prop, int value) +{ + char s_val[30]; + + sprintf(s_val, "%d", value); + + return set(prop, s_val); +} + +const char* CameraProperties::Properties::get(const char * prop) +{ + String8 value = mProperties->valueFor(String8(prop)); + return value.string(); +} + +void CameraProperties::Properties::dump() +{ + for (size_t i = 0; i < mProperties->size(); i++) + { + CAMHAL_LOGDB("%s = %s\n", + mProperties->keyAt(i).string(), + mProperties->valueAt(i).string()); + } +} + +const char* CameraProperties::Properties::keyAt(unsigned int index) +{ + if(index < mProperties->size()) + { + return mProperties->keyAt(index).string(); + } + return NULL; +} + +const char* CameraProperties::Properties::valueAt(unsigned int index) +{ + if(index < mProperties->size()) + { + return mProperties->valueAt(index).string(); + } + return NULL; +} + +}; diff --git a/camera/CameraProperties.cpp b/camera/CameraProperties.cpp new file mode 100644 index 0000000..47b2177 --- /dev/null +++ b/camera/CameraProperties.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 CameraProperties.cpp +* +* This file maps the CameraHardwareInterface to the Camera interfaces on OMAP4 (mainly OMX). +* +*/ + +//#include "CameraHal.h" +#include "DebugUtils.h" +#include "CameraProperties.h" + +#define CAMERA_ROOT "CameraRoot" +#define CAMERA_INSTANCE "CameraInstance" + +namespace android { + +// lower entries have higher priority +static const char* g_camera_adapters[] = { +#ifdef OMAP4_SUPPORT_OMX_CAMERA_ADAPTER + "libomxcameraadapter.so", +#endif +#ifdef OMAP4_SUPPORT_USB_CAMERA_ADAPTER + "libusbcameraadapter.so" +#endif +}; + +/********************************************************* + CameraProperties - public function implemetation +**********************************************************/ + +CameraProperties::CameraProperties() : mCamerasSupported(0) +{ + LOG_FUNCTION_NAME; + + mCamerasSupported = 0; + mInitialized = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +CameraProperties::~CameraProperties() +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; +} + + +// Initializes the CameraProperties class +status_t CameraProperties::initialize() +{ + LOG_FUNCTION_NAME; + + status_t ret; + + if(mInitialized) + return NO_ERROR; + + ret = loadProperties(); + + mInitialized = 1; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +extern "C" int CameraAdapter_Capabilities(CameraProperties::Properties* properties_array, + const unsigned int starting_camera, + const unsigned int max_camera); + +///Loads all the Camera related properties +status_t CameraProperties::loadProperties() +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + + // adapter updates capabilities and we update camera count + mCamerasSupported = CameraAdapter_Capabilities(mCameraProps, mCamerasSupported, MAX_CAMERAS_SUPPORTED); + + if((int)mCamerasSupported < 0) { + LOGE("error while getting capabilities"); + ret = UNKNOWN_ERROR; + } else if (mCamerasSupported > MAX_CAMERAS_SUPPORTED) { + LOGE("returned too many adapaters"); + ret = UNKNOWN_ERROR; + } else { + LOGE("num_cameras = %d", mCamerasSupported); + + for (unsigned int i = 0; i < mCamerasSupported; i++) { + mCameraProps[i].set(CAMERA_SENSOR_INDEX, i); + mCameraProps[i].dump(); + } + } + + LOGV("mCamerasSupported = %d", mCamerasSupported); + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +// Returns the number of Cameras found +int CameraProperties::camerasSupported() +{ + LOG_FUNCTION_NAME; + return mCamerasSupported; +} + +}; diff --git a/camera/MemoryManager.cpp b/camera/MemoryManager.cpp new file mode 100644 index 0000000..f86b263 --- /dev/null +++ b/camera/MemoryManager.cpp @@ -0,0 +1,284 @@ +/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * 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.
+ */
+
+
+
+#define LOG_TAG "CameraHAL"
+
+
+#include "CameraHal.h"
+#include "TICameraParameters.h"
+
+extern "C" {
+
+#include "memmgr.h"
+#include "tiler.h"
+//#include <timm_osal_interfaces.h>
+//#include <timm_osal_trace.h>
+
+
+};
+
+namespace android {
+
+///@todo Move these constants to a common header file, preferably in tiler.h
+#define STRIDE_8BIT (4 * 1024)
+#define STRIDE_16BIT (4 * 1024)
+
+#define ALLOCATION_2D 2
+
+///Utility Macro Declarations
+#define ZERO_OUT_ARR(a,b) { for(unsigned int i=0;i<b;i++) a[i]=NULL;}
+
+#define ZERO_OUT_STRUCT(a, b) memset(a, 0, sizeof(b));
+
+/*--------------------MemoryManager Class STARTS here-----------------------------*/
+void* MemoryManager::allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs)
+{
+ LOG_FUNCTION_NAME;
+ ///We allocate numBufs+1 because the last entry will be marked NULL to indicate end of array, which is used when freeing
+ ///the buffers
+ const uint numArrayEntriesC = (uint)(numBufs+1);
+
+ MemAllocBlock *tMemBlock;
+
+
+ ///Allocate a buffer array
+ uint32_t *bufsArr = new uint32_t[numArrayEntriesC];
+ if(!bufsArr)
+ {
+ CAMHAL_LOGEB("Allocation failed when creating buffers array of %d uint32_t elements", numArrayEntriesC);
+ LOG_FUNCTION_NAME_EXIT;
+ return NULL;
+ }
+
+ ///Initialize the array with zeros - this will help us while freeing the array in case of error
+ ///If a value of an array element is NULL, it means we didnt allocate it
+ ZERO_OUT_ARR(bufsArr, numArrayEntriesC);
+
+ ///If the bytes field is not zero, it means it is a 1-D tiler buffer request (possibly for image capture bit stream buffer)
+ if(bytes!=0)
+ {
+ ///MemAllocBlock is the structure that describes the buffer alloc request to MemMgr
+ tMemBlock = (MemAllocBlock*)malloc(sizeof(MemAllocBlock));
+
+ if(!tMemBlock)
+ {
+ delete [] bufsArr;
+ return NULL;
+ }
+
+ ZERO_OUT_STRUCT(tMemBlock, MemAllocBlock );
+
+ ///1D buffers
+ for (int i = 0; i < numBufs; i++)
+ {
+ tMemBlock->dim.len = bytes;
+ tMemBlock->pixelFormat = PIXEL_FMT_PAGE;
+ tMemBlock->stride = 0;
+ CAMHAL_LOGDB("requested bytes = %d", bytes);
+ CAMHAL_LOGDB("tMemBlock.dim.len = %d", tMemBlock->dim.len);
+ bufsArr[i] = (uint32_t)MemMgr_Alloc(tMemBlock, 1);
+ if(!bufsArr[i])
+ {
+ LOGE("Buffer allocation failed for iteration %d", i);
+ goto error;
+ }
+ else
+ {
+ CAMHAL_LOGDB("Allocated Tiler PAGED mode buffer address[%x]", bufsArr[i]);
+ }
+ }
+
+ }
+ else ///If bytes is not zero, then it is a 2-D tiler buffer request
+ {
+ ///2D buffers
+ ///MemAllocBlock is the structure that describes the buffer alloc request to MemMgr
+ tMemBlock = (MemAllocBlock*)malloc(sizeof(MemAllocBlock)*ALLOCATION_2D);
+
+ if(!tMemBlock)
+ {
+ delete [] bufsArr;
+ return NULL;
+ }
+
+ memset(tMemBlock, 0, sizeof(MemAllocBlock)*ALLOCATION_2D);
+
+ for (int i = 0; i < numBufs; i++)
+ {
+ int numAllocs = 1;
+ pixel_fmt_t pixelFormat[ALLOCATION_2D];
+ int stride[ALLOCATION_2D];
+
+ if(!strcmp(format,(const char *) CameraParameters::PIXEL_FORMAT_YUV422I))
+ {
+ ///YUV422I format
+ pixelFormat[0] = PIXEL_FMT_16BIT;
+ stride[0] = STRIDE_16BIT;
+ numAllocs = 1;
+ }
+ else if(!strcmp(format,(const char *) CameraParameters::PIXEL_FORMAT_YUV420SP))
+ {
+ ///YUV420 NV12 format
+ pixelFormat[0] = PIXEL_FMT_8BIT;
+ pixelFormat[1] = PIXEL_FMT_16BIT;
+ stride[0] = STRIDE_8BIT;
+ stride[1] = STRIDE_16BIT;
+ numAllocs = 2;
+ }
+ else if(!strcmp(format,(const char *) CameraParameters::PIXEL_FORMAT_RGB565))
+ {
+ ///RGB 565 format
+ pixelFormat[0] = PIXEL_FMT_16BIT;
+ stride[0] = STRIDE_16BIT;
+ numAllocs = 1;
+ }
+ else if(!strcmp(format,(const char *) TICameraParameters::PIXEL_FORMAT_RAW))
+ {
+ ///RAW format
+ pixelFormat[0] = PIXEL_FMT_16BIT;
+ stride[0] = STRIDE_16BIT;
+ numAllocs = 1;
+ }
+ else
+ {
+ ///By default assume YUV420 NV12 format
+ ///YUV420 NV12 format
+ pixelFormat[0] = PIXEL_FMT_8BIT;
+ pixelFormat[1] = PIXEL_FMT_16BIT;
+ stride[0] = STRIDE_8BIT;
+ stride[1] = STRIDE_16BIT;
+ numAllocs = 2;
+ }
+
+ for(int index=0;index<numAllocs;index++)
+ {
+ tMemBlock[index].pixelFormat = pixelFormat[index];
+ tMemBlock[index].stride = stride[index];
+ tMemBlock[index].dim.area.width= width;/*width*/
+ tMemBlock[index].dim.area.height= height;/*height*/
+ }
+
+ bufsArr[i] = (uint32_t)MemMgr_Alloc(tMemBlock, numAllocs);
+ if(!bufsArr[i])
+ {
+ CAMHAL_LOGEB("Buffer allocation failed for iteration %d", i);
+ goto error;
+ }
+ else
+ {
+ CAMHAL_LOGDB("Allocated Tiler PAGED mode buffer address[%x]", bufsArr[i]);
+ }
+ }
+
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+
+
+ ///Free the request structure before returning from the function
+ free(tMemBlock);
+
+ return (void*)bufsArr;
+
+ error:
+ LOGE("Freeing buffers already allocated after error occurred");
+ freeBuffer(bufsArr);
+ free(tMemBlock);
+
+ if ( NULL != mErrorNotifier.get() )
+ {
+ mErrorNotifier->errorNotify(-ENOMEM);
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+ return NULL;
+}
+
+//TODO: Get needed data to map tiler buffers
+//Return dummy data for now
+uint32_t * MemoryManager::getOffsets()
+{
+ LOG_FUNCTION_NAME;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return NULL;
+}
+
+int MemoryManager::getFd()
+{
+ LOG_FUNCTION_NAME;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return -1;
+}
+
+int MemoryManager::freeBuffer(void* buf)
+{
+ status_t ret = NO_ERROR;
+ LOG_FUNCTION_NAME;
+
+ uint32_t *bufEntry = (uint32_t*)buf;
+
+ if(!bufEntry)
+ {
+ CAMHAL_LOGEA("NULL pointer passed to freebuffer");
+ LOG_FUNCTION_NAME_EXIT;
+ return BAD_VALUE;
+ }
+
+ while(*bufEntry)
+ {
+ ret |= MemMgr_Free((void*)*bufEntry++);
+ }
+
+ ///@todo Check if this way of deleting array is correct, else use malloc/free
+ uint32_t * bufArr = (uint32_t*)buf;
+ delete [] bufArr;
+
+ LOG_FUNCTION_NAME_EXIT;
+ return ret;
+}
+
+status_t MemoryManager::setErrorHandler(ErrorNotifier *errorNotifier)
+{
+ status_t ret = NO_ERROR;
+
+ LOG_FUNCTION_NAME;
+
+ if ( NULL == errorNotifier )
+ {
+ CAMHAL_LOGEA("Invalid Error Notifier reference");
+ ret = -EINVAL;
+ }
+
+ if ( NO_ERROR == ret )
+ {
+ mErrorNotifier = errorNotifier;
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return ret;
+}
+
+};
+
+
+/*--------------------MemoryManager Class ENDS here-----------------------------*/
diff --git a/camera/OMXCameraAdapter/OMX3A.cpp b/camera/OMXCameraAdapter/OMX3A.cpp new file mode 100644 index 0000000..1c347a2 --- /dev/null +++ b/camera/OMXCameraAdapter/OMX3A.cpp @@ -0,0 +1,1083 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMX3A.cpp +* +* This file contains functionality for handling 3A configurations. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" + +namespace android { + +status_t OMXCameraAdapter::setParameters3A(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + int mode = 0; + const char *str = NULL; + + LOG_FUNCTION_NAME; + + str = params.get(TICameraParameters::KEY_EXPOSURE_MODE); + mode = getLUTvalue_HALtoOMX( str, ExpLUT); + if ( ( str != NULL ) && ( mParameters3A.Exposure != mode ) ) + { + mParameters3A.Exposure = mode; + CAMHAL_LOGDB("Exposure mode %d", mode); + if ( 0 <= mParameters3A.Exposure ) + { + mPending3Asettings |= SetExpMode; + } + } + + str = params.get(CameraParameters::KEY_WHITE_BALANCE); + mode = getLUTvalue_HALtoOMX( str, WBalLUT); + if ( ( mFirstTimeInit || ( str != NULL ) ) && ( mode != mParameters3A.WhiteBallance ) ) + { + mParameters3A.WhiteBallance = mode; + CAMHAL_LOGDB("Whitebalance mode %d", mode); + if ( 0 <= mParameters3A.WhiteBallance ) + { + mPending3Asettings |= SetWhiteBallance; + } + } + + if ( 0 <= params.getInt(TICameraParameters::KEY_CONTRAST) ) + { + if ( mFirstTimeInit || + ( (mParameters3A.Contrast + CONTRAST_OFFSET) != + params.getInt(TICameraParameters::KEY_CONTRAST)) ) + { + mParameters3A.Contrast = params.getInt(TICameraParameters::KEY_CONTRAST) - CONTRAST_OFFSET; + CAMHAL_LOGDB("Contrast %d", mParameters3A.Contrast); + mPending3Asettings |= SetContrast; + } + } + + if ( 0 <= params.getInt(TICameraParameters::KEY_SHARPNESS) ) + { + if ( mFirstTimeInit || + ((mParameters3A.Sharpness + SHARPNESS_OFFSET) != + params.getInt(TICameraParameters::KEY_SHARPNESS))) + { + mParameters3A.Sharpness = params.getInt(TICameraParameters::KEY_SHARPNESS) - SHARPNESS_OFFSET; + CAMHAL_LOGDB("Sharpness %d", mParameters3A.Sharpness); + mPending3Asettings |= SetSharpness; + } + } + + if ( 0 <= params.getInt(TICameraParameters::KEY_SATURATION) ) + { + if ( mFirstTimeInit || + ((mParameters3A.Saturation + SATURATION_OFFSET) != + params.getInt(TICameraParameters::KEY_SATURATION)) ) + { + mParameters3A.Saturation = params.getInt(TICameraParameters::KEY_SATURATION) - SATURATION_OFFSET; + CAMHAL_LOGDB("Saturation %d", mParameters3A.Saturation); + mPending3Asettings |= SetSaturation; + } + } + + if ( 0 <= params.getInt(TICameraParameters::KEY_BRIGHTNESS) ) + { + if ( mFirstTimeInit || + (( mParameters3A.Brightness != + ( unsigned int ) params.getInt(TICameraParameters::KEY_BRIGHTNESS))) ) + { + mParameters3A.Brightness = (unsigned)params.getInt(TICameraParameters::KEY_BRIGHTNESS); + CAMHAL_LOGDB("Brightness %d", mParameters3A.Brightness); + mPending3Asettings |= SetBrightness; + } + } + + str = params.get(CameraParameters::KEY_ANTIBANDING); + mode = getLUTvalue_HALtoOMX(str,FlickerLUT); + if ( mFirstTimeInit || ( ( str != NULL ) && ( mParameters3A.Flicker != mode ) )) + { + mParameters3A.Flicker = mode; + CAMHAL_LOGDB("Flicker %d", mParameters3A.Flicker); + if ( 0 <= mParameters3A.Flicker ) + { + mPending3Asettings |= SetFlicker; + } + } + + str = params.get(TICameraParameters::KEY_ISO); + mode = getLUTvalue_HALtoOMX(str, IsoLUT); + CAMHAL_LOGVB("ISO mode arrived in HAL : %s", str); + if ( mFirstTimeInit || ( ( str != NULL ) && ( mParameters3A.ISO != mode )) ) + { + mParameters3A.ISO = mode; + CAMHAL_LOGDB("ISO %d", mParameters3A.ISO); + if ( 0 <= mParameters3A.ISO ) + { + mPending3Asettings |= SetISO; + } + } + + str = params.get(CameraParameters::KEY_FOCUS_MODE); + mode = getLUTvalue_HALtoOMX(str, FocusLUT); + if ( mFirstTimeInit || ( ( str != NULL ) && ( mParameters3A.Focus != mode ) ) ) + { + //Apply focus mode immediatly only if CAF or Inifinity are selected + if ( ( mode == OMX_IMAGE_FocusControlAuto ) || + ( mode == OMX_IMAGE_FocusControlAutoInfinity ) ) + { + mPending3Asettings |= SetFocus; + mParameters3A.Focus = mode; + } + else if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) + { + //If we switch from CAF to something else, then disable CAF + mPending3Asettings |= SetFocus; + mParameters3A.Focus = OMX_IMAGE_FocusControlOff; + } + + mParameters3A.Focus = mode; + CAMHAL_LOGDB("Focus %x", mParameters3A.Focus); + } + + str = params.get(CameraParameters::KEY_EXPOSURE_COMPENSATION); + if ( mFirstTimeInit || + (( str != NULL ) && + (mParameters3A.EVCompensation != + params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION)))) + { + CAMHAL_LOGDB("Setting EV Compensation to %d", + params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION)); + + mParameters3A.EVCompensation = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + mPending3Asettings |= SetEVCompensation; + } + + str = params.get(CameraParameters::KEY_SCENE_MODE); + mode = getLUTvalue_HALtoOMX( str, SceneLUT); + if ( mFirstTimeInit || (( str != NULL ) && ( mParameters3A.SceneMode != mode )) ) + { + if ( 0 <= mode ) + { + mParameters3A.SceneMode = mode; + mPending3Asettings |= SetSceneMode; + } + else + { + mParameters3A.SceneMode = OMX_Manual; + } + + CAMHAL_LOGDB("SceneMode %d", mParameters3A.SceneMode); + } + + str = params.get(CameraParameters::KEY_FLASH_MODE); + mode = getLUTvalue_HALtoOMX( str, FlashLUT); + if ( mFirstTimeInit || (( str != NULL ) && ( mParameters3A.FlashMode != mode )) ) + { + if ( 0 <= mode ) + { + mParameters3A.FlashMode = mode; + mPending3Asettings |= SetFlash; + } + else + { + mParameters3A.FlashMode = OMX_Manual; + } + } + + CAMHAL_LOGVB("Flash Setting %s", str); + CAMHAL_LOGVB("FlashMode %d", mParameters3A.FlashMode); + + str = params.get(CameraParameters::KEY_EFFECT); + mode = getLUTvalue_HALtoOMX( str, EffLUT); + if ( mFirstTimeInit || (( str != NULL ) && ( mParameters3A.Effect != mode )) ) + { + mParameters3A.Effect = mode; + CAMHAL_LOGDB("Effect %d", mParameters3A.Effect); + if ( 0 <= mParameters3A.Effect ) + { + mPending3Asettings |= SetEffect; + } + } + + str = params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED); + if ( (str != NULL) && (!strcmp(str, "true")) ) + { + OMX_BOOL lock = OMX_FALSE; + str = params.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK); + if ( (strcmp(str, "true")) == 0) + { + CAMHAL_LOGVA("Locking Exposure"); + lock = OMX_TRUE; + } + else + { + CAMHAL_LOGVA("UnLocking Exposure"); + } + if (mParameters3A.ExposureLock != lock) + { + mParameters3A.ExposureLock = lock; + CAMHAL_LOGDB("ExposureLock %d", lock); + mPending3Asettings |= SetExpLock; + } + } + + str = params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED); + if ( (str != NULL) && (!strcmp(str, "true")) ) + { + OMX_BOOL lock = OMX_FALSE; + str = params.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK); + if ( (strcmp(str, "true")) == 0) + { + CAMHAL_LOGVA("Locking WhiteBalance"); + lock = OMX_TRUE; + } + else + { + CAMHAL_LOGVA("UnLocking WhiteBalance"); + } + if (mParameters3A.WhiteBalanceLock != lock) + { + mParameters3A.WhiteBalanceLock = lock; + CAMHAL_LOGDB("WhiteBalanceLock %d", lock); + mPending3Asettings |= SetWBLock; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +int OMXCameraAdapter::getLUTvalue_HALtoOMX(const char * HalValue, LUTtype LUT) +{ + int LUTsize = LUT.size; + if( HalValue ) + for(int i = 0; i < LUTsize; i++) + if( 0 == strcmp(LUT.Table[i].userDefinition, HalValue) ) + return LUT.Table[i].omxDefinition; + + return -ENOENT; +} + +const char* OMXCameraAdapter::getLUTvalue_OMXtoHAL(int OMXValue, LUTtype LUT) +{ + int LUTsize = LUT.size; + for(int i = 0; i < LUTsize; i++) + if( LUT.Table[i].omxDefinition == OMXValue ) + return LUT.Table[i].userDefinition; + + return NULL; +} + +status_t OMXCameraAdapter::setExposureMode(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSURECONTROLTYPE exp; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + if ( EXPOSURE_FACE_PRIORITY == Gen3A.Exposure ) + { + //Disable Region priority and enable Face priority + setAlgoPriority(REGION_PRIORITY, EXPOSURE_ALGO, false); + setAlgoPriority(FACE_PRIORITY, EXPOSURE_ALGO, true); + + //Then set the mode to auto + Gen3A.WhiteBallance = OMX_ExposureControlAuto; + } + else + { + //Disable Face and Region priority + setAlgoPriority(FACE_PRIORITY, EXPOSURE_ALGO, false); + setAlgoPriority(REGION_PRIORITY, EXPOSURE_ALGO, false); + } + + OMX_INIT_STRUCT_PTR (&exp, OMX_CONFIG_EXPOSURECONTROLTYPE); + exp.nPortIndex = OMX_ALL; + exp.eExposureControl = (OMX_EXPOSURECONTROLTYPE)Gen3A.Exposure; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposure, + &exp); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring exposure mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera exposure mode configured successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setFlashMode(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_PARAM_FLASHCONTROLTYPE flash; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&flash, OMX_IMAGE_PARAM_FLASHCONTROLTYPE); + flash.nPortIndex = OMX_ALL; + flash.eFlashControl = ( OMX_IMAGE_FLASHCONTROLTYPE ) Gen3A.FlashMode; + + CAMHAL_LOGDB("Configuring flash mode 0x%x", flash.eFlashControl); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigFlashControl, + &flash); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring flash mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera flash mode configured successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setFocusMode(Gen3A_settings& Gen3A) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focus; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + //First Disable Face and Region priority + ret |= setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); + ret |= setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&focus, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focus.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + focus.eFocusControl = (OMX_IMAGE_FOCUSCONTROLTYPE)Gen3A.Focus; + + CAMHAL_LOGDB("Configuring focus mode 0x%x", focus.eFocusControl); + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigFocusControl, &focus); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring focus mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera focus mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setScene(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SCENEMODETYPE scene; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&scene, OMX_CONFIG_SCENEMODETYPE); + scene.nPortIndex = OMX_ALL; + scene.eSceneMode = ( OMX_SCENEMODETYPE ) Gen3A.SceneMode; + + CAMHAL_LOGDB("Configuring scene mode 0x%x", scene.eSceneMode); + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSceneMode, + &scene); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring scene mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera scene configured successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setEVCompensation(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expValues; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&expValues, OMX_CONFIG_EXPOSUREVALUETYPE); + expValues.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + CAMHAL_LOGDB("old EV Compensation for OMX = 0x%x", (int)expValues.xEVCompensation); + CAMHAL_LOGDB("EV Compensation for HAL = %d", Gen3A.EVCompensation); + + expValues.xEVCompensation = ( Gen3A.EVCompensation * ( 1 << Q16_OFFSET ) ) / 10; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + CAMHAL_LOGDB("new EV Compensation for OMX = 0x%x", (int)expValues.xEVCompensation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring EV Compensation 0x%x error = 0x%x", + ( unsigned int ) expValues.xEVCompensation, + eError); + } + else + { + CAMHAL_LOGDB("EV Compensation 0x%x configured successfully", + ( unsigned int ) expValues.xEVCompensation); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setWBMode(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_WHITEBALCONTROLTYPE wb; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&wb, OMX_CONFIG_WHITEBALCONTROLTYPE); + wb.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + wb.eWhiteBalControl = ( OMX_WHITEBALCONTROLTYPE ) Gen3A.WhiteBallance; + + if ( WB_FACE_PRIORITY == Gen3A.WhiteBallance ) + { + //Disable Region priority and enable Face priority + setAlgoPriority(REGION_PRIORITY, WHITE_BALANCE_ALGO, false); + setAlgoPriority(FACE_PRIORITY, WHITE_BALANCE_ALGO, true); + + //Then set the mode to auto + Gen3A.WhiteBallance = OMX_WhiteBalControlAuto; + } + else + { + //Disable Face and Region priority + setAlgoPriority(FACE_PRIORITY, WHITE_BALANCE_ALGO, false); + setAlgoPriority(REGION_PRIORITY, WHITE_BALANCE_ALGO, false); + } + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonWhiteBalance, + &wb); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Whitebalance mode 0x%x error = 0x%x", + ( unsigned int ) wb.eWhiteBalControl, + eError); + } + else + { + CAMHAL_LOGDB("Whitebalance mode 0x%x configured successfully", + ( unsigned int ) wb.eWhiteBalControl); + } + + LOG_FUNCTION_NAME_EXIT; + + return eError; +} + +status_t OMXCameraAdapter::setFlicker(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_FLICKERCANCELTYPE flicker; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&flicker, OMX_CONFIG_FLICKERCANCELTYPE); + flicker.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + flicker.eFlickerCancel = (OMX_COMMONFLICKERCANCELTYPE)Gen3A.Flicker; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigFlickerCancel, + &flicker ); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Flicker mode 0x%x error = 0x%x", + ( unsigned int ) flicker.eFlickerCancel, + eError); + } + else + { + CAMHAL_LOGDB("Flicker mode 0x%x configured successfully", + ( unsigned int ) flicker.eFlickerCancel); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setBrightness(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BRIGHTNESSTYPE brightness; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&brightness, OMX_CONFIG_BRIGHTNESSTYPE); + brightness.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + brightness.nBrightness = Gen3A.Brightness; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonBrightness, + &brightness); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Brightness 0x%x error = 0x%x", + ( unsigned int ) brightness.nBrightness, + eError); + } + else + { + CAMHAL_LOGDB("Brightness 0x%x configured successfully", + ( unsigned int ) brightness.nBrightness); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setContrast(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CONTRASTTYPE contrast; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&contrast, OMX_CONFIG_CONTRASTTYPE); + contrast.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + contrast.nContrast = Gen3A.Contrast; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonContrast, + &contrast); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Contrast 0x%x error = 0x%x", + ( unsigned int ) contrast.nContrast, + eError); + } + else + { + CAMHAL_LOGDB("Contrast 0x%x configured successfully", + ( unsigned int ) contrast.nContrast); + } + + LOG_FUNCTION_NAME_EXIT; + + return eError; +} + +status_t OMXCameraAdapter::setSharpness(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE procSharpness; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&procSharpness, OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE); + procSharpness.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + procSharpness.nLevel = Gen3A.Sharpness; + + if( procSharpness.nLevel == 0 ) + { + procSharpness.bAuto = OMX_TRUE; + } + else + { + procSharpness.bAuto = OMX_FALSE; + } + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigSharpeningLevel, + &procSharpness); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Sharpness 0x%x error = 0x%x", + ( unsigned int ) procSharpness.nLevel, + eError); + } + else + { + CAMHAL_LOGDB("Sharpness 0x%x configured successfully", + ( unsigned int ) procSharpness.nLevel); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setSaturation(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SATURATIONTYPE saturation; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&saturation, OMX_CONFIG_SATURATIONTYPE); + saturation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + saturation.nSaturation = Gen3A.Saturation; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonSaturation, + &saturation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Saturation 0x%x error = 0x%x", + ( unsigned int ) saturation.nSaturation, + eError); + } + else + { + CAMHAL_LOGDB("Saturation 0x%x configured successfully", + ( unsigned int ) saturation.nSaturation); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setISO(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXPOSUREVALUETYPE expValues; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&expValues, OMX_CONFIG_EXPOSUREVALUETYPE); + expValues.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + + if( 0 == Gen3A.ISO ) + { + expValues.bAutoSensitivity = OMX_TRUE; + } + else + { + expValues.bAutoSensitivity = OMX_FALSE; + expValues.nSensitivity = Gen3A.ISO; + } + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &expValues); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring ISO 0x%x error = 0x%x", + ( unsigned int ) expValues.nSensitivity, + eError); + } + else + { + CAMHAL_LOGDB("ISO 0x%x configured successfully", + ( unsigned int ) expValues.nSensitivity); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setEffect(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_IMAGEFILTERTYPE effect; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&effect, OMX_CONFIG_IMAGEFILTERTYPE); + effect.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + effect.eImageFilter = (OMX_IMAGEFILTERTYPE ) Gen3A.Effect; + + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonImageFilter, + &effect); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Effect 0x%x error = 0x%x", + ( unsigned int ) effect.eImageFilter, + eError); + } + else + { + CAMHAL_LOGDB("Effect 0x%x configured successfully", + ( unsigned int ) effect.eImageFilter); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setWhiteBalanceLock(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + lock.bLock = Gen3A.WhiteBalanceLock; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageWhiteBalanceLock, + &lock); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring WhiteBalance Lock error = 0x%x", eError); + } + else + { + CAMHAL_LOGDB("WhiteBalance Lock configured successfully %d ", lock.bLock); + } + LOG_FUNCTION_NAME_EXIT + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::setExposureLock(Gen3A_settings& Gen3A) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + lock.bLock = Gen3A.ExposureLock; + eError = OMX_SetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageExposureLock, + &lock); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring Exposure Lock error = 0x%x", eError); + } + else + { + CAMHAL_LOGDB("Exposure Lock configured successfully %d ", lock.bLock); + } + LOG_FUNCTION_NAME_EXIT + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::release3ALock() +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_LOCKTYPE lock; + + LOG_FUNCTION_NAME + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + return NO_INIT; + } + + OMX_INIT_STRUCT_PTR (&lock, OMX_IMAGE_CONFIG_LOCKTYPE); + lock.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + mParameters3A.ExposureLock = OMX_FALSE; + mParameters3A.WhiteBalanceLock = OMX_FALSE; + + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageExposureLock, + &lock); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error GetConfig Exposure Lock error = 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Exposure Lock GetConfig successfull"); + } + + /*if locked then unlock */ + if ( lock.bLock ) + { + setExposureLock(mParameters3A); + } + + eError = OMX_GetConfig( mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexConfigImageWhiteBalanceLock, + &lock); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error GetConfig WhiteBalance Lock error = 0x%x", eError); + } + else + { + CAMHAL_LOGDA("WhiteBalance Lock GetConfig successfull"); + } + + /*if locked then unlock */ + if ( lock.bLock ) + { + setWhiteBalanceLock(mParameters3A); + } + + return ErrorUtils::omxToAndroidError(eError); + +} + +status_t OMXCameraAdapter::apply3Asettings( Gen3A_settings& Gen3A ) +{ + status_t ret = NO_ERROR; + unsigned int currSett; // 32 bit + int portIndex; + + /* + * Scenes have a priority during the process + * of applying 3A related parameters. + * They can override pretty much all other 3A + * settings and similarly get overridden when + * for instance the focus mode gets switched. + * There is only one exception to this rule, + * the manual a.k.a. auto scene. + */ + if ( ( SetSceneMode & mPending3Asettings ) ) + { + mPending3Asettings &= ~SetSceneMode; + return setScene(Gen3A); + } + else if ( OMX_Manual != Gen3A.SceneMode ) + { + mPending3Asettings = 0; + return NO_ERROR; + } + + for( currSett = 1; currSett < E3aSettingMax; currSett <<= 1) + { + if( currSett & mPending3Asettings ) + { + switch( currSett ) + { + case SetEVCompensation: + { + ret |= setEVCompensation(Gen3A); + break; + } + + case SetWhiteBallance: + { + ret |= setWBMode(Gen3A); + break; + } + + case SetFlicker: + { + ret |= setFlicker(Gen3A); + break; + } + + case SetBrightness: + { + ret |= setBrightness(Gen3A); + break; + } + + case SetContrast: + { + ret |= setContrast(Gen3A); + break; + } + + case SetSharpness: + { + ret |= setSharpness(Gen3A); + break; + } + + case SetSaturation: + { + ret |= setSaturation(Gen3A); + break; + } + + case SetISO: + { + ret |= setISO(Gen3A); + break; + } + + case SetEffect: + { + ret |= setEffect(Gen3A); + break; + } + + case SetFocus: + { + ret |= setFocusMode(Gen3A); + break; + } + + case SetExpMode: + { + ret |= setExposureMode(Gen3A); + break; + } + + case SetFlash: + { + ret |= setFlashMode(Gen3A); + break; + } + + case SetExpLock: + { + ret |= setExposureLock(Gen3A); + break; + } + + case SetWBLock: + { + ret |= setWhiteBalanceLock(Gen3A); + break; + } + + default: + CAMHAL_LOGEB("this setting (0x%x) is still not supported in CameraAdapter ", + currSett); + break; + } + mPending3Asettings &= ~currSett; + } + } + return ret; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXAlgo.cpp b/camera/OMXCameraAdapter/OMXAlgo.cpp new file mode 100644 index 0000000..ef9414e --- /dev/null +++ b/camera/OMXCameraAdapter/OMXAlgo.cpp @@ -0,0 +1,1181 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXAlgo.cpp +* +* This file contains functionality for handling algorithm configurations. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace android { + +status_t OMXCameraAdapter::setParametersAlgo(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *valstr = NULL; + const char *oldstr = NULL; + + LOG_FUNCTION_NAME; + + CaptureMode capMode; + CAMHAL_LOGEB("Capture mode %s", params.get(TICameraParameters::KEY_CAP_MODE)); + if ( (valstr = params.get(TICameraParameters::KEY_CAP_MODE)) != NULL ) + { + if (strcmp(valstr, (const char *) TICameraParameters::HIGH_PERFORMANCE_MODE) == 0) + { + capMode = OMXCameraAdapter::HIGH_SPEED; + } + else if (strcmp(valstr, (const char *) TICameraParameters::HIGH_QUALITY_MODE) == 0) + { + capMode = OMXCameraAdapter::HIGH_QUALITY; + } + else if (strcmp(valstr, (const char *) TICameraParameters::HIGH_QUALITY_ZSL_MODE) == 0) + { + capMode = OMXCameraAdapter::HIGH_QUALITY_ZSL; + } + else if (strcmp(valstr, (const char *) TICameraParameters::VIDEO_MODE) == 0) + { + capMode = OMXCameraAdapter::VIDEO_MODE; + } + else + { + capMode = OMXCameraAdapter::HIGH_QUALITY; + } + } + else + { + capMode = OMXCameraAdapter::HIGH_QUALITY_ZSL; + + } + + if ( mCapMode != capMode ) + { + mCapMode = capMode; + mOMXStateSwitch = true; + } + + CAMHAL_LOGDB("Capture Mode set %d", mCapMode); + + /// Configure IPP, LDCNSF, GBCE and GLBCE only in HQ mode + IPPMode ipp; + if((mCapMode == OMXCameraAdapter::HIGH_QUALITY) || (mCapMode == OMXCameraAdapter::HIGH_QUALITY_ZSL)) + { + if ( (valstr = params.get(TICameraParameters::KEY_IPP)) != NULL ) + { + if (strcmp(valstr, (const char *) TICameraParameters::IPP_LDCNSF) == 0) + { + ipp = OMXCameraAdapter::IPP_LDCNSF; + } + else if (strcmp(valstr, (const char *) TICameraParameters::IPP_LDC) == 0) + { + ipp = OMXCameraAdapter::IPP_LDC; + } + else if (strcmp(valstr, (const char *) TICameraParameters::IPP_NSF) == 0) + { + ipp = OMXCameraAdapter::IPP_NSF; + } + else if (strcmp(valstr, (const char *) TICameraParameters::IPP_NONE) == 0) + { + ipp = OMXCameraAdapter::IPP_NONE; + } + else + { + ipp = OMXCameraAdapter::IPP_NONE; + } + } + else + { + ipp = OMXCameraAdapter::IPP_NONE; + } + + CAMHAL_LOGVB("IPP Mode set %d", ipp); + + if (((valstr = params.get(TICameraParameters::KEY_GBCE)) != NULL) ) + { + // Configure GBCE only if the setting has changed since last time + oldstr = mParams.get(TICameraParameters::KEY_GBCE); + bool cmpRes = true; + if ( NULL != oldstr ) + { + cmpRes = strcmp(valstr, oldstr) != 0; + } + else + { + cmpRes = true; + } + + + if( cmpRes ) + { + if (strcmp(valstr, ( const char * ) TICameraParameters::GBCE_ENABLE ) == 0) + { + setGBCE(OMXCameraAdapter::BRIGHTNESS_ON); + } + else if (strcmp(valstr, ( const char * ) TICameraParameters::GBCE_DISABLE ) == 0) + { + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + else + { + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + } + } + else + { + //Disable GBCE by default + setGBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + + if ( ( valstr = params.get(TICameraParameters::KEY_GLBCE) ) != NULL ) + { + // Configure GLBCE only if the setting has changed since last time + + oldstr = mParams.get(TICameraParameters::KEY_GLBCE); + bool cmpRes = true; + if ( NULL != oldstr ) + { + cmpRes = strcmp(valstr, oldstr) != 0; + } + else + { + cmpRes = true; + } + + + if( cmpRes ) + { + if (strcmp(valstr, ( const char * ) TICameraParameters::GLBCE_ENABLE ) == 0) + { + setGLBCE(OMXCameraAdapter::BRIGHTNESS_ON); + } + else if (strcmp(valstr, ( const char * ) TICameraParameters::GLBCE_DISABLE ) == 0) + { + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + else + { + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + } + } + else + { + //Disable GLBCE by default + setGLBCE(OMXCameraAdapter::BRIGHTNESS_OFF); + } + } + else + { + ipp = OMXCameraAdapter::IPP_NONE; + } + + if ( mIPP != ipp ) + { + mIPP = ipp; + mOMXStateSwitch = true; + } + + ///Set VNF Configuration + bool vnfEnabled = false; + if ( params.getInt(TICameraParameters::KEY_VNF) > 0 ) + { + CAMHAL_LOGDA("VNF Enabled"); + vnfEnabled = true; + } + else + { + CAMHAL_LOGDA("VNF Disabled"); + vnfEnabled = false; + } + + if ( mVnfEnabled != vnfEnabled ) + { + mVnfEnabled = vnfEnabled; + mOMXStateSwitch = true; + } + + ///Set VSTAB Configuration + bool vstabEnabled = false; + if ( params.getInt(TICameraParameters::KEY_VSTAB) > 0 ) + { + CAMHAL_LOGDA("VSTAB Enabled"); + vstabEnabled = true; + } + else + { + CAMHAL_LOGDA("VSTAB Disabled"); + vstabEnabled = false; + } + + if ( mVstabEnabled != vstabEnabled ) + { + mVstabEnabled = vstabEnabled; + mOMXStateSwitch = true; + } + + //A work-around for a failing call to OMX flush buffers + if ( ( capMode = OMXCameraAdapter::VIDEO_MODE ) && + ( mVstabEnabled ) ) + { + mOMXStateSwitch = true; + } + + //Set Auto Convergence Mode + valstr = params.get((const char *) TICameraParameters::KEY_AUTOCONVERGENCE); + if ( valstr != NULL ) + { + // Set ManualConvergence default value + OMX_S32 manualconvergence = -30; + if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_DISABLE) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeDisable, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_FRAME) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeFrame, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_CENTER) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeCenter, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_FFT) == 0 ) + { + setAutoConvergence(OMX_TI_AutoConvergenceModeFocusFaceTouch, manualconvergence); + } + else if ( strcmp (valstr, (const char *) TICameraParameters::AUTOCONVERGENCE_MODE_MANUAL) == 0 ) + { + manualconvergence = (OMX_S32)params.getInt(TICameraParameters::KEY_MANUALCONVERGENCE_VALUES); + setAutoConvergence(OMX_TI_AutoConvergenceModeManual, manualconvergence); + } + CAMHAL_LOGVB("AutoConvergenceMode %s, value = %d", valstr, (int) manualconvergence); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// Get AutoConvergence +status_t OMXCameraAdapter::getAutoConvergence(OMX_TI_AUTOCONVERGENCEMODETYPE *pACMode, + OMX_S32 *pManualConverence) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_CONVERGENCETYPE ACParams; + + ACParams.nSize = sizeof(OMX_TI_CONFIG_CONVERGENCETYPE); + ACParams.nVersion = mLocalVersionParam; + ACParams.nPortIndex = OMX_ALL; + + LOG_FUNCTION_NAME; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutoConvergence, + &ACParams); + if ( eError != OMX_ErrorNone ) + { + CAMHAL_LOGEB("Error while getting AutoConvergence 0x%x", eError); + ret = -EINVAL; + } + else + { + *pManualConverence = ACParams.nManualConverence; + *pACMode = ACParams.eACMode; + CAMHAL_LOGDA("AutoConvergence got successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +// Set AutoConvergence +status_t OMXCameraAdapter::setAutoConvergence(OMX_TI_AUTOCONVERGENCEMODETYPE pACMode, + OMX_S32 pManualConverence) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_CONVERGENCETYPE ACParams; + + LOG_FUNCTION_NAME; + + ACParams.nSize = sizeof(OMX_TI_CONFIG_CONVERGENCETYPE); + ACParams.nVersion = mLocalVersionParam; + ACParams.nPortIndex = OMX_ALL; + ACParams.nManualConverence = pManualConverence; + ACParams.eACMode = pACMode; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigAutoConvergence, + &ACParams); + if ( eError != OMX_ErrorNone ) + { + CAMHAL_LOGEB("Error while setting AutoConvergence 0x%x", eError); + ret = -EINVAL; + } + else + { + CAMHAL_LOGDA("AutoConvergence applied successfully"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::enableVideoNoiseFilter(bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_VIDEONOISEFILTERTYPE vnfCfg; + + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&vnfCfg, OMX_PARAM_VIDEONOISEFILTERTYPE); + + if ( enable ) + { + CAMHAL_LOGDA("VNF is enabled"); + vnfCfg.eMode = OMX_VideoNoiseFilterModeOn; + } + else + { + CAMHAL_LOGDA("VNF is disabled"); + vnfCfg.eMode = OMX_VideoNoiseFilterModeOff; + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamVideoNoiseFilter, + &vnfCfg); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring video noise filter 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Video noise filter is configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::enableVideoStabilization(bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_FRAMESTABTYPE frameStabCfg; + + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + OMX_CONFIG_BOOLEANTYPE vstabp; + OMX_INIT_STRUCT_PTR (&vstabp, OMX_CONFIG_BOOLEANTYPE); + if(enable) + { + vstabp.bEnabled = OMX_TRUE; + } + else + { + vstabp.bEnabled = OMX_FALSE; + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexParamFrameStabilisation, + &vstabp); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring video stabilization param 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Video stabilization param configured successfully"); + } + + } + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&frameStabCfg, OMX_CONFIG_FRAMESTABTYPE); + + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigCommonFrameStabilisation, + &frameStabCfg); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while getting video stabilization mode 0x%x", + (unsigned int)eError); + ret = -1; + } + + CAMHAL_LOGDB("VSTAB Port Index = %d", (int)frameStabCfg.nPortIndex); + + frameStabCfg.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + if ( enable ) + { + CAMHAL_LOGDA("VSTAB is enabled"); + frameStabCfg.bStab = OMX_TRUE; + } + else + { + CAMHAL_LOGDA("VSTAB is disabled"); + frameStabCfg.bStab = OMX_FALSE; + + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigCommonFrameStabilisation, + &frameStabCfg); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring video stabilization mode 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Video stabilization mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setGBCE(OMXCameraAdapter::BrightnessMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE bControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bControl, OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE); + + bControl.nPortIndex = OMX_ALL; + + switch ( mode ) + { + case OMXCameraAdapter::BRIGHTNESS_ON: + { + bControl.eControl = OMX_TI_BceModeOn; + break; + } + case OMXCameraAdapter::BRIGHTNESS_AUTO: + { + bControl.eControl = OMX_TI_BceModeAuto; + break; + } + case OMXCameraAdapter::BRIGHTNESS_OFF: + default: + { + bControl.eControl = OMX_TI_BceModeOff; + break; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigGlobalBrightnessContrastEnhance, + &bControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting GBCE 0x%x", eError); + } + else + { + CAMHAL_LOGDB("GBCE configured successfully 0x%x", mode); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setGLBCE(OMXCameraAdapter::BrightnessMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE bControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bControl, OMX_TI_CONFIG_LOCAL_AND_GLOBAL_BRIGHTNESSCONTRASTTYPE); + bControl.nPortIndex = OMX_ALL; + + switch ( mode ) + { + case OMXCameraAdapter::BRIGHTNESS_ON: + { + bControl.eControl = OMX_TI_BceModeOn; + break; + } + case OMXCameraAdapter::BRIGHTNESS_AUTO: + { + bControl.eControl = OMX_TI_BceModeAuto; + break; + } + case OMXCameraAdapter::BRIGHTNESS_OFF: + default: + { + bControl.eControl = OMX_TI_BceModeOff; + break; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigLocalBrightnessContrastEnhance, + &bControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configure GLBCE 0x%x", eError); + } + else + { + CAMHAL_LOGDA("GLBCE configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setCaptureMode(OMXCameraAdapter::CaptureMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CAMOPERATINGMODETYPE camMode; + OMX_CONFIG_BOOLEANTYPE bCAC; + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR (&bCAC, OMX_CONFIG_BOOLEANTYPE); + bCAC.bEnabled = OMX_FALSE; + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&camMode, OMX_CONFIG_CAMOPERATINGMODETYPE); + if ( mSensorIndex == OMX_TI_StereoSensor ) + { + CAMHAL_LOGDA("Camera mode: STEREO"); + camMode.eCamOperatingMode = OMX_CaptureStereoImageCapture; + } + else if ( OMXCameraAdapter::HIGH_SPEED == mode ) + { + CAMHAL_LOGDA("Camera mode: HIGH SPEED"); + camMode.eCamOperatingMode = OMX_CaptureImageHighSpeedTemporalBracketing; + } + else if( OMXCameraAdapter::HIGH_QUALITY == mode ) + { + CAMHAL_LOGDA("Camera mode: HIGH QUALITY"); + camMode.eCamOperatingMode = OMX_CaptureImageProfileBase; + bCAC.bEnabled = OMX_TRUE; + } + else if( OMXCameraAdapter::HIGH_QUALITY_ZSL== mode ) + { + CAMHAL_LOGDA("Camera mode: HIGH QUALITY_ZSL"); + camMode.eCamOperatingMode = OMX_TI_CaptureImageProfileZeroShutterLag; + bCAC.bEnabled = OMX_TRUE; + } + else if( OMXCameraAdapter::VIDEO_MODE == mode ) + { + CAMHAL_LOGDA("Camera mode: VIDEO MODE"); + camMode.eCamOperatingMode = OMX_CaptureVideo; + } + else + { + CAMHAL_LOGEA("Camera mode: INVALID mode passed!"); + return BAD_VALUE; + } + + if(ret != -1) + { + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexCameraOperatingMode, + &camMode); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring camera mode 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Camera mode configured successfully"); + } + } + + if(ret != -1) + { + //Configure CAC + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigChromaticAberrationCorrection, + &bCAC); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring CAC 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("CAC configured successfully"); + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setLDC(OMXCameraAdapter::IPPMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in loaded state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + + switch ( mode ) + { + case OMXCameraAdapter::IPP_LDCNSF: + case OMXCameraAdapter::IPP_LDC: + { + bOMX.bEnabled = OMX_TRUE; + break; + } + case OMXCameraAdapter::IPP_NONE: + case OMXCameraAdapter::IPP_NSF: + default: + { + bOMX.bEnabled = OMX_FALSE; + break; + } + } + + CAMHAL_LOGVB("Configuring LDC mode 0x%x", bOMX.bEnabled); + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamLensDistortionCorrection, + &bOMX); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEA("Error while setting LDC"); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setNSF(OMXCameraAdapter::IPPMode mode) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_ISONOISEFILTERTYPE nsf; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in loaded state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&nsf, OMX_PARAM_ISONOISEFILTERTYPE); + nsf.nPortIndex = OMX_ALL; + + switch ( mode ) + { + case OMXCameraAdapter::IPP_LDCNSF: + case OMXCameraAdapter::IPP_NSF: + { + nsf.eMode = OMX_ISONoiseFilterModeOn; + break; + } + case OMXCameraAdapter::IPP_LDC: + case OMXCameraAdapter::IPP_NONE: + default: + { + nsf.eMode = OMX_ISONoiseFilterModeOff; + break; + } + } + + CAMHAL_LOGVB("Configuring NSF mode 0x%x", nsf.eMode); + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_IndexParamHighISONoiseFiler, + &nsf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEA("Error while setting NSF"); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setImageQuality(unsigned int quality) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_PARAM_QFACTORTYPE jpegQualityConf; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(jpegQualityConf, OMX_IMAGE_PARAM_QFACTORTYPE); + jpegQualityConf.nQFactor = quality; + jpegQualityConf.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamQFactor, + &jpegQualityConf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring jpeg Quality 0x%x", eError); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setThumbnailParams(unsigned int width, + unsigned int height, + unsigned int quality) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_THUMBNAILTYPE thumbConf; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(thumbConf, OMX_PARAM_THUMBNAILTYPE); + thumbConf.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamThumbnail, + &thumbConf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while retrieving thumbnail size 0x%x", eError); + ret = -1; + } + + //CTS Requirement: width or height equal to zero should + //result in absent EXIF thumbnail + if ( ( 0 == width ) || ( 0 == height ) ) + { + thumbConf.nWidth = mThumbRes[0].width; + thumbConf.nHeight = mThumbRes[0].height; + thumbConf.eCompressionFormat = OMX_IMAGE_CodingUnused; + } + else + { + thumbConf.nWidth = width; + thumbConf.nHeight = height; + thumbConf.nQuality = quality; + thumbConf.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + + CAMHAL_LOGDB("Thumbnail width = %d, Thumbnail Height = %d", width, height); + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexParamThumbnail, + &thumbConf); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring thumbnail size 0x%x", eError); + ret = -1; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setAlgoPriority(AlgoPriority priority, + Algorithm3A algo, + bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_3A_REGION_PRIORITY regionPriority; + OMX_TI_CONFIG_3A_FACE_PRIORITY facePriority; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + + if ( FACE_PRIORITY == priority ) + { + OMX_INIT_STRUCT_PTR (&facePriority, OMX_TI_CONFIG_3A_FACE_PRIORITY); + facePriority.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + if ( algo & WHITE_BALANCE_ALGO ) + { + if ( enable ) + { + facePriority.bAwbFaceEnable = OMX_TRUE; + } + else + { + facePriority.bAwbFaceEnable = OMX_FALSE; + } + } + + if ( algo & EXPOSURE_ALGO ) + { + if ( enable ) + { + facePriority.bAeFaceEnable = OMX_TRUE; + } + else + { + facePriority.bAeFaceEnable = OMX_FALSE; + } + } + + if ( algo & FOCUS_ALGO ) + { + if ( enable ) + { + facePriority.bAfFaceEnable= OMX_TRUE; + } + else + { + facePriority.bAfFaceEnable = OMX_FALSE; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFacePriority3a, + &facePriority); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring face priority 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Face priority for algorithms set successfully"); + } + + } + else if ( REGION_PRIORITY == priority ) + { + + OMX_INIT_STRUCT_PTR (®ionPriority, OMX_TI_CONFIG_3A_REGION_PRIORITY); + regionPriority.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + if ( algo & WHITE_BALANCE_ALGO ) + { + if ( enable ) + { + regionPriority.bAwbRegionEnable= OMX_TRUE; + } + else + { + regionPriority.bAwbRegionEnable = OMX_FALSE; + } + } + + if ( algo & EXPOSURE_ALGO ) + { + if ( enable ) + { + regionPriority.bAeRegionEnable = OMX_TRUE; + } + else + { + regionPriority.bAeRegionEnable = OMX_FALSE; + } + } + + if ( algo & FOCUS_ALGO ) + { + if ( enable ) + { + regionPriority.bAfRegionEnable = OMX_TRUE; + } + else + { + regionPriority.bAfRegionEnable = OMX_FALSE; + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigRegionPriority3a, + ®ionPriority); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring region priority 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Region priority for algorithms set successfully"); + } + + } + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setPictureRotation(unsigned int degree) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_ROTATIONTYPE rotation; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(rotation, OMX_CONFIG_ROTATIONTYPE); + rotation.nRotation = degree; + rotation.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &rotation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring rotation 0x%x", eError); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setSensorOrientation(unsigned int degree) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_ROTATIONTYPE sensorOrientation; + int tmpHeight, tmpWidth; + OMXCameraPortParameters *mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + LOG_FUNCTION_NAME; + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + /* Set Temproary Port resolution. + * For resolution with height > 1008,resolution cannot be set without configuring orientation. + * So we first set a temp resolution. We have used VGA + */ + tmpHeight = mPreviewData->mHeight; + tmpWidth = mPreviewData->mWidth; + mPreviewData->mWidth = 640; + mPreviewData->mHeight = 480; + ret = setFormat(OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, *mPreviewData); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEB("setFormat() failed %d", ret); + } + + /* Now set Required Orientation*/ + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT(sensorOrientation, OMX_CONFIG_ROTATIONTYPE); + sensorOrientation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &sensorOrientation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while Reading Sensor Orientation : 0x%x", eError); + } + CAMHAL_LOGVB(" Currently Sensor Orientation is set to : %d", + ( unsigned int ) sensorOrientation.nRotation); + sensorOrientation.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + sensorOrientation.nRotation = degree; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &sensorOrientation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring rotation 0x%x", eError); + } + CAMHAL_LOGVA(" Read the Parameters that are set"); + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonRotate, + &sensorOrientation); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while Reading Sensor Orientation : 0x%x", eError); + } + CAMHAL_LOGVB(" Currently Sensor Orientation is set to : %d", + ( unsigned int ) sensorOrientation.nRotation); + CAMHAL_LOGVB(" Sensor Configured for Port : %d", + ( unsigned int ) sensorOrientation.nPortIndex); + } + + /* Now set the required resolution as requested */ + + mPreviewData->mWidth = tmpWidth; + mPreviewData->mHeight = tmpHeight; + if ( NO_ERROR == ret ) + { + ret = setFormat (mCameraAdapterParameters.mPrevPortIndex, + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setFormat() failed %d", ret); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setVFramerate(OMX_U32 minFrameRate, OMX_U32 maxFrameRate) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_VARFRMRANGETYPE vfr; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&vfr, OMX_TI_CONFIG_VARFRMRANGETYPE); + + vfr.xMin = minFrameRate<<16; + vfr.xMax = maxFrameRate<<16; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexConfigVarFrmRange, + &vfr); + if(OMX_ErrorNone != eError) + { + CAMHAL_LOGEB("Error while setting VFR min = %d, max = %d, error = 0x%x", + ( unsigned int ) minFrameRate, + ( unsigned int ) maxFrameRate, + eError); + ret = -1; + } + else + { + CAMHAL_LOGDB("VFR Configured Successfully [%d:%d]", + ( unsigned int ) minFrameRate, + ( unsigned int ) maxFrameRate); + } + } + + return ret; + } + +}; diff --git a/camera/OMXCameraAdapter/OMXCameraAdapter.cpp b/camera/OMXCameraAdapter/OMXCameraAdapter.cpp new file mode 100644 index 0000000..899e3dc --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCameraAdapter.cpp @@ -0,0 +1,3160 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXCameraAdapter.cpp +* +* This file maps the Camera Hardware Interface to OMX. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" +#include "TICameraParameters.h" +#include <signal.h> +#include <math.h> + +#include <cutils/properties.h> +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +static int mDebugFps = 0; + +#define HERE(Msg) {CAMHAL_LOGEB("--===line %d, %s===--\n", __LINE__, Msg);} + +namespace android { + +#undef LOG_TAG +///Maintain a separate tag for OMXCameraAdapter logs to isolate issues OMX specific +#define LOG_TAG "CameraHAL" + +//frames skipped before recalculating the framerate +#define FPS_PERIOD 30 + +static OMXCameraAdapter *gCameraAdapter = NULL; +Mutex gAdapterLock; + +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +status_t OMXCameraAdapter::initialize(CameraProperties::Properties* caps, int sensor_index) +{ + LOG_FUNCTION_NAME; + + char value[PROPERTY_VALUE_MAX]; + property_get("debug.camera.showfps", value, "0"); + mDebugFps = atoi(value); + + TIMM_OSAL_ERRORTYPE osalError = OMX_ErrorNone; + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + + + mLocalVersionParam.s.nVersionMajor = 0x1; + mLocalVersionParam.s.nVersionMinor = 0x1; + mLocalVersionParam.s.nRevision = 0x0 ; + mLocalVersionParam.s.nStep = 0x0; + + mPending3Asettings = 0;//E3AsettingsAll; + + if ( 0 != mInitSem.Count() ) + { + CAMHAL_LOGEB("Error mInitSem semaphore count %d", mInitSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if (mComponentState != OMX_StateLoaded && mComponentState != OMX_StateInvalid) { + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if ( mComponentState != OMX_StateExecuting ){ + ///Update the preview and image capture port indexes + mCameraAdapterParameters.mPrevPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW; + // temp changed in order to build OMX_CAMERA_PORT_VIDEO_OUT_IMAGE; + mCameraAdapterParameters.mImagePortIndex = OMX_CAMERA_PORT_IMAGE_OUT_IMAGE; + mCameraAdapterParameters.mMeasurementPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT; + //currently not supported use preview port instead + mCameraAdapterParameters.mVideoPortIndex = OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW; + + if(!mCameraAdapterParameters.mHandleComp) + { + ///Initialize the OMX Core + eError = OMX_Init(); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_Init -0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + ///Setup key parameters to send to Ducati during init + OMX_CALLBACKTYPE oCallbacks; + + /* Initialize the callback handles */ + oCallbacks.EventHandler = android::OMXCameraAdapterEventHandler; + oCallbacks.EmptyBufferDone = android::OMXCameraAdapterEmptyBufferDone; + oCallbacks.FillBufferDone = android::OMXCameraAdapterFillBufferDone; + + ///Get the handle to the OMX Component + mCameraAdapterParameters.mHandleComp = NULL; + eError = OMX_GetHandle(&(mCameraAdapterParameters.mHandleComp), // previously used: OMX_GetHandle + (OMX_STRING)"OMX.TI.DUCATI1.VIDEO.CAMERA" ///@todo Use constant instead of hardcoded name + , this + , &oCallbacks); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_GetHandle -0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + OMX_ALL, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortDisable) -0x%x", eError); + } + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + ///Register for port enable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + mInitSem); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Enable PREVIEW Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + } + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + //Wait for the port enable event to occur + ret = mInitSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("-Port enable event arrived"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + CAMHAL_LOGEA("Timeout for enabling preview port expired!"); + goto EXIT; + } + + } + else + { + OMXCameraPortParameters * mPreviewData = + &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + //Apply default configs before trying to swtich to a new sensor + if ( NO_ERROR != setFormat(OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, *mPreviewData) ) + { + CAMHAL_LOGEB("Error 0x%x while applying defaults", ret); + goto EXIT; + } + } + } + ///Select the sensor + OMX_CONFIG_SENSORSELECTTYPE sensorSelect; + OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE); + sensorSelect.eSensor = (OMX_SENSORSELECT)sensor_index; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSensorSelect, &sensorSelect); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while selecting the sensor index as %d - 0x%x", sensor_index, eError); + return BAD_VALUE; + } + else + { + CAMHAL_LOGDB("Sensor %d selected successfully", sensor_index); + } + + printComponentVersion(mCameraAdapterParameters.mHandleComp); + + mSensorIndex = sensor_index; + mBracketingEnabled = false; + mBracketingBuffersQueuedCount = 0; + mBracketingRange = 1; + mLastBracetingBufferIdx = 0; + mOMXStateSwitch = false; + + if ( mComponentState != OMX_StateExecuting ){ + mCaptureSignalled = false; + mCaptureConfigured = false; + mRecording = false; + mWaitingForSnapshot = false; + mSnapshotCount = 0; + mComponentState = OMX_StateLoaded; + + mCapMode = HIGH_QUALITY; + mBurstFrames = 1; + mCapturedFrames = 0; + mPictureQuality = 100; + mCurrentZoomIdx = 0; + mTargetZoomIdx = 0; + mReturnZoomStatus = false; + mZoomInc = 1; + mZoomParameterIdx = 0; + mExposureBracketingValidEntries = 0; + mSensorOverclock = false; + + mDeviceOrientation = 0; + mCapabilities = caps; + + mEXIFData.mGPSData.mAltitudeValid = false; + mEXIFData.mGPSData.mDatestampValid = false; + mEXIFData.mGPSData.mLatValid = false; + mEXIFData.mGPSData.mLongValid = false; + mEXIFData.mGPSData.mMapDatumValid = false; + mEXIFData.mGPSData.mProcMethodValid = false; + mEXIFData.mGPSData.mVersionIdValid = false; + mEXIFData.mGPSData.mTimeStampValid = false; + mEXIFData.mModelValid = false; + mEXIFData.mMakeValid = false; + + // initialize command handling thread + if(mCommandHandler.get() == NULL) + mCommandHandler = new CommandHandler(this); + + if ( NULL == mCommandHandler.get() ) + { + CAMHAL_LOGEA("Couldn't create command handler"); + return NO_MEMORY; + } + + ret = mCommandHandler->run("CallbackThread", PRIORITY_URGENT_DISPLAY); + if ( ret != NO_ERROR ) + { + if( ret == INVALID_OPERATION){ + CAMHAL_LOGDA("command handler thread already runnning!!"); + }else + { + CAMHAL_LOGEA("Couldn't run command handlerthread"); + return ret; + } + } + + // initialize omx callback handling thread + if(mOMXCallbackHandler.get() == NULL) + mOMXCallbackHandler = new OMXCallbackHandler(this); + + if ( NULL == mOMXCallbackHandler.get() ) + { + CAMHAL_LOGEA("Couldn't create omx callback handler"); + return NO_MEMORY; + } + + ret = mOMXCallbackHandler->run("OMXCallbackThread", PRIORITY_URGENT_DISPLAY); + if ( ret != NO_ERROR ) + { + if( ret == INVALID_OPERATION){ + CAMHAL_LOGDA("omx callback handler thread already runnning!!"); + }else + { + CAMHAL_LOGEA("Couldn't run omx callback handler thread"); + return ret; + } + } + + //Remove any unhandled events + if ( !mEventSignalQ.isEmpty() ) + { + for (unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ ) + { + TIUTILS::Message *msg = mEventSignalQ.itemAt(i); + //remove from queue and free msg + mEventSignalQ.removeAt(i); + if ( NULL != msg ) + { + free(msg); + } + } + } + + //Setting this flag will that the first setParameter call will apply all 3A settings + //and will not conditionally apply based on current values. + mFirstTimeInit = true; + + memset(mExposureBracketingValues, 0, EXP_BRACKET_RANGE*sizeof(int)); + mMeasurementEnabled = false; + mFaceDetectionRunning = false; + + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex], 0, sizeof(OMXCameraPortParameters)); + memset(&mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex], 0, sizeof(OMXCameraPortParameters)); + } + LOG_FUNCTION_NAME_EXIT; + return ErrorUtils::omxToAndroidError(eError); + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + + if(mCameraAdapterParameters.mHandleComp) + { + ///Free the OMX component handle in case of error + OMX_FreeHandle(mCameraAdapterParameters.mHandleComp); + } + + ///De-init the OMX + OMX_Deinit(); + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +OMXCameraAdapter::OMXCameraPortParameters *OMXCameraAdapter::getPortParams(CameraFrame::FrameType frameType) +{ + OMXCameraAdapter::OMXCameraPortParameters *ret = NULL; + + switch ( frameType ) + { + case CameraFrame::IMAGE_FRAME: + case CameraFrame::RAW_FRAME: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + break; + case CameraFrame::PREVIEW_FRAME_SYNC: + case CameraFrame::SNAPSHOT_FRAME: + case CameraFrame::VIDEO_FRAME_SYNC: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + break; + case CameraFrame::FRAME_DATA_SYNC: + ret = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + break; + default: + break; + }; + + return ret; +} + +status_t OMXCameraAdapter::fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType) +{ + status_t ret = NO_ERROR; + OMXCameraPortParameters *port = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) + { + return NO_INIT; + } + + if ( NULL == frameBuf ) + { + return -EINVAL; + } + + if ( (NO_ERROR == ret) && + ((CameraFrame::IMAGE_FRAME == frameType) || (CameraFrame::RAW_FRAME == frameType)) && + (1 > mCapturedFrames) && + (!mBracketingEnabled)) { + // Signal end of image capture + if ( NULL != mEndImageCaptureCallback) { + mEndImageCaptureCallback(mEndCaptureData); + } + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + port = getPortParams(frameType); + if ( NULL == port ) + { + CAMHAL_LOGEB("Invalid frameType 0x%x", frameType); + ret = -EINVAL; + } + } + + if ( NO_ERROR == ret ) + { + + for ( int i = 0 ; i < port->mNumBufs ; i++) + { + if ( port->mBufferHeader[i]->pBuffer == frameBuf ) + { + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, port->mBufferHeader[i]); + if ( eError != OMX_ErrorNone ) + { + CAMHAL_LOGDB("OMX_FillThisBuffer 0x%x", eError); + ret = ErrorUtils::omxToAndroidError(eError); + } + break; + } + } + + } + + return ret; +} + +status_t OMXCameraAdapter::setParameters(const CameraParameters ¶ms) +{ + LOG_FUNCTION_NAME; + + const char * str = NULL; + int mode = 0; + status_t ret = NO_ERROR; + bool updateImagePortParams = false; + int minFramerate, maxFramerate, frameRate; + const char *valstr = NULL; + const char *oldstr = NULL; + int w, h; + OMX_COLOR_FORMATTYPE pixFormat; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + ///@todo Include more camera parameters + if ( (valstr = params.getPreviewFormat()) != NULL ) + { + if (strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 || + strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV420P) == 0) + { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + } + else + { + CAMHAL_LOGDA("Invalid format, CbYCrY format selected as default"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + } + else + { + CAMHAL_LOGEA("Preview format is NULL, defaulting to CbYCrY"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + + OMXCameraPortParameters *cap; + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + params.getPreviewSize(&w, &h); + frameRate = params.getPreviewFrameRate(); + minFramerate = params.getInt(TICameraParameters::KEY_MINFRAMERATE); + maxFramerate = params.getInt(TICameraParameters::KEY_MAXFRAMERATE); + if ( ( 0 < minFramerate ) && + ( 0 < maxFramerate ) ) + { + if ( minFramerate > maxFramerate ) + { + CAMHAL_LOGEA(" Min FPS set higher than MAX. So setting MIN and MAX to the higher value"); + maxFramerate = minFramerate; + } + + if ( 0 >= frameRate ) + { + frameRate = maxFramerate; + } + + if( ( cap->mMinFrameRate != minFramerate ) || + ( cap->mMaxFrameRate != maxFramerate ) ) + { + cap->mMinFrameRate = minFramerate; + cap->mMaxFrameRate = maxFramerate; + setVFramerate(cap->mMinFrameRate, cap->mMaxFrameRate); + } + } + + if ( 0 < frameRate ) + { + cap->mColorFormat = pixFormat; + cap->mWidth = w; + cap->mHeight = h; + cap->mFrameRate = frameRate; + + CAMHAL_LOGVB("Prev: cap.mColorFormat = %d", (int)cap->mColorFormat); + CAMHAL_LOGVB("Prev: cap.mWidth = %d", (int)cap->mWidth); + CAMHAL_LOGVB("Prev: cap.mHeight = %d", (int)cap->mHeight); + CAMHAL_LOGVB("Prev: cap.mFrameRate = %d", (int)cap->mFrameRate); + + //TODO: Add an additional parameter for video resolution + //use preview resolution for now + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + cap->mColorFormat = pixFormat; + cap->mWidth = w; + cap->mHeight = h; + cap->mFrameRate = frameRate; + + CAMHAL_LOGVB("Video: cap.mColorFormat = %d", (int)cap->mColorFormat); + CAMHAL_LOGVB("Video: cap.mWidth = %d", (int)cap->mWidth); + CAMHAL_LOGVB("Video: cap.mHeight = %d", (int)cap->mHeight); + CAMHAL_LOGVB("Video: cap.mFrameRate = %d", (int)cap->mFrameRate); + + ///mStride is set from setBufs() while passing the APIs + cap->mStride = 4096; + cap->mBufSize = cap->mStride * cap->mHeight; + } + + if ( ( cap->mWidth >= 1920 ) && + ( cap->mHeight >= 1080 ) && + ( cap->mFrameRate >= FRAME_RATE_FULL_HD ) && + ( !mSensorOverclock ) ) + { + mOMXStateSwitch = true; + } + else if ( ( ( cap->mWidth < 1920 ) || + ( cap->mHeight < 1080 ) || + ( cap->mFrameRate < FRAME_RATE_FULL_HD ) ) && + ( mSensorOverclock ) ) + { + mOMXStateSwitch = true; + } + + if ( (valstr = params.get(TICameraParameters::KEY_MEASUREMENT_ENABLE)) != NULL ) + { + if (strcmp(valstr, (const char *) TICameraParameters::MEASUREMENT_ENABLE) == 0) + { + mMeasurementEnabled = true; + } + else if (strcmp(valstr, (const char *) TICameraParameters::MEASUREMENT_DISABLE) == 0) + { + mMeasurementEnabled = false; + } + else + { + mMeasurementEnabled = false; + } + } + else + { + //Disable measurement data by default + mMeasurementEnabled = false; + } + + ret |= setParametersCapture(params, state); + + ret |= setParameters3A(params, state); + + ret |= setParametersAlgo(params, state); + + ret |= setParametersFocus(params, state); + + ret |= setParametersFD(params, state); + + ret |= setParametersZoom(params, state); + + ret |= setParametersEXIF(params, state); + + mParams = params; + mFirstTimeInit = false; + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +void saveFile(unsigned char *buff, int width, int height, int format) { + static int counter = 1; + int fd = -1; + char fn[256]; + + LOG_FUNCTION_NAME; + + fn[0] = 0; + sprintf(fn, "/preview%03d.yuv", counter); + fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + if(fd < 0) { + LOGE("Unable to open file %s: %s", fn, strerror(fd)); + return; + } + + CAMHAL_LOGVB("Copying from 0x%x, size=%d x %d", buff, width, height); + + //method currently supports only nv12 dumping + int stride = width; + uint8_t *bf = (uint8_t*) buff; + for(int i=0;i<height;i++) + { + write(fd, bf, width); + bf += 4096; + } + + for(int i=0;i<height/2;i++) + { + write(fd, bf, stride); + bf += 4096; + } + + close(fd); + + + counter++; + + LOG_FUNCTION_NAME_EXIT; +} + +void OMXCameraAdapter::getParameters(CameraParameters& params) +{ + status_t ret = NO_ERROR; + OMX_CONFIG_EXPOSUREVALUETYPE exp; + OMX_ERRORTYPE eError = OMX_ErrorNone; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + LOG_FUNCTION_NAME; + +#ifdef PARAM_FEEDBACK + + OMX_CONFIG_WHITEBALCONTROLTYPE wb; + OMX_CONFIG_FLICKERCANCELTYPE flicker; + OMX_CONFIG_SCENEMODETYPE scene; + OMX_IMAGE_PARAM_FLASHCONTROLTYPE flash; + OMX_CONFIG_BRIGHTNESSTYPE brightness; + OMX_CONFIG_CONTRASTTYPE contrast; + OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE procSharpness; + OMX_CONFIG_SATURATIONTYPE saturation; + OMX_CONFIG_IMAGEFILTERTYPE effect; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focus; + + exp.nSize = sizeof(OMX_CONFIG_EXPOSURECONTROLTYPE); + exp.nVersion = mLocalVersionParam; + exp.nPortIndex = OMX_ALL; + + expValues.nSize = sizeof(OMX_CONFIG_EXPOSUREVALUETYPE); + expValues.nVersion = mLocalVersionParam; + expValues.nPortIndex = OMX_ALL; + + wb.nSize = sizeof(OMX_CONFIG_WHITEBALCONTROLTYPE); + wb.nVersion = mLocalVersionParam; + wb.nPortIndex = OMX_ALL; + + flicker.nSize = sizeof(OMX_CONFIG_FLICKERCANCELTYPE); + flicker.nVersion = mLocalVersionParam; + flicker.nPortIndex = OMX_ALL; + + scene.nSize = sizeof(OMX_CONFIG_SCENEMODETYPE); + scene.nVersion = mLocalVersionParam; + scene.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + flash.nSize = sizeof(OMX_IMAGE_PARAM_FLASHCONTROLTYPE); + flash.nVersion = mLocalVersionParam; + flash.nPortIndex = OMX_ALL; + + + brightness.nSize = sizeof(OMX_CONFIG_BRIGHTNESSTYPE); + brightness.nVersion = mLocalVersionParam; + brightness.nPortIndex = OMX_ALL; + + contrast.nSize = sizeof(OMX_CONFIG_CONTRASTTYPE); + contrast.nVersion = mLocalVersionParam; + contrast.nPortIndex = OMX_ALL; + + procSharpness.nSize = sizeof( OMX_IMAGE_CONFIG_PROCESSINGLEVELTYPE ); + procSharpness.nVersion = mLocalVersionParam; + procSharpness.nPortIndex = OMX_ALL; + + saturation.nSize = sizeof(OMX_CONFIG_SATURATIONTYPE); + saturation.nVersion = mLocalVersionParam; + saturation.nPortIndex = OMX_ALL; + + effect.nSize = sizeof(OMX_CONFIG_IMAGEFILTERTYPE); + effect.nVersion = mLocalVersionParam; + effect.nPortIndex = OMX_ALL; + + focus.nSize = sizeof(OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focus.nVersion = mLocalVersionParam; + focus.nPortIndex = OMX_ALL; + + OMX_GetConfig( mCameraAdapterParameters.mHandleComp,OMX_IndexConfigCommonExposure, &exp); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigCommonWhiteBalance, &wb); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_IndexConfigFlickerCancel, &flicker ); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_IndexParamSceneMode, &scene); + OMX_GetParameter( mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_IndexParamFlashControl, &flash); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigCommonBrightness, &brightness); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigCommonContrast, &contrast); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, (OMX_INDEXTYPE)OMX_IndexConfigSharpeningLevel, &procSharpness); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigCommonSaturation, &saturation); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigCommonImageFilter, &effect); + OMX_GetConfig( mCameraAdapterParameters.mHandleComp, OMX_IndexConfigFocusControl, &focus); + + char * str = NULL; + + for(int i = 0; i < ExpLUT.size; i++) + if( ExpLUT.Table[i].omxDefinition == exp.eExposureControl ) + str = (char*)ExpLUT.Table[i].userDefinition; + params.set( TICameraParameters::KEY_EXPOSURE_MODE , str); + + for(int i = 0; i < WBalLUT.size; i++) + if( WBalLUT.Table[i].omxDefinition == wb.eWhiteBalControl ) + str = (char*)WBalLUT.Table[i].userDefinition; + params.set( CameraParameters::KEY_WHITE_BALANCE , str ); + + for(int i = 0; i < FlickerLUT.size; i++) + if( FlickerLUT.Table[i].omxDefinition == flicker.eFlickerCancel ) + str = (char*)FlickerLUT.Table[i].userDefinition; + params.set( CameraParameters::KEY_ANTIBANDING , str ); + + for(int i = 0; i < SceneLUT.size; i++) + if( SceneLUT.Table[i].omxDefinition == scene.eSceneMode ) + str = (char*)SceneLUT.Table[i].userDefinition; + params.set( CameraParameters::KEY_SCENE_MODE , str ); + + for(int i = 0; i < FlashLUT.size; i++) + if( FlashLUT.Table[i].omxDefinition == flash.eFlashControl ) + str = (char*)FlashLUT.Table[i].userDefinition; + params.set( CameraParameters::KEY_FLASH_MODE, str ); + + for(int i = 0; i < EffLUT.size; i++) + if( EffLUT.Table[i].omxDefinition == effect.eImageFilter ) + str = (char*)EffLUT.Table[i].userDefinition; + params.set( CameraParameters::KEY_EFFECT , str ); + + for(int i = 0; i < FocusLUT.size; i++) + if( FocusLUT.Table[i].omxDefinition == focus.eFocusControl ) + str = (char*)FocusLUT.Table[i].userDefinition; + + params.set( CameraParameters::KEY_FOCUS_MODE , str ); + + int comp = ((expValues.xEVCompensation * 10) >> Q16_OFFSET); + + params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION, comp ); + params.set( TICameraParameters::KEY_MAN_EXPOSURE, expValues.nShutterSpeedMsec); + params.set( TICameraParameters::KEY_BRIGHTNESS, brightness.nBrightness); + params.set( TICameraParameters::KEY_CONTRAST, contrast.nContrast ); + params.set( TICameraParameters::KEY_SHARPNESS, procSharpness.nLevel); + params.set( TICameraParameters::KEY_SATURATION, saturation.nSaturation); + +#else + + //Query focus distances only during CAF, Infinity + //or when focus is running + if ( ( AF_ACTIVE & state ) || + ( mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) || + ( mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity ) || + ( NULL == mParameters.get(CameraParameters::KEY_FOCUS_DISTANCES) ) ) + { + updateFocusDistances(params); + } + else + { + params.set(CameraParameters::KEY_FOCUS_DISTANCES, + mParameters.get(CameraParameters::KEY_FOCUS_DISTANCES)); + } + + OMX_INIT_STRUCT_PTR (&exp, OMX_CONFIG_EXPOSUREVALUETYPE); + exp.nPortIndex = OMX_ALL; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonExposureValue, + &exp); + if ( OMX_ErrorNone == eError ) + { + params.set(TICameraParameters::KEY_CURRENT_ISO, exp.nSensitivity); + } + else + { + CAMHAL_LOGEB("OMX error 0x%x, while retrieving current ISO value", eError); + } + + { + Mutex::Autolock lock(mZoomLock); + //Immediate zoom should not be avaialable while smooth zoom is running + if ( ZOOM_ACTIVE & state ) + { + if ( mZoomParameterIdx != mCurrentZoomIdx ) + { + mZoomParameterIdx += mZoomInc; + } + params.set( CameraParameters::KEY_ZOOM, mZoomParameterIdx); + if ( ( mCurrentZoomIdx == mTargetZoomIdx ) && + ( mZoomParameterIdx == mCurrentZoomIdx ) ) + { + + if ( NO_ERROR == ret ) + { + + ret = BaseCameraAdapter::setState(CAMERA_STOP_SMOOTH_ZOOM); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + } + + } + + CAMHAL_LOGDB("CameraParameters Zoom = %d", mCurrentZoomIdx); + } + else + { + params.set( CameraParameters::KEY_ZOOM, mCurrentZoomIdx); + } + } + +#endif + + LOG_FUNCTION_NAME_EXIT; +} + +status_t OMXCameraAdapter::setFormat(OMX_U32 port, OMXCameraPortParameters &portParams) +{ + size_t bufferCount; + + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_PARAM_PORTDEFINITIONTYPE portCheck; + + OMX_INIT_STRUCT_PTR (&portCheck, OMX_PARAM_PORTDEFINITIONTYPE); + + portCheck.nPortIndex = port; + + eError = OMX_GetParameter (mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_GetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + if ( OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW == port ) + { + portCheck.format.video.nFrameWidth = portParams.mWidth; + portCheck.format.video.nFrameHeight = portParams.mHeight; + portCheck.format.video.eColorFormat = portParams.mColorFormat; + portCheck.format.video.nStride = portParams.mStride; + if( ( portCheck.format.video.nFrameWidth >= 1920 ) && + ( portCheck.format.video.nFrameHeight >= 1080 ) && + ( portParams.mFrameRate >= FRAME_RATE_FULL_HD ) ) + { + setSensorOverclock(true); + } + else + { + setSensorOverclock(false); + } + + portCheck.format.video.xFramerate = portParams.mFrameRate<<16; + portCheck.nBufferSize = portParams.mStride * portParams.mHeight; + portCheck.nBufferCountActual = portParams.mNumBufs; + mFocusThreshold = FOCUS_THRESHOLD * portParams.mFrameRate; + } + else if ( OMX_CAMERA_PORT_IMAGE_OUT_IMAGE == port ) + { + portCheck.format.image.nFrameWidth = portParams.mWidth; + portCheck.format.image.nFrameHeight = portParams.mHeight; + if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingNone ) + { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingJPS ) + { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = (OMX_IMAGE_CODINGTYPE) OMX_TI_IMAGE_CodingJPS; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingMPO ) + { + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = (OMX_IMAGE_CODINGTYPE) OMX_TI_IMAGE_CodingMPO; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingRAWJPEG ) + { + //TODO: OMX_IMAGE_CodingJPEG should be changed to OMX_IMAGE_CodingRAWJPEG when + // RAW format is supported + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + else if ( OMX_COLOR_FormatUnused == portParams.mColorFormat && mCodingMode == CodingRAWMPO ) + { + //TODO: OMX_IMAGE_CodingJPEG should be changed to OMX_IMAGE_CodingRAWMPO when + // RAW format is supported + portCheck.format.image.eColorFormat = OMX_COLOR_FormatCbYCrY; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG; + } + else + { + portCheck.format.image.eColorFormat = portParams.mColorFormat; + portCheck.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused; + } + + //Stride for 1D tiler buffer is zero + portCheck.format.image.nStride = 0; + portCheck.nBufferSize = portParams.mStride * portParams.mWidth * portParams.mHeight; + portCheck.nBufferCountActual = portParams.mNumBufs; + } + else + { + CAMHAL_LOGEB("Unsupported port index 0x%x", (unsigned int)port); + } + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + /* check if parameters are set correctly by calling GetParameter() */ + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, + OMX_IndexParamPortDefinition, &portCheck); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_GetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + portParams.mBufSize = portCheck.nBufferSize; + + if ( OMX_CAMERA_PORT_IMAGE_OUT_IMAGE == port ) + { + CAMHAL_LOGDB("\n *** IMG Width = %ld", portCheck.format.image.nFrameWidth); + CAMHAL_LOGDB("\n ***IMG Height = %ld", portCheck.format.image.nFrameHeight); + + CAMHAL_LOGDB("\n ***IMG IMG FMT = %x", portCheck.format.image.eColorFormat); + CAMHAL_LOGDB("\n ***IMG portCheck.nBufferSize = %ld\n",portCheck.nBufferSize); + CAMHAL_LOGDB("\n ***IMG portCheck.nBufferCountMin = %ld\n", + portCheck.nBufferCountMin); + CAMHAL_LOGDB("\n ***IMG portCheck.nBufferCountActual = %ld\n", + portCheck.nBufferCountActual); + CAMHAL_LOGDB("\n ***IMG portCheck.format.image.nStride = %ld\n", + portCheck.format.image.nStride); + } + else + { + CAMHAL_LOGDB("\n *** PRV Width = %ld", portCheck.format.video.nFrameWidth); + CAMHAL_LOGDB("\n ***PRV Height = %ld", portCheck.format.video.nFrameHeight); + + CAMHAL_LOGDB("\n ***PRV IMG FMT = %x", portCheck.format.video.eColorFormat); + CAMHAL_LOGDB("\n ***PRV portCheck.nBufferSize = %ld\n",portCheck.nBufferSize); + CAMHAL_LOGDB("\n ***PRV portCheck.nBufferCountMin = %ld\n", + portCheck.nBufferCountMin); + CAMHAL_LOGDB("\n ***PRV portCheck.nBufferCountActual = %ld\n", + portCheck.nBufferCountActual); + CAMHAL_LOGDB("\n ***PRV portCheck.format.video.nStride = %ld\n", + portCheck.format.video.nStride); + } + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of eError=%x", __FUNCTION__, eError); + + LOG_FUNCTION_NAME_EXIT; + + return ErrorUtils::omxToAndroidError(eError); +} + +status_t OMXCameraAdapter::flushBuffers() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + TIMM_OSAL_ERRORTYPE err; + TIMM_OSAL_U32 uRequestedEvents = OMXCameraAdapter::CAMERA_PORT_FLUSH; + TIMM_OSAL_U32 pRetrievedEvents; + + if ( 0 != mFlushSem.Count() ) + { + CAMHAL_LOGEB("Error mFlushSem semaphore count %d", mFlushSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + LOG_FUNCTION_NAME; + + OMXCameraPortParameters * mPreviewData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + + ///Register for the FLUSH event + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandFlush, + OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, + mFlushSem); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Send FLUSH command to preview port + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp, + OMX_CommandFlush, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandFlush)-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + CAMHAL_LOGDA("Waiting for flush event"); + + ///Wait for the FLUSH event to occur + ret = mFlushSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Flush event received"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandFlush, + OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW, + NULL); + CAMHAL_LOGDA("Flush event timeout expired"); + goto EXIT; + } + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); + + EXIT: + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); +} + +///API to give the buffers to Adapter +status_t OMXCameraAdapter::useBuffers(CameraMode mode, void* bufArr, int num, size_t length, unsigned int queueable) +{ + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + switch(mode) + { + case CAMERA_PREVIEW: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreview(bufArr, num); + break; + + case CAMERA_IMAGE_CAPTURE: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].mMaxQueueable = queueable; + ret = UseBuffersCapture(bufArr, num); + break; + + case CAMERA_VIDEO: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreview(bufArr, num); + break; + + case CAMERA_MEASUREMENT: + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex].mNumBufs = num; + mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex].mMaxQueueable = queueable; + ret = UseBuffersPreviewData(bufArr, num); + break; + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::UseBuffersPreviewData(void* bufArr, int num) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * measurementData = NULL; + uint32_t *buffers; + Mutex::Autolock lock( mPreviewDataBufferLock); + + LOG_FUNCTION_NAME; + + if ( mComponentState != OMX_StateLoaded ) + { + CAMHAL_LOGEA("Calling UseBuffersPreviewData() when not in LOADED state"); + ret = BAD_VALUE; + } + + if ( NULL == bufArr ) + { + CAMHAL_LOGEA("NULL pointer passed for buffArr"); + ret = BAD_VALUE; + } + + if ( 0 != mUsePreviewDataSem.Count() ) + { + CAMHAL_LOGEB("Error mUsePreviewDataSem semaphore count %d", mUsePreviewDataSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + measurementData->mNumBufs = num ; + buffers= (uint32_t*) bufArr; + } + + if ( NO_ERROR == ret ) + { + ///Register for port enable event on measurement port + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mMeasurementPortIndex, + mUsePreviewDataSem); + + if ( ret == NO_ERROR ) + { + CAMHAL_LOGDB("Registering for event %d", ret); + } + else + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + ///Enable MEASUREMENT Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mMeasurementPortIndex, + NULL); + + if ( eError == OMX_ErrorNone ) + { + CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + } + else + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_CommandPortEnable) -0x%x", eError); + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + ret = mUsePreviewDataSem.WaitTimeout(OMX_CMD_TIMEOUT); + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Port enable event arrived on measurement port"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mMeasurementPortIndex, + NULL); + CAMHAL_LOGEA("Timeout expoired during port enable on measurement port"); + } + + CAMHAL_LOGDA("Port enable event arrived on measurement port"); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::switchToLoaded() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( mComponentState == OMX_StateLoaded ) + { + CAMHAL_LOGDA("Already in OMX_Loaded state"); + goto EXIT; + } + + if ( 0 != mSwitchToLoadedSem.Count() ) + { + CAMHAL_LOGEB("Error mSwitchToLoadedSem semaphore count %d", mSwitchToLoadedSem.Count()); + goto EXIT; + } + + ///Register for EXECUTING state transition. + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + mSwitchToLoadedSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp, + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_StateIdle) - %x", eError); + } + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + ///Wait for the EXECUTING ->IDLE transition to arrive + + CAMHAL_LOGDA("EXECUTING->IDLE state changed"); + ret = mSwitchToLoadedSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("EXECUTING->IDLE state changed"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + CAMHAL_LOGEA("Timeout expired on EXECUTING->IDLE state change"); + goto EXIT; + } + + ///Register for LOADED state transition. + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateLoaded, + mSwitchToLoadedSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp, + OMX_CommandStateSet, + OMX_StateLoaded, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_StateLoaded) - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + CAMHAL_LOGDA("Switching IDLE->LOADED state"); + ret = mSwitchToLoadedSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("IDLE->LOADED state changed"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateLoaded, + NULL); + CAMHAL_LOGEA("Timeout expired on IDLE->LOADED state change"); + goto EXIT; + } + + mComponentState = OMX_StateLoaded; + + ///Register for Preview port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + mSwitchToLoadedSem); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Enable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + + CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandStateSet) 0x%x", eError); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + CAMHAL_LOGDA("Enabling Preview port"); + ///Wait for state to switch to idle + ret = mSwitchToLoadedSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Preview port enabled!"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + CAMHAL_LOGEA("Preview enable timedout"); + goto EXIT; + } + + EXIT: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::UseBuffersPreview(void* bufArr, int num) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + int tmpHeight, tmpWidth; + + LOG_FUNCTION_NAME; + + ///Flag to determine whether it is 3D camera or not + bool isS3d = false; + const char *valstr = NULL; + if ( (valstr = mParams.get(TICameraParameters::KEY_S3D_SUPPORTED)) != NULL) { + isS3d = (strcmp(valstr, "true") == 0); + } + + if(!bufArr) + { + CAMHAL_LOGEA("NULL pointer passed for buffArr"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + OMXCameraPortParameters * mPreviewData = NULL; + OMXCameraPortParameters *measurementData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + mPreviewData->mNumBufs = num ; + uint32_t *buffers = (uint32_t*)bufArr; + + if ( 0 != mUsePreviewSem.Count() ) + { + CAMHAL_LOGEB("Error mUsePreviewSem semaphore count %d", mUsePreviewSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + if(mPreviewData->mNumBufs != num) + { + CAMHAL_LOGEA("Current number of buffers doesnt equal new num of buffers passed!"); + LOG_FUNCTION_NAME_EXIT; + return BAD_VALUE; + } + + if ( mComponentState == OMX_StateLoaded ) + { + + ret = setLDC(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setLDC() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + ret = setNSF(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setNSF() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + ret = setCaptureMode(mCapMode); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setCaptureMode() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + CAMHAL_LOGDB("Camera Mode = %d", mCapMode); + + if( ( mCapMode == OMXCameraAdapter::VIDEO_MODE ) || + ( isS3d && (mCapMode == OMXCameraAdapter::HIGH_QUALITY)) ) + { + ///Enable/Disable Video Noise Filter + ret = enableVideoNoiseFilter(mVnfEnabled); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + return ret; + } + + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(mVstabEnabled); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + return ret; + } + } + else + { + ret = enableVideoNoiseFilter(false); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + return ret; + } + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(false); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + return ret; + } + } + } + + ret = setSensorOrientation(mSensorOrientation); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring Sensor Orientation %x", ret); + mSensorOrientation = 0; + } + + ret = setVFramerate(mPreviewData->mMinFrameRate, mPreviewData->mMaxFrameRate); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEB("VFR configuration failed 0x%x", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + if ( mComponentState == OMX_StateLoaded ) + { + ///Register for IDLE state switch event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + mUsePreviewSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Once we get the buffers, move component state to idle state and pass the buffers to OMX comp using UseBuffer + eError = OMX_SendCommand (mCameraAdapterParameters.mHandleComp , + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + + CAMHAL_LOGDB("OMX_SendCommand(OMX_CommandStateSet) 0x%x", eError); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + mComponentState = OMX_StateIdle; + } + else + { + ///Register for Preview port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + mUsePreviewSem); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Enable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + } + + + ///Configure DOMX to use either gralloc handles or vptrs + OMX_TI_PARAMUSENATIVEBUFFER domxUseGrallocHandles; + OMX_INIT_STRUCT_PTR (&domxUseGrallocHandles, OMX_TI_PARAMUSENATIVEBUFFER); + + domxUseGrallocHandles.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + domxUseGrallocHandles.bEnable = OMX_TRUE; + + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE)OMX_TI_IndexUseNativeBuffers, &domxUseGrallocHandles); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SetParameter - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + OMX_BUFFERHEADERTYPE *pBufferHdr; + for(int index=0;index<num;index++) { + + CAMHAL_LOGDB("OMX_UseBuffer(0x%x)", buffers[index]); + eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp, + &pBufferHdr, + mCameraAdapterParameters.mPrevPortIndex, + 0, + mPreviewData->mBufSize, + (OMX_U8*)buffers[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_UseBuffer-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + //pBufferHdr->pAppPrivate = (OMX_PTR)pBufferHdr; + pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufferHdr->nVersion.s.nVersionMajor = 1 ; + pBufferHdr->nVersion.s.nVersionMinor = 1 ; + pBufferHdr->nVersion.s.nRevision = 0 ; + pBufferHdr->nVersion.s.nStep = 0; + mPreviewData->mBufferHeader[index] = pBufferHdr; + } + + if ( mMeasurementEnabled ) + { + + for( int i = 0; i < num; i++ ) + { + OMX_BUFFERHEADERTYPE *pBufHdr; + eError = OMX_UseBuffer( mCameraAdapterParameters.mHandleComp, + &pBufHdr, + mCameraAdapterParameters.mMeasurementPortIndex, + 0, + measurementData->mBufSize, + (OMX_U8*)(mPreviewDataBuffers[i])); + + if ( eError == OMX_ErrorNone ) + { + pBufHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufHdr->nVersion.s.nVersionMajor = 1 ; + pBufHdr->nVersion.s.nVersionMinor = 1 ; + pBufHdr->nVersion.s.nRevision = 0 ; + pBufHdr->nVersion.s.nStep = 0; + measurementData->mBufferHeader[i] = pBufHdr; + } + else + { + CAMHAL_LOGEB("OMX_UseBuffer -0x%x", eError); + ret = BAD_VALUE; + break; + } + } + + } + + CAMHAL_LOGDA("Registering preview buffers"); + + ret = mUsePreviewSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Preview buffer registration successfull"); + } + else + { + if ( mComponentState == OMX_StateLoaded ) + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateIdle, + NULL); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + } + CAMHAL_LOGEA("Timeout expired on preview buffer registration"); + goto EXIT; + } + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); + + ///If there is any failure, we reach here. + ///Here, we do any resource freeing and convert from OMX error code to Camera Hal error code + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); +} + +status_t OMXCameraAdapter::startPreview() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters *mPreviewData = NULL; + OMXCameraPortParameters *measurementData = NULL; + + LOG_FUNCTION_NAME; + + if( 0 != mStartPreviewSem.Count() ) + { + CAMHAL_LOGEB("Error mStartPreviewSem semaphore count %d", mStartPreviewSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + + if( OMX_StateIdle == mComponentState ) + { + ///Register for EXECUTING state transition. + ///This method just inserts a message in Event Q, which is checked in the callback + ///The sempahore passed is signalled by the callback + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateExecuting, + mStartPreviewSem); + + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error in registering for event %d", ret); + goto EXIT; + } + + ///Switch to EXECUTING state + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandStateSet, + OMX_StateExecuting, + NULL); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_SendCommand(OMX_StateExecuting)-0x%x", eError); + } + + CAMHAL_LOGDA("+Waiting for component to go into EXECUTING state"); + ret = mStartPreviewSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("+Great. Component went into executing state!!"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandStateSet, + OMX_StateExecuting, + NULL); + CAMHAL_LOGDA("Timeout expired on executing state switch!"); + goto EXIT; + } + + mComponentState = OMX_StateExecuting; + + } + + //Queue all the buffers on preview port + for(int index=0;index< mPreviewData->mMaxQueueable;index++) + { + CAMHAL_LOGDB("Queuing buffer on Preview port - 0x%x", (uint32_t)mPreviewData->mBufferHeader[index]->pBuffer); + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)mPreviewData->mBufferHeader[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + if ( mMeasurementEnabled ) + { + + for(int index=0;index< mPreviewData->mNumBufs;index++) + { + CAMHAL_LOGDB("Queuing buffer on Measurement port - 0x%x", (uint32_t) measurementData->mBufferHeader[index]->pBuffer); + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*) measurementData->mBufferHeader[index]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FillThisBuffer-0x%x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + } + + if ( mPending3Asettings ) + apply3Asettings(mParameters3A); + + //Query current focus distance after + //starting the preview + updateFocusDistances(mParameters); + + //reset frame rate estimates + mFPS = 0.0f; + mLastFPS = 0.0f; + mFrameCount = 0; + mLastFrameCount = 0; + mIter = 1; + mLastFPSTime = systemTime(); + + LOG_FUNCTION_NAME_EXIT; + + return ret; + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, ret, eError); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); + +} + +status_t OMXCameraAdapter::stopPreview() +{ + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + status_t ret = NO_ERROR; + + OMXCameraPortParameters *mCaptureData , *mPreviewData, *measurementData; + mCaptureData = mPreviewData = measurementData = NULL; + + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + mCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + measurementData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mMeasurementPortIndex]; + + if ( mComponentState != OMX_StateExecuting ) + { + CAMHAL_LOGEA("Calling StopPreview() when not in EXECUTING state"); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + ret = cancelAutoFocus(); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error canceling autofocus %d", ret); + // Error, but we probably still want to continue to stop preview + } + + ret = release3ALock(); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error Releaseing 3A locks%d", ret); + } + + if ( 0 != mStopPreviewSem.Count() ) + { + CAMHAL_LOGEB("Error mStopPreviewSem semaphore count %d", mStopPreviewSem.Count()); + LOG_FUNCTION_NAME_EXIT; + return NO_INIT; + } + + CAMHAL_LOGDB("Average framerate: %f", mFPS); + + //Avoid state switching of the OMX Component + ret = flushBuffers(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Flush Buffers failed 0x%x", ret); + goto EXIT; + } + + ///Register for Preview port Disable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + mStopPreviewSem); + + ///Disable Preview Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + + ///Free the OMX Buffers + for ( int i = 0 ; i < mPreviewData->mNumBufs ; i++ ) + { + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mPrevPortIndex, + mPreviewData->mBufferHeader[i]); + + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FreeBuffer - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + if ( mMeasurementEnabled ) + { + + for ( int i = 0 ; i < measurementData->mNumBufs ; i++ ) + { + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mMeasurementPortIndex, + measurementData->mBufferHeader[i]); + if(eError!=OMX_ErrorNone) + { + CAMHAL_LOGEB("OMX_FreeBuffer - %x", eError); + } + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + { + Mutex::Autolock lock(mPreviewDataBufferLock); + mPreviewDataBuffersAvailable.clear(); + } + + } + + CAMHAL_LOGDA("Disabling preview port"); + ret = mStopPreviewSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Preview port disabled"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mPrevPortIndex, + NULL); + CAMHAL_LOGEA("Timeout expired on preview port disable"); + goto EXIT; + } + + { + Mutex::Autolock lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + + switchToLoaded(); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); + + EXIT: + + { + Mutex::Autolock lock(mPreviewBufferLock); + ///Clear all the available preview buffers + mPreviewBuffersAvailable.clear(); + } + + switchToLoaded(); + + LOG_FUNCTION_NAME_EXIT; + + return (ret | ErrorUtils::omxToAndroidError(eError)); + +} + +status_t OMXCameraAdapter::setSensorOverclock(bool enable) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGDA("OMX component is not in loaded state"); + return ret; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + + if ( enable ) + { + bOMX.bEnabled = OMX_TRUE; + } + else + { + bOMX.bEnabled = OMX_FALSE; + } + + CAMHAL_LOGDB("Configuring Sensor overclock mode 0x%x", bOMX.bEnabled); + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexParamSensorOverClockMode, &bOMX); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting Sensor overclock 0x%x", eError); + ret = BAD_VALUE; + } + else + { + mSensorOverclock = enable; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::printComponentVersion(OMX_HANDLETYPE handle) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_VERSIONTYPE compVersion; + char compName[OMX_MAX_STRINGNAME_SIZE]; + char *currentUUID = NULL; + size_t offset = 0; + + LOG_FUNCTION_NAME; + + if ( NULL == handle ) + { + CAMHAL_LOGEB("Invalid OMX Handle =0x%x", ( unsigned int ) handle); + ret = -EINVAL; + } + + mCompUUID[0] = 0; + + if ( NO_ERROR == ret ) + { + eError = OMX_GetComponentVersion(handle, + compName, + &compVersion, + &mCompRevision, + &mCompUUID + ); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_GetComponentVersion returned 0x%x", eError); + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGVB("OMX Component name: [%s]", compName); + CAMHAL_LOGVB("OMX Component version: [%u]", ( unsigned int ) compVersion.nVersion); + CAMHAL_LOGVB("Spec version: [%u]", ( unsigned int ) mCompRevision.nVersion); + CAMHAL_LOGVB("Git Commit ID: [%s]", mCompUUID); + currentUUID = ( char * ) mCompUUID; + } + + if ( NULL != currentUUID ) + { + offset = strlen( ( const char * ) mCompUUID) + 1; + if ( (int)currentUUID + (int)offset - (int)mCompUUID < OMX_MAX_STRINGNAME_SIZE ) + { + currentUUID += offset; + CAMHAL_LOGVB("Git Branch: [%s]", currentUUID); + } + else + { + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + offset = strlen( ( const char * ) currentUUID) + 1; + + if ( (int)currentUUID + (int)offset - (int)mCompUUID < OMX_MAX_STRINGNAME_SIZE ) + { + currentUUID += offset; + CAMHAL_LOGVB("Build date and time: [%s]", currentUUID); + } + else + { + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + offset = strlen( ( const char * ) currentUUID) + 1; + + if ( (int)currentUUID + (int)offset - (int)mCompUUID < OMX_MAX_STRINGNAME_SIZE ) + { + currentUUID += offset; + CAMHAL_LOGVB("Build description: [%s]", currentUUID); + } + else + { + ret = BAD_VALUE; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::autoFocus() +{ + status_t ret = NO_ERROR; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + msg.command = CommandHandler::CAMERA_PERFORM_AUTOFOCUS; + msg.arg1 = mErrorNotifier; + ret = mCommandHandler->put(&msg); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::takePicture() +{ + status_t ret = NO_ERROR; + TIUTILS::Message msg; + + LOG_FUNCTION_NAME; + + msg.command = CommandHandler::CAMERA_START_IMAGE_CAPTURE; + msg.arg1 = mErrorNotifier; + ret = mCommandHandler->put(&msg); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startVideoCapture() +{ + return BaseCameraAdapter::startVideoCapture(); +} + +status_t OMXCameraAdapter::stopVideoCapture() +{ + return BaseCameraAdapter::stopVideoCapture(); +} + +//API to get the frame size required to be allocated. This size is used to override the size passed +//by camera service when VSTAB/VNF is turned ON for example +status_t OMXCameraAdapter::getFrameSize(size_t &width, size_t &height) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_RECTTYPE tFrameDim; + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT_PTR (&tFrameDim, OMX_CONFIG_RECTTYPE); + tFrameDim.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + if ( mOMXStateSwitch ) + { + + ret = switchToLoaded(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("switchToLoaded() failed 0x%x", ret); + goto exit; + } + + mOMXStateSwitch = false; + } + + if ( OMX_StateLoaded == mComponentState ) + { + + ret = setLDC(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setLDC() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + goto exit; + } + + ret = setNSF(mIPP); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setNSF() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + goto exit; + } + + ret = setCaptureMode(mCapMode); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("setCaptureMode() failed %d", ret); + } + + if(mCapMode == OMXCameraAdapter::VIDEO_MODE) + { + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Noise Filter + ret = enableVideoNoiseFilter(mVnfEnabled); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + } + + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(mVstabEnabled); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + } + } + else + { + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Noise Filter + ret = enableVideoNoiseFilter(false); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VNF %x", ret); + } + + if ( NO_ERROR == ret ) + { + ///Enable/Disable Video Stabilization + ret = enableVideoStabilization(false); + } + + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring VSTAB %x", ret); + } + } + + } + + ret = setSensorOrientation(mSensorOrientation); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring Sensor Orientation %x", ret); + mSensorOrientation = 0; + } + + if ( NO_ERROR == ret ) + { + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, ( OMX_INDEXTYPE ) OMX_TI_IndexParam2DBufferAllocDimension, &tFrameDim); + if ( OMX_ErrorNone == eError) + { + width = tFrameDim.nWidth; + height = tFrameDim.nHeight; + } + } + +exit: + + CAMHAL_LOGDB("Required frame size %dx%d", width, height); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) +{ + status_t ret = NO_ERROR; + OMX_PARAM_PORTDEFINITIONTYPE portCheck; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( OMX_StateLoaded != mComponentState ) + { + CAMHAL_LOGEA("Calling getFrameDataSize() when not in LOADED state"); + dataFrameSize = 0; + ret = BAD_VALUE; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR(&portCheck, OMX_PARAM_PORTDEFINITIONTYPE); + portCheck.nPortIndex = mCameraAdapterParameters.mMeasurementPortIndex; + + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, OMX_IndexParamPortDefinition, &portCheck); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_GetParameter on OMX_IndexParamPortDefinition returned: 0x%x", eError); + dataFrameSize = 0; + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + portCheck.nBufferCountActual = bufferCount; + eError = OMX_SetParameter(mCameraAdapterParameters.mHandleComp, OMX_IndexParamPortDefinition, &portCheck); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_SetParameter on OMX_IndexParamPortDefinition returned: 0x%x", eError); + dataFrameSize = 0; + ret = BAD_VALUE; + } + } + + if ( NO_ERROR == ret ) + { + eError = OMX_GetParameter(mCameraAdapterParameters.mHandleComp, OMX_IndexParamPortDefinition, &portCheck); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("OMX_GetParameter on OMX_IndexParamPortDefinition returned: 0x%x", eError); + ret = BAD_VALUE; + } + else + { + mCameraAdapterParameters.mCameraPortParams[portCheck.nPortIndex].mBufSize = portCheck.nBufferSize; + dataFrameSize = portCheck.nBufferSize; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +void OMXCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) +{ + LOG_FUNCTION_NAME; + + static const int DEGREES_TILT_IGNORE = 45; + int device_orientation = 0; + int mount_orientation = 0; + const char *facing_direction = NULL; + + // if tilt angle is greater than DEGREES_TILT_IGNORE + // we are going to ignore the orientation returned from + // sensor. the orientation returned from sensor is not + // reliable. Value of DEGREES_TILT_IGNORE may need adjusting + if (tilt > DEGREES_TILT_IGNORE) { + return; + } + + if (mCapabilities) { + if (mCapabilities->get(CameraProperties::ORIENTATION_INDEX)) { + mount_orientation = atoi(mCapabilities->get(CameraProperties::ORIENTATION_INDEX)); + } + facing_direction = mCapabilities->get(CameraProperties::FACING_INDEX); + } + + // calculate device orientation relative to the sensor orientation + // front camera display is mirrored + if (facing_direction && !strcmp(facing_direction, TICameraParameters::FACING_FRONT)) { + device_orientation = (orientation - mount_orientation + 360) % 360; + } else { // back-facing camera + device_orientation = (orientation + mount_orientation) % 360; + } + + if (device_orientation != mDeviceOrientation) { + mDeviceOrientation = device_orientation; + + mFaceDetectionLock.lock(); + if (mFaceDetectionRunning) { + // restart face detection with new rotation + setFaceDetection(true, mDeviceOrientation); + } + mFaceDetectionLock.unlock(); + } + CAMHAL_LOGVB("orientation = %d tilt = %d device_orientation = %d", orientation, tilt, mDeviceOrientation); + + LOG_FUNCTION_NAME_EXIT; +} + +/* Application callback Functions */ +/*========================================================*/ +/* @ fn SampleTest_EventHandler :: Application callback */ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + LOG_FUNCTION_NAME; + + CAMHAL_LOGDB("Event %d", eEvent); + + OMX_ERRORTYPE ret = OMX_ErrorNone; + OMXCameraAdapter *oca = (OMXCameraAdapter*)pAppData; + ret = oca->OMXCameraAdapterEventHandler(hComponent, eEvent, nData1, nData2, pEventData); + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +/* Application callback Functions */ +/*========================================================*/ +/* @ fn SampleTest_EventHandler :: Application callback */ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + CAMHAL_LOGDB("+OMX_Event %x, %d %d", eEvent, (int)nData1, (int)nData2); + + switch (eEvent) { + case OMX_EventCmdComplete: + CAMHAL_LOGDB("+OMX_EventCmdComplete %d %d", (int)nData1, (int)nData2); + + if (OMX_CommandStateSet == nData1) { + mCameraAdapterParameters.mState = (OMX_STATETYPE) nData2; + + } else if (OMX_CommandFlush == nData1) { + CAMHAL_LOGDB("OMX_CommandFlush received for port %d", (int)nData2); + + } else if (OMX_CommandPortDisable == nData1) { + CAMHAL_LOGDB("OMX_CommandPortDisable received for port %d", (int)nData2); + + } else if (OMX_CommandPortEnable == nData1) { + CAMHAL_LOGDB("OMX_CommandPortEnable received for port %d", (int)nData2); + + } else if (OMX_CommandMarkBuffer == nData1) { + ///This is not used currently + } + + CAMHAL_LOGDA("-OMX_EventCmdComplete"); + break; + + case OMX_EventIndexSettingChanged: + CAMHAL_LOGDB("OMX_EventIndexSettingChanged event received data1 0x%x, data2 0x%x", + ( unsigned int ) nData1, ( unsigned int ) nData2); + break; + + case OMX_EventError: + CAMHAL_LOGDB("OMX interface failed to execute OMX command %d", (int)nData1); + CAMHAL_LOGDA("See OMX_INDEXTYPE for reference"); + if ( NULL != mErrorNotifier && ( ( OMX_U32 ) OMX_ErrorHardware == nData1 ) && mComponentState != OMX_StateInvalid) + { + CAMHAL_LOGEA("***Got Fatal Error Notification***\n"); + mComponentState = OMX_StateInvalid; + ///Report Error to App + mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN); + } + break; + + case OMX_EventMark: + break; + + case OMX_EventPortSettingsChanged: + break; + + case OMX_EventBufferFlag: + break; + + case OMX_EventResourcesAcquired: + break; + + case OMX_EventComponentResumed: + break; + + case OMX_EventDynamicResourcesAvailable: + break; + + case OMX_EventPortFormatDetected: + break; + + default: + break; + } + + ///Signal to the thread(s) waiting that the event has occured + SignalEvent(hComponent, eEvent, nData1, nData2, pEventData); + + LOG_FUNCTION_NAME_EXIT; + return eError; + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of eError=%x", __FUNCTION__, eError); + LOG_FUNCTION_NAME_EXIT; + return eError; +} + +OMX_ERRORTYPE OMXCameraAdapter::SignalEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData) +{ + Mutex::Autolock lock(mEventLock); + TIUTILS::Message *msg; + + LOG_FUNCTION_NAME; + + if ( !mEventSignalQ.isEmpty() ) + { + CAMHAL_LOGDA("Event queue not empty"); + + for ( unsigned int i = 0 ; i < mEventSignalQ.size() ; i++ ) + { + msg = mEventSignalQ.itemAt(i); + if ( NULL != msg ) + { + if( ( msg->command != 0 || msg->command == ( unsigned int ) ( eEvent ) ) + && ( !msg->arg1 || ( OMX_U32 ) msg->arg1 == nData1 ) + && ( !msg->arg2 || ( OMX_U32 ) msg->arg2 == nData2 ) + && msg->arg3) + { + Semaphore *sem = (Semaphore*) msg->arg3; + CAMHAL_LOGDA("Event matched, signalling sem"); + mEventSignalQ.removeAt(i); + //Signal the semaphore provided + sem->Signal(); + free(msg); + break; + } + } + } + } + else + { + CAMHAL_LOGEA("Event queue empty!!!"); + } + + LOG_FUNCTION_NAME_EXIT; + + return OMX_ErrorNone; +} + +status_t OMXCameraAdapter::RegisterForEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN Semaphore &semaphore) +{ + status_t ret = NO_ERROR; + ssize_t res; + Mutex::Autolock lock(mEventLock); + + LOG_FUNCTION_NAME; + + TIUTILS::Message * msg = ( struct TIUTILS::Message * ) malloc(sizeof(struct TIUTILS::Message)); + if ( NULL != msg ) + { + msg->command = ( unsigned int ) eEvent; + msg->arg1 = ( void * ) nData1; + msg->arg2 = ( void * ) nData2; + msg->arg3 = ( void * ) &semaphore; + msg->arg4 = ( void * ) hComponent; + res = mEventSignalQ.add(msg); + if ( NO_MEMORY == res ) + { + CAMHAL_LOGEA("No ressources for inserting OMX events"); + ret = -ENOMEM; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/*========================================================*/ +/* @ fn SampleTest_EmptyBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + LOG_FUNCTION_NAME; + + OMX_ERRORTYPE eError = OMX_ErrorNone; + + OMXCameraAdapter *oca = (OMXCameraAdapter*)pAppData; + eError = oca->OMXCameraAdapterEmptyBufferDone(hComponent, pBuffHeader); + + LOG_FUNCTION_NAME_EXIT; + return eError; +} + + +/*========================================================*/ +/* @ fn SampleTest_EmptyBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return OMX_ErrorNone; +} + +static void debugShowFPS() +{ + static int mFrameCount = 0; + static int mLastFrameCount = 0; + static nsecs_t mLastFpsTime = 0; + static float mFps = 0; + mFrameCount++; + if (!(mFrameCount & 0x1F)) { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFpsTime; + mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFpsTime = now; + mLastFrameCount = mFrameCount; + LOGD("Camera %d Frames, %f FPS", mFrameCount, mFps); + } + // XXX: mFPS has the value we want +} + +/*========================================================*/ +/* @ fn SampleTest_FillBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + TIUTILS::Message msg; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + if (UNLIKELY(mDebugFps)) { + debugShowFPS(); + } + + OMXCameraAdapter *adapter = ( OMXCameraAdapter * ) pAppData; + if ( NULL != adapter ) + { + msg.command = OMXCameraAdapter::OMXCallbackHandler::CAMERA_FILL_BUFFER_DONE; + msg.arg1 = ( void * ) hComponent; + msg.arg2 = ( void * ) pBuffHeader; + adapter->mOMXCallbackHandler->put(&msg); + } + + return eError; +} + +/*========================================================*/ +/* @ fn SampleTest_FillBufferDone :: Application callback*/ +/*========================================================*/ +OMX_ERRORTYPE OMXCameraAdapter::OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader) +{ + + status_t stat = NO_ERROR; + status_t res1, res2; + OMXCameraPortParameters *pPortParam; + OMX_ERRORTYPE eError = OMX_ErrorNone; + CameraFrame::FrameType typeOfFrame = CameraFrame::ALL_FRAMES; + unsigned int refCount = 0; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + sp<CameraFDResult> fdResult = NULL; + + res1 = res2 = NO_ERROR; + pPortParam = &(mCameraAdapterParameters.mCameraPortParams[pBuffHeader->nOutputPortIndex]); + if (pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW) + { + + if ( ( PREVIEW_ACTIVE & state ) != PREVIEW_ACTIVE ) + { + return OMX_ErrorNone; + } + + recalculateFPS(); + + { + Mutex::Autolock lock(mFaceDetectionLock); + if ( mFaceDetectionRunning ) { + detectFaces(pBuffHeader, fdResult, pPortParam->mWidth, pPortParam->mHeight); + if ( NULL != fdResult.get() ) { + notifyFaceSubscribers(fdResult); + fdResult.clear(); + } + } + } + + stat |= advanceZoom(); + + ///On the fly update to 3A settings not working + if( mPending3Asettings ) + { + apply3Asettings(mParameters3A); + } + + ///Prepare the frames to be sent - initialize CameraFrame object and reference count + CameraFrame cameraFrameVideo, cameraFramePreview; + if ( mRecording ) + { + res1 = initCameraFrame(cameraFrameVideo, + pBuffHeader, + CameraFrame::VIDEO_FRAME_SYNC, + pPortParam); + } + + if( mWaitingForSnapshot ) + { + typeOfFrame = CameraFrame::SNAPSHOT_FRAME; + } + else + { + typeOfFrame = CameraFrame::PREVIEW_FRAME_SYNC; + } + + LOGV("FBD pBuffer = 0x%x", pBuffHeader->pBuffer); + + res2 = initCameraFrame(cameraFramePreview, + pBuffHeader, + typeOfFrame, + pPortParam); + + stat |= res1 | res2; + + if ( mRecording ) + { + res1 = sendFrame(cameraFrameVideo); + } + + if( mWaitingForSnapshot ) + { + mSnapshotCount++; + + if ( ( mSnapshotCount == 1 ) && + ( HIGH_SPEED == mCapMode ) ) + { + notifyShutterSubscribers(); + } + } + + res2 = sendFrame(cameraFramePreview); + + stat |= ( ( NO_ERROR == res1 ) || ( NO_ERROR == res2 ) ) ? ( ( int ) NO_ERROR ) : ( -1 ); + + } + else if( pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT ) + { + typeOfFrame = CameraFrame::FRAME_DATA_SYNC; + CameraFrame cameraFrame; + stat |= initCameraFrame(cameraFrame, + pBuffHeader, + typeOfFrame, + pPortParam); + stat |= sendFrame(cameraFrame); + } + else if( pBuffHeader->nOutputPortIndex == OMX_CAMERA_PORT_IMAGE_OUT_IMAGE ) + { + + if ( OMX_COLOR_FormatUnused == mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex].mColorFormat ) + { + typeOfFrame = CameraFrame::IMAGE_FRAME; + } + else + { + typeOfFrame = CameraFrame::RAW_FRAME; + } + + pPortParam->mImageType = typeOfFrame; + + if((mCapturedFrames>0) && !mCaptureSignalled) + { + mCaptureSignalled = true; + mCaptureSem.Signal(); + } + + if( ( CAPTURE_ACTIVE & state ) != CAPTURE_ACTIVE ) + { + goto EXIT; + } + + { + Mutex::Autolock lock(mBracketingLock); + if ( mBracketingEnabled ) + { + doBracketing(pBuffHeader, typeOfFrame); + return eError; + } + } + + if ( 1 > mCapturedFrames ) + { + goto EXIT; + } + + CAMHAL_LOGDB("Captured Frames: %d", mCapturedFrames); + + mCapturedFrames--; + + CameraFrame cameraFrame; + stat |= initCameraFrame(cameraFrame, + pBuffHeader, + typeOfFrame, + pPortParam); + stat |= sendFrame(cameraFrame); + } + else + { + CAMHAL_LOGEA("Frame received for non-(preview/capture/measure) port. This is yet to be supported"); + goto EXIT; + } + + if ( NO_ERROR != stat ) + { + CAMHAL_LOGDB("sendFrameToSubscribers error: %d", stat); + returnFrame(pBuffHeader->pBuffer, typeOfFrame); + } + + return eError; + + EXIT: + + CAMHAL_LOGEB("Exiting function %s because of ret %d eError=%x", __FUNCTION__, stat, eError); + + if ( NO_ERROR != stat ) + { + if ( NULL != mErrorNotifier ) + { + mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN); + } + } + + return eError; +} + +status_t OMXCameraAdapter::recalculateFPS() +{ + float currentFPS; + + mFrameCount++; + + if ( ( mFrameCount % FPS_PERIOD ) == 0 ) + { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFPSTime; + currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFPSTime = now; + mLastFrameCount = mFrameCount; + + if ( 1 == mIter ) + { + mFPS = currentFPS; + } + else + { + //cumulative moving average + mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter; + } + + mLastFPS = mFPS; + mIter++; + } + + return NO_ERROR; +} + +status_t OMXCameraAdapter::sendFrame(CameraFrame &frame) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + + if ( NO_ERROR == ret ) + { + ret = sendFrameToSubscribers(&frame); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::initCameraFrame( CameraFrame &frame, + OMX_IN OMX_BUFFERHEADERTYPE *pBuffHeader, + int typeOfFrame, + OMXCameraPortParameters *port) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NULL == port) + { + CAMHAL_LOGEA("Invalid portParam"); + return -EINVAL; + } + + if ( NULL == pBuffHeader ) + { + CAMHAL_LOGEA("Invalid Buffer header"); + return -EINVAL; + } + + frame.mFrameType = typeOfFrame; + frame.mBuffer = pBuffHeader->pBuffer; + frame.mLength = pBuffHeader->nFilledLen; + frame.mAlignment = port->mStride; + frame.mOffset = pBuffHeader->nOffset; + frame.mWidth = port->mWidth; + frame.mHeight = port->mHeight; + + // Calculating the time source delta of Ducati & system time only once at the start of camera. + // It's seen that there is a one-time constant diff between the ducati source clock & + // System monotonic timer, although both derived from the same 32KHz clock. + // This delta is offsetted to/from ducati timestamp to match with system time so that + // video timestamps are aligned with Audio with a periodic timestamp intervals. + if ( onlyOnce ) + { + mTimeSourceDelta = (pBuffHeader->nTimeStamp * 1000) - systemTime(SYSTEM_TIME_MONOTONIC); + onlyOnce = false; + } + + // Calculating the new video timestamp based on offset from ducati source. + frame.mTimestamp = (pBuffHeader->nTimeStamp * 1000) - mTimeSourceDelta; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +bool OMXCameraAdapter::CommandHandler::Handler() +{ + TIUTILS::Message msg; + volatile int forever = 1; + status_t stat; + ErrorNotifier *errorNotify = NULL; + + LOG_FUNCTION_NAME; + + while ( forever ) + { + stat = NO_ERROR; + CAMHAL_LOGDA("Handler: waiting for messsage..."); + TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1); + mCommandMsgQ.get(&msg); + CAMHAL_LOGDB("msg.command = %d", msg.command); + switch ( msg.command ) { + case CommandHandler::CAMERA_START_IMAGE_CAPTURE: + { + stat = mCameraAdapter->startImageCapture(); + break; + } + case CommandHandler::CAMERA_PERFORM_AUTOFOCUS: + { + stat = mCameraAdapter->doAutoFocus(); + break; + } + case CommandHandler::COMMAND_EXIT: + { + CAMHAL_LOGEA("Exiting command handler"); + forever = 0; + break; + } + } + + if ( NO_ERROR != stat ) + { + errorNotify = ( ErrorNotifier * ) msg.arg1; + if ( NULL != errorNotify ) + { + errorNotify->errorNotify(CAMERA_ERROR_UNKNOWN); + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return false; +} + +bool OMXCameraAdapter::OMXCallbackHandler::Handler() +{ + TIUTILS::Message msg; + volatile int forever = 1; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + while(forever){ + TIUTILS::MessageQueue::waitForMsg(&mCommandMsgQ, NULL, NULL, -1); + mCommandMsgQ.get(&msg); + switch ( msg.command ) { + case OMXCallbackHandler::CAMERA_FILL_BUFFER_DONE: + { + ret = mCameraAdapter->OMXCameraAdapterFillBufferDone(( OMX_HANDLETYPE ) msg.arg1, + ( OMX_BUFFERHEADERTYPE *) msg.arg2); + break; + } + case CommandHandler::COMMAND_EXIT: + { + CAMHAL_LOGEA("Exiting OMX callback handler"); + forever = 0; + break; + } + } + } + + LOG_FUNCTION_NAME_EXIT; + return false; +} + +OMXCameraAdapter::OMXCameraAdapter():mComponentState (OMX_StateInvalid) +{ + LOG_FUNCTION_NAME; + + mPictureRotation = 0; + // Initial values + mTimeSourceDelta = 0; + onlyOnce = true; + + mDoAFSem.Create(0); + mInitSem.Create(0); + mFlushSem.Create(0); + mUsePreviewDataSem.Create(0); + mUsePreviewSem.Create(0); + mUseCaptureSem.Create(0); + mStartPreviewSem.Create(0); + mStopPreviewSem.Create(0); + mStartCaptureSem.Create(0); + mStopCaptureSem.Create(0); + mSwitchToLoadedSem.Create(0); + mCaptureSem.Create(0); + + mCameraAdapterParameters.mHandleComp = 0; + + LOG_FUNCTION_NAME_EXIT; +} + +OMXCameraAdapter::~OMXCameraAdapter() +{ + LOG_FUNCTION_NAME; + + //Return to OMX Loaded state + switchToLoaded(); + + ///Free the handle for the Camera component + if(mCameraAdapterParameters.mHandleComp) + { + OMX_FreeHandle(mCameraAdapterParameters.mHandleComp); + } + + ///De-init the OMX + if( (mComponentState==OMX_StateLoaded) || (mComponentState==OMX_StateInvalid)) + { + OMX_Deinit(); + } + + //Exit and free ref to command handling thread + if ( NULL != mCommandHandler.get() ) + { + TIUTILS::Message msg; + msg.command = CommandHandler::COMMAND_EXIT; + msg.arg1 = mErrorNotifier; + mCommandHandler->put(&msg); + mCommandHandler->requestExitAndWait(); + mCommandHandler.clear(); + } + + //Exit and free ref to callback handling thread + if ( NULL != mOMXCallbackHandler.get() ) + { + TIUTILS::Message msg; + msg.command = OMXCallbackHandler::COMMAND_EXIT; + mOMXCallbackHandler->put(&msg); + mOMXCallbackHandler->requestExitAndWait(); + mOMXCallbackHandler.clear(); + } + + gCameraAdapter = NULL; + + LOG_FUNCTION_NAME_EXIT; +} + +extern "C" CameraAdapter* CameraAdapter_Factory() +{ + Mutex::Autolock lock(gAdapterLock); + + LOG_FUNCTION_NAME; + + if ( NULL == gCameraAdapter ) + { + CAMHAL_LOGDA("Creating new Camera adapter instance"); + gCameraAdapter= new OMXCameraAdapter(); + } + else + { + CAMHAL_LOGDA("Reusing existing Camera adapter instance"); + } + + LOG_FUNCTION_NAME_EXIT; + + return gCameraAdapter; +} + +extern "C" int CameraAdapter_Capabilities(CameraProperties::Properties* properties_array, + const unsigned int starting_camera, + const unsigned int max_camera) { + int num_cameras_supported = 0; + CameraProperties::Properties* properties = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_HANDLETYPE handle = NULL; + OMX_TI_CAPTYPE caps; + + LOG_FUNCTION_NAME; + + if (!properties_array) { + CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array); + LOG_FUNCTION_NAME_EXIT; + return -EINVAL; + } + + // OMX_Init + eError = OMX_Init(); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_Init -0x%x", eError); + return 0; // no cameras supported + } + + // Setup key parameters to send to Ducati during init + OMX_CALLBACKTYPE oCallbacks; + + // Initialize the callback handles + oCallbacks.EventHandler = android::OMXCameraAdapterEventHandler; + oCallbacks.EmptyBufferDone = android::OMXCameraAdapterEmptyBufferDone; + oCallbacks.FillBufferDone = android::OMXCameraAdapterFillBufferDone; + + // Get Handle + eError = OMX_GetHandle(&handle, (OMX_STRING)"OMX.TI.DUCATI1.VIDEO.CAMERA", NULL, &oCallbacks); + if (eError != OMX_ErrorNone) { + CAMHAL_LOGEB("OMX_GetHandle -0x%x", eError); + goto EXIT; + } + + // Continue selecting sensor and then querying OMX Camera for it's capabilities + // When sensor select returns an error, we know to break and stop + while (eError == OMX_ErrorNone && + (starting_camera + num_cameras_supported) < max_camera) { + // sensor select + OMX_CONFIG_SENSORSELECTTYPE sensorSelect; + OMX_INIT_STRUCT_PTR (&sensorSelect, OMX_CONFIG_SENSORSELECTTYPE); + sensorSelect.eSensor = (OMX_SENSORSELECT) num_cameras_supported; + eError = OMX_SetConfig(handle, ( OMX_INDEXTYPE ) OMX_TI_IndexConfigSensorSelect, &sensorSelect); + + if ( OMX_ErrorNone != eError ) { + break; + } + + // get and fill capabilities + properties = properties_array + starting_camera + num_cameras_supported; + OMXCameraAdapter::getCaps(properties, handle); + + // need to fill facing information + // assume that only sensor 0 is back facing + if (num_cameras_supported == 0) { + properties->set(CameraProperties::FACING_INDEX, TICameraParameters::FACING_BACK); + } else { + properties->set(CameraProperties::FACING_INDEX, TICameraParameters::FACING_FRONT); + } + + num_cameras_supported++; + } + + EXIT: + // clean up + if(handle) { + OMX_FreeHandle(handle); + } + OMX_Deinit(); + + LOG_FUNCTION_NAME_EXIT; + + return num_cameras_supported; +} + +}; + + +/*--------------------Camera Adapter Class ENDS here-----------------------------*/ + diff --git a/camera/OMXCameraAdapter/OMXCapabilities.cpp b/camera/OMXCameraAdapter/OMXCapabilities.cpp new file mode 100644 index 0000000..fc961fa --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCapabilities.cpp @@ -0,0 +1,1181 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXCap.cpp +* +* This file implements the OMX Capabilities feature. +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include "ErrorUtils.h" +#include "TICameraParameters.h" + +extern "C" { +#include "memmgr.h" +} + +namespace android { + +#undef LOG_TAG + +// Maintain a separate tag for OMXCameraAdapter logs to isolate issues OMX specific +#define LOG_TAG "CameraHAL" + +/************************************ + * global constants and variables + *************************************/ + +#define ARRAY_SIZE(array) (sizeof((array)) / sizeof((array)[0])) +#define FPS_MIN 5 +#define FPS_STEP 5 +#define FPS_RANGE_STEP 10 + +static const char PARAM_SEP[] = ","; +static const int PARAM_SEP_CHAR = ','; +static const uint32_t VFR_OFFSET = 8; +static const char VFR_BACKET_START[] = "("; +static const char VFR_BRACKET_END[] = ")"; +static const char FRAMERATE_COUNT = 10; + +/**** look up tables to translate OMX Caps to Parameter ****/ + +const CapResolution OMXCameraAdapter::mImageCapRes [] = { + { 4032, 3024, "4032x3024" }, + { 4000, 3000, "4000x3000" }, + { 3648, 2736, "3648x2736" }, + { 3264, 2448, "3264x2448" }, + { 2592, 1944, "2592x1944" }, + { 2048, 1536, "2048x1536" }, + { 1600, 1200, "1600x1200" }, + { 1280, 1024, "1280x1024" }, + { 1152, 864, "1152x864" }, + { 1280, 960, "1280x960" }, + { 640, 480, "640x480" }, + { 320, 240, "320x240" }, +}; + +const CapResolution OMXCameraAdapter::mPreviewRes [] = { + { 1920, 1080, "1920x1080" }, + { 1280, 720, "1280x720" }, + { 800, 480, "800x480" }, + { 720, 576, "720x576" }, + { 720, 480, "720x480" }, + { 768, 576, "768x576" }, + { 640, 480, "640x480" }, + { 320, 240, "320x240" }, + { 352, 288, "352x288" }, + { 240, 160, "240x160" }, + { 176, 144, "176x144" }, + { 128, 96, "128x96" }, +}; + +const CapResolution OMXCameraAdapter::mThumbRes [] = { + { 640, 480, "640x480" }, + { 160, 120, "160x120" }, + { 200, 120, "200x120" }, + { 320, 240, "320x240" }, + { 512, 384, "512x384" }, + { 352, 144, "352x144" }, + { 176, 144, "176x144" }, + { 96, 96, "96x96" }, +}; + +const CapPixelformat OMXCameraAdapter::mPixelformats [] = { + { OMX_COLOR_FormatCbYCrY, CameraParameters::PIXEL_FORMAT_YUV422I }, + { OMX_COLOR_FormatYUV420SemiPlanar, CameraParameters::PIXEL_FORMAT_YUV420SP }, + { OMX_COLOR_Format16bitRGB565, CameraParameters::PIXEL_FORMAT_RGB565 }, + { OMX_COLOR_FormatRawBayer10bit, TICameraParameters::PIXEL_FORMAT_RAW }, +}; + +const CapFramerate OMXCameraAdapter::mFramerates [] = { + { 30, "30" }, + { 25, "25" }, + { 24, "24" }, + { 20, "20" }, + { 15, "15" }, + { 10, "10" }, +}; + +const CapZoom OMXCameraAdapter::mZoomStages [] = { + { 65536, "100" }, + { 68157, "104" }, + { 70124, "107" }, + { 72745, "111" }, + { 75366, "115" }, + { 77988, "119" }, + { 80609, "123" }, + { 83231, "127" }, + { 86508, "132" }, + { 89784, "137" }, + { 92406, "141" }, + { 95683, "146" }, + { 99615, "152" }, + { 102892, "157" }, + { 106168, "162" }, + { 110100, "168" }, + { 114033, "174" }, + { 117965, "180" }, + { 122552, "187" }, + { 126484, "193" }, + { 131072, "200" }, + { 135660, "207" }, + { 140247, "214" }, + { 145490, "222" }, + { 150733, "230" }, + { 155976, "238" }, + { 161219, "246" }, + { 167117, "255" }, + { 173015, "264" }, + { 178913, "273" }, + { 185467, "283" }, + { 192020, "293" }, + { 198574, "303" }, + { 205783, "314" }, + { 212992, "325" }, + { 220201, "336" }, + { 228065, "348" }, + { 236585, "361" }, + { 244449, "373" }, + { 252969, "386" }, + { 262144, "400" }, + { 271319, "414" }, + { 281149, "429" }, + { 290980, "444" }, + { 300810, "459" }, + { 311951, "476" }, + { 322437, "492" }, + { 334234, "510" }, + { 346030, "528" }, + { 357827, "546" }, + { 370934, "566" }, + { 384041, "586" }, + { 397148, "606" }, + { 411566, "628" }, + { 425984, "650" }, + { 441057, "673" }, + { 456131, "696" }, + { 472515, "721" }, + { 488899, "746" }, + { 506593, "773" }, + { 524288, "800" }, +}; + +const CapISO OMXCameraAdapter::mISOStages [] = { + { 0, "auto" }, + { 100, "100" }, + { 200, "200"}, + { 400, "400" }, + { 800, "800" }, + { 1000, "1000" }, + { 1200, "1200" }, + { 1600, "1600" }, +}; + +// mapped values have to match with new_sensor_MSP.h +const CapU32 OMXCameraAdapter::mSensorNames [] = { + { 300, "IMX060" }, + { 301, "OV5650" }, + { 305, "S5K4E1GA"}, + { 306, "S5K6A1GX03" } + // TODO(XXX): need to account for S3D camera later +}; + +/************************************ + * static helper functions + *************************************/ + +// utility function to remove last seperator +void remove_last_sep(char* buffer) { + char* last_sep = NULL; + last_sep = strrchr(buffer, PARAM_SEP_CHAR); + if (last_sep != NULL) { + last_sep[0] = '\0'; + } +} + + +/***************************************** + * internal static function declarations + *****************************************/ + +/**** Utility functions to help translate OMX Caps to Parameter ****/ + +status_t OMXCameraAdapter::encodePixelformatCap(OMX_COLOR_FORMATTYPE format, + const CapPixelformat *cap, + size_t capCount, + char * buffer, + size_t bufferSize) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( ( NULL == buffer ) || ( NULL == cap ) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( format == cap[i].pixelformat ) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFramerateCap(OMX_U32 framerateMax, + OMX_U32 framerateMin, + const CapFramerate *cap, + size_t capCount, + char * buffer, + size_t bufferSize) { + status_t ret = NO_ERROR; + bool minInserted = false; + bool maxInserted = false; + char tmpBuffer[FRAMERATE_COUNT]; + + LOG_FUNCTION_NAME; + + if ( ( NULL == buffer ) || ( NULL == cap ) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( (framerateMax >= cap[i].num) && (framerateMin <= cap[i].num) ) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + + if ( cap[i].num == framerateMin ) { + minInserted = true; + } + } + if ( cap[i].num == framerateMax ) { + maxInserted = true; + } + } + + if ( !maxInserted ) { + memset(tmpBuffer, 0, FRAMERATE_COUNT); + snprintf(tmpBuffer, FRAMERATE_COUNT - 1, "%u,", ( unsigned int ) framerateMax); + strncat(buffer, tmpBuffer, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + + if ( !minInserted ) { + memset(tmpBuffer, 0, FRAMERATE_COUNT); + snprintf(tmpBuffer, FRAMERATE_COUNT - 1, "%u,", ( unsigned int ) framerateMin); + strncat(buffer, tmpBuffer, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + + remove_last_sep(buffer); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeVFramerateCap(OMX_TI_CAPTYPE &caps, + char *buffer, + char *defaultRange, + size_t bufferSize) { + status_t ret = NO_ERROR; + uint32_t minVFR, maxVFR; + char tmpBuffer[MAX_PROP_VALUE_LENGTH]; + bool skipLast = false; + uint32_t min, max; + + LOG_FUNCTION_NAME; + + if ( NULL == buffer ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + if(caps.ulPrvVarFPSModesCount < 1) { + return NO_ERROR; + } + + // Assumption: last range in tPrvVarFPSModes will be for S30FPSHD mode + minVFR = caps.tPrvVarFPSModes[caps.ulPrvVarFPSModesCount-1].nVarFPSMin >> VFR_OFFSET; + maxVFR = caps.tPrvVarFPSModes[caps.ulPrvVarFPSModesCount-1].nVarFPSMax >> VFR_OFFSET; + + if (minVFR < FPS_MIN) { + minVFR = FPS_MIN; + } + + memset(tmpBuffer, '\0', MAX_PROP_VALUE_LENGTH); + min = max = 0; + for (unsigned int i = minVFR; i <= maxVFR; i += FPS_STEP) { + + min = i * CameraHal::VFR_SCALE; + max = (i + FPS_RANGE_STEP) * CameraHal::VFR_SCALE; + + snprintf(tmpBuffer, ( MAX_PROP_VALUE_LENGTH - 1 ), "(%d,%d)", min, min); + strncat(buffer, tmpBuffer, ( bufferSize - 1 )); + strncat(buffer, PARAM_SEP, bufferSize - 1); + + if (max <= maxVFR * CameraHal::VFR_SCALE) { + snprintf(tmpBuffer, ( MAX_PROP_VALUE_LENGTH - 1 ), "(%d,%d)", min, max); + strncat(buffer, tmpBuffer, ( bufferSize - 1 )); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + } + remove_last_sep(buffer); + + if ( 1 < strlen(tmpBuffer) ) { + snprintf(defaultRange, ( MAX_PROP_VALUE_LENGTH - 1 ), "%d,%d", min, min); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +size_t OMXCameraAdapter::encodeZoomCap(OMX_S32 maxZoom, + const CapZoom *cap, + size_t capCount, + char * buffer, + size_t bufferSize) { + status_t res = NO_ERROR; + size_t ret = 0; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( cap[i].num <= maxZoom ) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + ret++; + } + } + remove_last_sep(buffer); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeISOCap(OMX_U32 maxISO, + const CapISO *cap, + size_t capCount, + char * buffer, + size_t bufferSize) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0; i < capCount; i++ ) { + if ( cap[i].num <= maxISO) { + strncat(buffer, cap[i].param, bufferSize - 1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + } + remove_last_sep(buffer); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeSizeCap(OMX_TI_CAPRESTYPE &res, + const CapResolution *cap, + size_t capCount, + char * buffer, + size_t bufferSize) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( (NULL == buffer) || (NULL == cap) ) { + CAMHAL_LOGEA("Invalid input arguments"); + return -EINVAL; + } + + for ( unsigned int i = 0 ; i < capCount ; i++ ) { + if ( (cap[i].width <= res.nWidthMax) && + (cap[i].height <= res.nHeightMax) && + (cap[i].width >= res.nWidthMin) && + (cap[i].height >= res.nHeightMin) ) { + strncat(buffer, cap[i].param, bufferSize -1); + strncat(buffer, PARAM_SEP, bufferSize - 1); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::insertImageSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeSizeCap(caps.tImageResRange, + mImageCapRes, + ARRAY_SIZE(mImageCapRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture sizes 0x%x", ret); + } else { + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_PICTURE_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertPreviewSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeSizeCap(caps.tPreviewResRange, + mPreviewRes, + ARRAY_SIZE(mPreviewRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview sizes 0x%x", ret); + } else { + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_PREVIEW_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertThumbSizes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeSizeCap(caps.tThumbResRange, + mThumbRes, + ARRAY_SIZE(mThumbRes), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported thumbnail sizes 0x%x", ret); + } else { + //CTS Requirement: 0x0 should always be supported + strncat(supported, "0x0", MAX_PROP_NAME_LENGTH); + params->set(CameraProperties::SUPPORTED_THUMBNAIL_SIZES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertZoomStages(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) +{ + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + size_t zoomStageCount = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + zoomStageCount = encodeZoomCap(caps.xMaxWidthZoom, + mZoomStages, + ARRAY_SIZE(mZoomStages), + supported, + MAX_PROP_VALUE_LENGTH); + + params->set(CameraProperties::SUPPORTED_ZOOM_RATIOS, supported); + params->set(CameraProperties::SUPPORTED_ZOOM_STAGES, zoomStageCount - 1); //As per CTS requirement + + if ( 0 == zoomStageCount ) { + params->set(CameraProperties::ZOOM_SUPPORTED, TICameraParameters::ZOOM_UNSUPPORTED); + params->set(CameraProperties::SMOOTH_ZOOM_SUPPORTED, TICameraParameters::ZOOM_UNSUPPORTED); + } else { + params->set(CameraProperties::ZOOM_SUPPORTED, TICameraParameters::ZOOM_SUPPORTED); + params->set(CameraProperties::SMOOTH_ZOOM_SUPPORTED, TICameraParameters::ZOOM_SUPPORTED); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertImageFormats(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( int i = 0 ; i < caps.ulImageFormatCount ; i++ ) { + ret = encodePixelformatCap(caps.eImageFormats[i], + mPixelformats, + ARRAY_SIZE(mPixelformats), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported picture formats 0x%x", ret); + break; + } + } + + if ( NO_ERROR == ret ) { + //jpeg is not supported in OMX capabilies yet + strncat(supported, CameraParameters::PIXEL_FORMAT_JPEG, MAX_PROP_VALUE_LENGTH - 1); + params->set(CameraProperties::SUPPORTED_PICTURE_FORMATS, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertPreviewFormats(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( int i = 0 ; i < caps.ulPreviewFormatCount; i++ ) { + ret = encodePixelformatCap(caps.ePreviewFormats[i], + mPixelformats, + ARRAY_SIZE(mPixelformats), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview formats 0x%x", ret); + break; + } + } + + if ( NO_ERROR == ret ) { + // need to advertise we support YV12 format + // We will program preview port with NV21 when we see application set YV12 + strncat(supported, CameraParameters::PIXEL_FORMAT_YUV420P, MAX_PROP_VALUE_LENGTH - 1); + params->set(CameraProperties::SUPPORTED_PREVIEW_FORMATS, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertFramerates(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeFramerateCap(caps.xFramerateMax >> VFR_OFFSET, + caps.xFramerateMin >> VFR_OFFSET, + mFramerates, + ARRAY_SIZE(mFramerates), + supported, + MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview framerates 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_PREVIEW_FRAME_RATES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertVFramerates(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + char defaultRange[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeVFramerateCap(caps, supported, defaultRange, MAX_PROP_VALUE_LENGTH); + + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported preview framerate ranges 0x%x", ret); + } else { + params->set(CameraProperties::FRAMERATE_RANGE_SUPPORTED, supported); + CAMHAL_LOGDB("framerate ranges %s", supported); + params->set(CameraProperties::FRAMERATE_RANGE, defaultRange); + CAMHAL_LOGDB("Default framerate range: [%s]", defaultRange); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertEVs(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.xEVCompensationMin * 10 )); + params->set(CameraProperties::SUPPORTED_EV_MIN, supported); + + snprintf(supported, MAX_PROP_VALUE_LENGTH, "%d", ( int ) ( caps.xEVCompensationMax * 10 )); + params->set(CameraProperties::SUPPORTED_EV_MAX, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertISOModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + ret = encodeISOCap(caps.nSensitivityMax, + mISOStages, + ARRAY_SIZE(mISOStages), + supported, + MAX_PROP_VALUE_LENGTH); + if ( NO_ERROR != ret ) { + CAMHAL_LOGEB("Error inserting supported ISO modes 0x%x", ret); + } else { + params->set(CameraProperties::SUPPORTED_ISO_VALUES, supported); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertIPPModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + //Off is always supported + strncat(supported, TICameraParameters::IPP_NONE, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + + if ( caps.bLensDistortionCorrectionSupported ) { + strncat(supported, TICameraParameters::IPP_LDC, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + + if ( caps.bISONoiseFilterSupported ) { + strncat(supported, TICameraParameters::IPP_NSF, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + + if ( caps.bISONoiseFilterSupported && caps.bLensDistortionCorrectionSupported ) { + strncat(supported, TICameraParameters::IPP_LDCNSF, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_IPP_MODES, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertWBModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulWhiteBalanceCount ; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eWhiteBalanceModes[i], WBalLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + //These modes are not supported by the capability feature + strncat(supported, TICameraParameters::WHITE_BALANCE_FACE, MAX_PROP_NAME_LENGTH); + + params->set(CameraProperties::SUPPORTED_WHITE_BALANCE, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertEffects(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulColorEffectCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eColorEffects[i], EffLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_EFFECTS, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertExpModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulExposureModeCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eExposureModes[i], ExpLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + //These modes are not supported by the capability feature + strncat(supported, TICameraParameters::EXPOSURE_MODE_FACE, MAX_PROP_NAME_LENGTH); + + params->set(CameraProperties::SUPPORTED_EXPOSURE_MODES, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertFlashModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulFlashCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eFlashModes[i], FlashLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_FLASH_MODES, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertSceneModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulSceneCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eSceneModes[i], SceneLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_SCENE_MODES, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertFocusModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulFocusModeCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eFocusModes[i], FocusLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + + // Check if focus is supported by camera + if (caps.ulFocusModeCount == 1 && + caps.eFocusModes[0] == OMX_IMAGE_FocusControlOff) { + // Focus is not supported by camera + // Advertise this to app as infinitiy focus mode + strncat(supported, CameraParameters::FOCUS_MODE_INFINITY, MAX_PROP_NAME_LENGTH); + } else { + // Focus is supported but these modes are not supported by the + // capability feature. Apply manually + strncat(supported, TICameraParameters::FOCUS_MODE_FACE, MAX_PROP_NAME_LENGTH); + } + + params->set(CameraProperties::SUPPORTED_FOCUS_MODES, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertFlickerModes(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + for ( unsigned int i = 0 ; i < caps.ulFlickerCount; i++ ) { + p = getLUTvalue_OMXtoHAL(caps.eFlicker[i], FlickerLUT); + if ( NULL != p ) { + strncat(supported, p, MAX_PROP_NAME_LENGTH); + strncat(supported, PARAM_SEP, 1); + } + } + remove_last_sep(supported); + params->set(CameraProperties::SUPPORTED_ANTIBANDING, supported); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertLocks(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME + + params->set(CameraProperties::AUTO_EXPOSURE_LOCK_SUPPORTED, DEFAULT_LOCK_SUPPORTED); + params->set(CameraProperties::AUTO_WHITEBALANCE_LOCK_SUPPORTED, DEFAULT_LOCK_SUPPORTED); + + LOG_FUNCTION_NAME + + return ret; +} + +status_t OMXCameraAdapter::insertDefaults(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + + LOG_FUNCTION_NAME; + + params->set(CameraProperties::ANTIBANDING, DEFAULT_ANTIBANDING); + params->set(CameraProperties::BRIGHTNESS, DEFAULT_BRIGHTNESS); + params->set(CameraProperties::CONTRAST, DEFAULT_CONTRAST); + params->set(CameraProperties::EFFECT, DEFAULT_EFFECT); + params->set(CameraProperties::EV_COMPENSATION, DEFAULT_EV_COMPENSATION); + params->set(CameraProperties::SUPPORTED_EV_STEP, DEFAULT_EV_STEP); + params->set(CameraProperties::EXPOSURE_MODE, DEFAULT_EXPOSURE_MODE); + params->set(CameraProperties::FLASH_MODE, DEFAULT_FLASH_MODE); + params->set(CameraProperties::FOCUS_MODE, DEFAULT_FOCUS_MODE); + params->set(CameraProperties::IPP, DEFAULT_IPP); + params->set(CameraProperties::ISO_MODE, DEFAULT_ISO_MODE); + params->set(CameraProperties::JPEG_QUALITY, DEFAULT_JPEG_QUALITY); + params->set(CameraProperties::JPEG_THUMBNAIL_QUALITY, DEFAULT_THUMBNAIL_QUALITY); + params->set(CameraProperties::JPEG_THUMBNAIL_SIZE, DEFAULT_THUMBNAIL_SIZE); + params->set(CameraProperties::PICTURE_FORMAT, DEFAULT_PICTURE_FORMAT); + params->set(CameraProperties::PICTURE_SIZE, DEFAULT_PICTURE_SIZE); + params->set(CameraProperties::PREVIEW_FORMAT, DEFAULT_PREVIEW_FORMAT); + params->set(CameraProperties::PREVIEW_FRAME_RATE, DEFAULT_FRAMERATE); + params->set(CameraProperties::PREVIEW_SIZE, DEFAULT_PREVIEW_SIZE); + params->set(CameraProperties::REQUIRED_PREVIEW_BUFS, DEFAULT_NUM_PREV_BUFS); + params->set(CameraProperties::REQUIRED_IMAGE_BUFS, DEFAULT_NUM_PIC_BUFS); + params->set(CameraProperties::MAX_FOCUS_AREAS, DEFAULT_MAX_FOCUS_AREAS); + params->set(CameraProperties::SATURATION, DEFAULT_SATURATION); + params->set(CameraProperties::SCENE_MODE, DEFAULT_SCENE_MODE); + params->set(CameraProperties::SHARPNESS, DEFAULT_SHARPNESS); + params->set(CameraProperties::VSTAB, DEFAULT_VSTAB); + params->set(CameraProperties::WHITEBALANCE, DEFAULT_WB); + params->set(CameraProperties::ZOOM, DEFAULT_ZOOM); + params->set(CameraProperties::MAX_FD_HW_FACES, DEFAULT_MAX_FD_HW_FACES); + params->set(CameraProperties::MAX_FD_SW_FACES, DEFAULT_MAX_FD_SW_FACES); + params->set(CameraProperties::AUTO_EXPOSURE_LOCK, DEFAULT_AE_LOCK); + params->set(CameraProperties::AUTO_WHITEBALANCE_LOCK, DEFAULT_AWB_LOCK); + params->set(CameraProperties::MAX_NUM_METERING_AREAS, DEFAULT_MAX_NUM_METERING_AREAS); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertSenMount(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + const char *p; + int i = 0; + + LOG_FUNCTION_NAME; + + memset(supported, '\0', MAX_PROP_VALUE_LENGTH); + + // 1) Look up and assign sensor name + for (i = 0; i < ARRAY_SIZE(mSensorNames); i++) { + if(mSensorNames[i].num == caps.tSenMounting.nSenId) { + // sensor found + break; + } + } + if ( i == ARRAY_SIZE(mSensorNames) ) { + p = "UNKNOWN_SENSOR"; + } else { + p = mSensorNames[i].param; + } + strncat(supported, p, MAX_PROP_NAME_LENGTH); + params->set(CameraProperties::CAMERA_NAME, supported); + + // 2) Assign mounting rotation + params->set(CameraProperties::ORIENTATION_INDEX, caps.tSenMounting.nRotation); + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::insertCapabilities(CameraProperties::Properties* params, OMX_TI_CAPTYPE &caps) { + status_t ret = NO_ERROR; + char supported[MAX_PROP_VALUE_LENGTH]; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) { + ret = insertImageSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertPreviewSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertThumbSizes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertZoomStages(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertImageFormats(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertPreviewFormats(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFramerates(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertVFramerates(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertEVs(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertISOModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertIPPModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertWBModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertEffects(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertExpModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFlashModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertSceneModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFocusModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertFlickerModes(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertSenMount(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertLocks(params, caps); + } + + if ( NO_ERROR == ret ) { + ret = insertDefaults(params, caps); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +/***************************************** + * public exposed function declarations + *****************************************/ + +status_t OMXCameraAdapter::getCaps(CameraProperties::Properties* params, OMX_HANDLETYPE handle) { + status_t ret = NO_ERROR; + int caps_size = 0; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CAPTYPE** caps = NULL;; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + MemoryManager memMgr; + + LOG_FUNCTION_NAME; + + // allocate tiler (or ion) buffer for caps + caps_size = sizeof(OMX_TI_CAPTYPE); + caps = (OMX_TI_CAPTYPE**) memMgr.allocateBuffer(0, 0, NULL, caps_size, 1); + + if (!caps) { + CAMHAL_LOGEB("Error allocating buffer for caps %d", eError); + ret = -ENOMEM; + goto EXIT; + } + + // initialize structures to be passed to OMX Camera + OMX_INIT_STRUCT_PTR (caps[0], OMX_TI_CAPTYPE); + caps[0]->nPortIndex = OMX_ALL; + + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + sharedBuffer.nPortIndex = OMX_ALL; + sharedBuffer.nSharedBuffSize = caps_size; + sharedBuffer.pSharedBuff = (OMX_U8 *) caps[0]; + + // Get capabilities from OMX Camera + eError = OMX_GetConfig(handle, (OMX_INDEXTYPE) OMX_TI_IndexConfigCamCapabilities, &sharedBuffer); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGEB("Error during capabilities query 0x%x", eError); + ret = UNKNOWN_ERROR; + goto EXIT; + } else { + CAMHAL_LOGDA("OMX capability query success"); + } + + // Translate and insert Ducati capabilities to CameraProperties + if ( NO_ERROR == ret ) { + ret = insertCapabilities(params, *caps[0]); + } + + CAMHAL_LOGDB("sen mount id=%u", (unsigned int)caps[0]->tSenMounting.nSenId); + + + EXIT: + if (caps) { + memMgr.freeBuffer((void*) caps); + caps = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +}; + diff --git a/camera/OMXCameraAdapter/OMXCapture.cpp b/camera/OMXCameraAdapter/OMXCapture.cpp new file mode 100644 index 0000000..42fb384 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXCapture.cpp @@ -0,0 +1,1066 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXCapture.cpp +* +* This file contains functionality for handling image capture. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace android { + +status_t OMXCameraAdapter::setParametersCapture(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *str = NULL; + int w, h; + OMX_COLOR_FORMATTYPE pixFormat; + const char *valstr = NULL; + bool updateImagePortParams = false; + + LOG_FUNCTION_NAME; + + OMXCameraPortParameters *cap; + cap = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + params.getPictureSize(&w, &h); + + if ( ( w != ( int ) cap->mWidth ) || + ( h != ( int ) cap->mHeight ) ) + { + updateImagePortParams = true; + } + + cap->mWidth = w; + cap->mHeight = h; + //TODO: Support more pixelformats + cap->mStride = 2; + + CAMHAL_LOGVB("Image: cap.mWidth = %d", (int)cap->mWidth); + CAMHAL_LOGVB("Image: cap.mHeight = %d", (int)cap->mHeight); + + if ( (valstr = params.getPictureFormat()) != NULL ) + { + if (strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV422I) == 0) + { + CAMHAL_LOGDA("CbYCrY format selected"); + pixFormat = OMX_COLOR_FormatCbYCrY; + } + else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) + { + CAMHAL_LOGDA("YUV420SP format selected"); + pixFormat = OMX_COLOR_FormatYUV420SemiPlanar; + } + else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_RGB565) == 0) + { + CAMHAL_LOGDA("RGB565 format selected"); + pixFormat = OMX_COLOR_Format16bitRGB565; + } + else if(strcmp(valstr, (const char *) CameraParameters::PIXEL_FORMAT_JPEG) == 0) + { + CAMHAL_LOGDA("JPEG format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingNone; + } + else if(strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_JPS) == 0) + { + CAMHAL_LOGDA("JPS format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingJPS; + } + else if(strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_MPO) == 0) + { + CAMHAL_LOGDA("MPO format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingMPO; + } + else if(strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_RAW_JPEG) == 0) + { + CAMHAL_LOGDA("RAW + JPEG format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingRAWJPEG; + } + else if(strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_RAW_MPO) == 0) + { + CAMHAL_LOGDA("RAW + MPO format selected"); + pixFormat = OMX_COLOR_FormatUnused; + mCodingMode = CodingRAWMPO; + } + else if(strcmp(valstr, (const char *) TICameraParameters::PIXEL_FORMAT_RAW) == 0) + { + CAMHAL_LOGDA("RAW Picture format selected"); + pixFormat = OMX_COLOR_FormatRawBayer10bit; + } + else + { + CAMHAL_LOGEA("Invalid format, JPEG format selected as default"); + pixFormat = OMX_COLOR_FormatUnused; + } + } + else + { + CAMHAL_LOGEA("Picture format is NULL, defaulting to JPEG"); + pixFormat = OMX_COLOR_FormatUnused; + } + + if ( pixFormat != cap->mColorFormat ) + { + updateImagePortParams = true; + cap->mColorFormat = pixFormat; + } + + if ( updateImagePortParams ) + { + if ( ( CAPTURE_ACTIVE & state ) != CAPTURE_ACTIVE ) + { + setFormat(OMX_CAMERA_PORT_IMAGE_OUT_IMAGE, *cap); + } + } + + str = params.get(TICameraParameters::KEY_EXP_BRACKETING_RANGE); + if ( NULL != str ) { + parseExpRange(str, mExposureBracketingValues, EXP_BRACKET_RANGE, mExposureBracketingValidEntries); + } else { + mExposureBracketingValidEntries = 0; + } + + if ( params.getInt(CameraParameters::KEY_ROTATION) != -1 ) + { + mPictureRotation = params.getInt(CameraParameters::KEY_ROTATION); + } + else + { + mPictureRotation = 0; + } + + CAMHAL_LOGVB("Picture Rotation set %d", mPictureRotation); + + // Read Sensor Orientation and set it based on perating mode + + if (( params.getInt(TICameraParameters::KEY_SENSOR_ORIENTATION) != -1 ) && (mCapMode == OMXCameraAdapter::VIDEO_MODE)) + { + mSensorOrientation = params.getInt(TICameraParameters::KEY_SENSOR_ORIENTATION); + if (mSensorOrientation == 270 ||mSensorOrientation==90) + { + CAMHAL_LOGEA(" Orientation is 270/90. So setting counter rotation to Ducati"); + mSensorOrientation +=180; + mSensorOrientation%=360; + } + } + else + { + mSensorOrientation = 0; + } + + CAMHAL_LOGVB("Sensor Orientation set : %d", mSensorOrientation); + + if ( params.getInt(TICameraParameters::KEY_BURST) >= 1 ) + { + mBurstFrames = params.getInt(TICameraParameters::KEY_BURST); + } + else + { + mBurstFrames = 1; + } + + CAMHAL_LOGVB("Burst Frames set %d", mBurstFrames); + + if ( ( params.getInt(CameraParameters::KEY_JPEG_QUALITY) >= MIN_JPEG_QUALITY ) && + ( params.getInt(CameraParameters::KEY_JPEG_QUALITY) <= MAX_JPEG_QUALITY ) ) + { + mPictureQuality = params.getInt(CameraParameters::KEY_JPEG_QUALITY); + } + else + { + mPictureQuality = MAX_JPEG_QUALITY; + } + + CAMHAL_LOGVB("Picture Quality set %d", mPictureQuality); + + if ( params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH) >= 0 ) + { + mThumbWidth = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH); + } + else + { + mThumbWidth = DEFAULT_THUMB_WIDTH; + } + + + CAMHAL_LOGVB("Picture Thumb width set %d", mThumbWidth); + + if ( params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT) >= 0 ) + { + mThumbHeight = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT); + } + else + { + mThumbHeight = DEFAULT_THUMB_HEIGHT; + } + + + CAMHAL_LOGVB("Picture Thumb height set %d", mThumbHeight); + + if ( ( params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY) >= MIN_JPEG_QUALITY ) && + ( params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY) <= MAX_JPEG_QUALITY ) ) + { + mThumbQuality = params.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + } + else + { + mThumbQuality = MAX_JPEG_QUALITY; + } + + CAMHAL_LOGDB("Thumbnail Quality set %d", mThumbQuality); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getPictureBufferSize(size_t &length, size_t bufferCount) +{ + status_t ret = NO_ERROR; + OMXCameraPortParameters *imgCaptureData = NULL; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + imgCaptureData->mNumBufs = bufferCount; + ret = setFormat(OMX_CAMERA_PORT_IMAGE_OUT_IMAGE, *imgCaptureData); + if ( ret == NO_ERROR ) + { + length = imgCaptureData->mBufSize; + } + else + { + CAMHAL_LOGEB("setFormat() failed 0x%x", ret); + length = 0; + } + } + + CAMHAL_LOGDB("getPictureBufferSize %d", length); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::parseExpRange(const char *rangeStr, + int * expRange, + size_t count, + size_t &validEntries) +{ + status_t ret = NO_ERROR; + char *ctx, *expVal; + char *tmp = NULL; + size_t i = 0; + + LOG_FUNCTION_NAME; + + if ( NULL == rangeStr ) + { + return -EINVAL; + } + + if ( NULL == expRange ) + { + return -EINVAL; + } + + if ( NO_ERROR == ret ) + { + tmp = ( char * ) malloc( strlen(rangeStr) + 1 ); + + if ( NULL == tmp ) + { + CAMHAL_LOGEA("No resources for temporary buffer"); + return -1; + } + memset(tmp, '\0', strlen(rangeStr) + 1); + + } + + if ( NO_ERROR == ret ) + { + strncpy(tmp, rangeStr, strlen(rangeStr) ); + expVal = strtok_r( (char *) tmp, CameraHal::PARAMS_DELIMITER, &ctx); + + i = 0; + while ( ( NULL != expVal ) && ( i < count ) ) + { + expRange[i] = atoi(expVal); + expVal = strtok_r(NULL, CameraHal::PARAMS_DELIMITER, &ctx); + i++; + } + validEntries = i; + } + + if ( NULL != tmp ) + { + free(tmp); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setExposureBracketing(int *evValues, + size_t evCount, + size_t frameCount) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CAPTUREMODETYPE expCapMode; + OMX_CONFIG_EXTCAPTUREMODETYPE extExpCapMode; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NULL == evValues ) + { + CAMHAL_LOGEA("Exposure compensation values pointer is invalid"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&expCapMode, OMX_CONFIG_CAPTUREMODETYPE); + expCapMode.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + /// If frameCount>0 but evCount<=0, then this is the case of HQ burst. + //Otherwise, it is normal HQ capture + ///If frameCount>0 and evCount>0 then this is the cause of HQ Exposure bracketing. + if ( 0 == evCount && 0 == frameCount ) + { + expCapMode.bFrameLimited = OMX_FALSE; + } + else + { + expCapMode.bFrameLimited = OMX_TRUE; + expCapMode.nFrameLimit = frameCount; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCaptureMode, + &expCapMode); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring capture mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Camera capture mode configured successfully"); + } + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&extExpCapMode, OMX_CONFIG_EXTCAPTUREMODETYPE); + extExpCapMode.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + if ( 0 == evCount ) + { + extExpCapMode.bEnableBracketing = OMX_FALSE; + } + else + { + extExpCapMode.bEnableBracketing = OMX_TRUE; + extExpCapMode.tBracketConfigType.eBracketMode = OMX_BracketExposureRelativeInEV; + extExpCapMode.tBracketConfigType.nNbrBracketingValues = evCount - 1; + } + + for ( unsigned int i = 0 ; i < evCount ; i++ ) + { + extExpCapMode.tBracketConfigType.nBracketValues[i] = ( evValues[i] * ( 1 << Q16_OFFSET ) ) / 10; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigExtCaptureMode, + &extExpCapMode); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring extended capture mode 0x%x", eError); + } + else + { + CAMHAL_LOGDA("Extended camera capture mode configured successfully"); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setShutterCallback(bool enabled) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CALLBACKREQUESTTYPE shutterRequstCallback; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&shutterRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE); + shutterRequstCallback.nPortIndex = OMX_ALL; + + if ( enabled ) + { + shutterRequstCallback.bEnable = OMX_TRUE; + shutterRequstCallback.nIndex = ( OMX_INDEXTYPE ) OMX_TI_IndexConfigShutterCallback; + CAMHAL_LOGDA("Enabling shutter callback"); + } + else + { + shutterRequstCallback.bEnable = OMX_FALSE; + shutterRequstCallback.nIndex = ( OMX_INDEXTYPE ) OMX_TI_IndexConfigShutterCallback; + CAMHAL_LOGDA("Disabling shutter callback"); + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigCallbackRequest, + &shutterRequstCallback); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error registering shutter callback 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDB("Shutter callback for index 0x%x registered successfully", + OMX_TI_IndexConfigShutterCallback); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doBracketing(OMX_BUFFERHEADERTYPE *pBuffHeader, + CameraFrame::FrameType typeOfFrame) +{ + status_t ret = NO_ERROR; + int currentBufferIdx, nextBufferIdx; + OMXCameraPortParameters * imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in executing state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + currentBufferIdx = ( unsigned int ) pBuffHeader->pAppPrivate; + + if ( currentBufferIdx >= imgCaptureData->mNumBufs) + { + CAMHAL_LOGEB("Invalid bracketing buffer index 0x%x", currentBufferIdx); + ret = -EINVAL; + } + } + + if ( NO_ERROR == ret ) + { + mBracketingBuffersQueued[currentBufferIdx] = false; + mBracketingBuffersQueuedCount--; + + if ( 0 >= mBracketingBuffersQueuedCount ) + { + nextBufferIdx = ( currentBufferIdx + 1 ) % imgCaptureData->mNumBufs; + mBracketingBuffersQueued[nextBufferIdx] = true; + mBracketingBuffersQueuedCount++; + mLastBracetingBufferIdx = nextBufferIdx; + setFrameRefCount(imgCaptureData->mBufferHeader[nextBufferIdx]->pBuffer, typeOfFrame, 1); + returnFrame(imgCaptureData->mBufferHeader[nextBufferIdx]->pBuffer, typeOfFrame); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::sendBracketFrames() +{ + status_t ret = NO_ERROR; + int currentBufferIdx; + OMXCameraPortParameters * imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in executing state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + + currentBufferIdx = mLastBracetingBufferIdx; + do + { + currentBufferIdx++; + currentBufferIdx %= imgCaptureData->mNumBufs; + if (!mBracketingBuffersQueued[currentBufferIdx] ) + { + CameraFrame cameraFrame; + initCameraFrame(cameraFrame, + imgCaptureData->mBufferHeader[currentBufferIdx], + imgCaptureData->mImageType, + imgCaptureData); + sendFrame(cameraFrame); + } + } while ( currentBufferIdx != mLastBracetingBufferIdx ); + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startBracketing(int range) +{ + status_t ret = NO_ERROR; + OMXCameraPortParameters * imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component is not in executing state"); + ret = -EINVAL; + } + + { + Mutex::Autolock lock(mBracketingLock); + + if ( mBracketingEnabled ) + { + return ret; + } + } + + if ( 0 == imgCaptureData->mNumBufs ) + { + CAMHAL_LOGEB("Image capture buffers set to %d", imgCaptureData->mNumBufs); + ret = -EINVAL; + } + + if ( mPending3Asettings ) + apply3Asettings(mParameters3A); + + if ( NO_ERROR == ret ) + { + Mutex::Autolock lock(mBracketingLock); + + mBracketingRange = range; + mBracketingBuffersQueued = new bool[imgCaptureData->mNumBufs]; + if ( NULL == mBracketingBuffersQueued ) + { + CAMHAL_LOGEA("Unable to allocate bracketing management structures"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + mBracketingBuffersQueuedCount = imgCaptureData->mNumBufs; + mLastBracetingBufferIdx = mBracketingBuffersQueuedCount - 1; + + for ( int i = 0 ; i < imgCaptureData->mNumBufs ; i++ ) + { + mBracketingBuffersQueued[i] = true; + } + + } + } + + if ( NO_ERROR == ret ) + { + + ret = startImageCapture(); + { + Mutex::Autolock lock(mBracketingLock); + + if ( NO_ERROR == ret ) + { + mBracketingEnabled = true; + } + else + { + mBracketingEnabled = false; + } + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopBracketing() +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mBracketingLock); + + if ( mBracketingEnabled ) + { + + if ( NULL != mBracketingBuffersQueued ) + { + delete [] mBracketingBuffersQueued; + } + + ret = stopImageCapture(); + + mBracketingBuffersQueued = NULL; + mBracketingEnabled = false; + mBracketingBuffersQueuedCount = 0; + mLastBracetingBufferIdx = 0; + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startImageCapture() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMXCameraPortParameters * capData = NULL; + OMX_CONFIG_BOOLEANTYPE bOMX; + + LOG_FUNCTION_NAME; + + if(!mCaptureConfigured) + { + ///Image capture was cancelled before we could start + return NO_ERROR; + } + + if ( 0 != mStartCaptureSem.Count() ) + { + CAMHAL_LOGEB("Error mStartCaptureSem semaphore count %d", mStartCaptureSem.Count()); + return NO_INIT; + } + + //During bracketing image capture is already active + { + Mutex::Autolock lock(mBracketingLock); + if ( mBracketingEnabled ) + { + //Stop bracketing, activate normal burst for the remaining images + mBracketingEnabled = false; + mCapturedFrames = mBracketingRange; + ret = sendBracketFrames(); + goto EXIT; + } + } + + if ( NO_ERROR == ret ) + { + ret = setPictureRotation(mPictureRotation); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring image rotation %x", ret); + } + } + + //OMX shutter callback events are only available in hq mode + if ( (HIGH_QUALITY == mCapMode) || (HIGH_QUALITY_ZSL== mCapMode)) + { + + if ( NO_ERROR == ret ) + { + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_TI_IndexConfigShutterCallback, + mStartCaptureSem); + } + + if ( NO_ERROR == ret ) + { + ret = setShutterCallback(true); + } + + } + + if ( NO_ERROR == ret ) + { + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + ///Queue all the buffers on capture port + for ( int index = 0 ; index < capData->mNumBufs ; index++ ) + { + CAMHAL_LOGDB("Queuing buffer on Capture port - 0x%x", + ( unsigned int ) capData->mBufferHeader[index]->pBuffer); + eError = OMX_FillThisBuffer(mCameraAdapterParameters.mHandleComp, + (OMX_BUFFERHEADERTYPE*)capData->mBufferHeader[index]); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + + mWaitingForSnapshot = true; + mCaptureSignalled = false; + + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + bOMX.bEnabled = OMX_TRUE; + + /// sending Capturing Command to the component + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCapturing, + &bOMX); + + CAMHAL_LOGDB("Capture set - 0x%x", eError); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + + } + + //OMX shutter callback events are only available in hq mode + if ( (HIGH_QUALITY == mCapMode) || (HIGH_QUALITY_ZSL== mCapMode)) + { + + if ( NO_ERROR == ret ) + { + ret = mStartCaptureSem.WaitTimeout(OMX_CAPTURE_TIMEOUT); + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDA("Shutter callback received"); + notifyShutterSubscribers(); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_TI_IndexConfigShutterCallback, + NULL); + CAMHAL_LOGEA("Timeout expired on shutter callback"); + goto EXIT; + } + + } + + EXIT: + + if ( eError != OMX_ErrorNone ) + { + + mWaitingForSnapshot = false; + mCaptureSignalled = false; + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopImageCapture() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError; + OMX_CONFIG_BOOLEANTYPE bOMX; + OMXCameraPortParameters *imgCaptureData = NULL; + + LOG_FUNCTION_NAME; + + if (!mCaptureConfigured) { + //Capture is not ongoing, return from here + return NO_ERROR; + } + + if ( 0 != mStopCaptureSem.Count() ) { + CAMHAL_LOGEB("Error mStopCaptureSem semaphore count %d", mStopCaptureSem.Count()); + goto EXIT; + } + + //Disable the callback first + mWaitingForSnapshot = false; + mSnapshotCount = 0; + + //Disable the callback first + ret = setShutterCallback(false); + + //release any 3A locks if locked + ret = release3ALock(); + if(ret!=NO_ERROR) + { + CAMHAL_LOGEB("Error Releaseing 3A locks%d", ret); + } + + //Wait here for the capture to be done, in worst case timeout and proceed with cleanup + ret = mCaptureSem.WaitTimeout(OMX_CAPTURE_TIMEOUT); + if ( NO_ERROR != ret ) { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_TI_IndexConfigShutterCallback, + NULL); + CAMHAL_LOGEA("Timeout expired on shutter callback"); + } + + //Disable image capture + OMX_INIT_STRUCT_PTR (&bOMX, OMX_CONFIG_BOOLEANTYPE); + bOMX.bEnabled = OMX_FALSE; + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCapturing, + &bOMX); + if ( OMX_ErrorNone != eError ) { + CAMHAL_LOGDB("Error during SetConfig- 0x%x", eError); + ret = -1; + } + + CAMHAL_LOGDB("Capture set - 0x%x", eError); + + mCaptureSignalled = true; //set this to true if we exited because of timeout + + mCaptureConfigured = false; + + ///Register for Image port Disable event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mImagePortIndex, + mStopCaptureSem); + ///Disable Capture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortDisable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + + ///Free all the buffers on capture port + if (imgCaptureData) { + CAMHAL_LOGDB("Freeing buffer on Capture port - %d", imgCaptureData->mNumBufs); + for ( int index = 0 ; index < imgCaptureData->mNumBufs ; index++) { + CAMHAL_LOGDB("Freeing buffer on Capture port - 0x%x", + ( unsigned int ) imgCaptureData->mBufferHeader[index]->pBuffer); + eError = OMX_FreeBuffer(mCameraAdapterParameters.mHandleComp, + mCameraAdapterParameters.mImagePortIndex, + (OMX_BUFFERHEADERTYPE*)imgCaptureData->mBufferHeader[index]); + + GOTO_EXIT_IF((eError!=OMX_ErrorNone), eError); + } + } + CAMHAL_LOGDA("Waiting for port disable"); + //Wait for the image port enable event + ret = mStopCaptureSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( NO_ERROR == ret ) { + CAMHAL_LOGDA("Port disabled"); + } else { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortDisable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port disable"); + goto EXIT; + } + + EXIT: + + //Release image buffers + if ( NULL != mReleaseImageBuffersCallback ) { + mReleaseImageBuffersCallback(mReleaseData); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::UseBuffersCapture(void* bufArr, int num) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError; + OMXCameraPortParameters * imgCaptureData = NULL; + uint32_t *buffers = (uint32_t*)bufArr; + OMXCameraPortParameters cap; + + imgCaptureData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( 0 != mUseCaptureSem.Count() ) + { + CAMHAL_LOGEB("Error mUseCaptureSem semaphore count %d", mUseCaptureSem.Count()); + goto EXIT; + } + + imgCaptureData->mNumBufs = num; + + //TODO: Support more pixelformats + + CAMHAL_LOGDB("Params Width = %d", (int)imgCaptureData->mWidth); + CAMHAL_LOGDB("Params Height = %d", (int)imgCaptureData->mWidth); + + ret = setFormat(OMX_CAMERA_PORT_IMAGE_OUT_IMAGE, *imgCaptureData); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEB("setFormat() failed %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + ret = setThumbnailParams(mThumbWidth, mThumbHeight, mThumbQuality); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring thumbnail size %x", ret); + return ret; + } + + ret = setExposureBracketing( mExposureBracketingValues, + mExposureBracketingValidEntries, mBurstFrames); + if ( ret != NO_ERROR ) + { + CAMHAL_LOGEB("setExposureBracketing() failed %d", ret); + return ret; + } + + ret = setImageQuality(mPictureQuality); + if ( NO_ERROR != ret) + { + CAMHAL_LOGEB("Error configuring image quality %x", ret); + return ret; + } + + ///Register for Image port ENABLE event + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + mUseCaptureSem); + + ///Enable Capture Port + eError = OMX_SendCommand(mCameraAdapterParameters.mHandleComp, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + + for ( int index = 0 ; index < imgCaptureData->mNumBufs ; index++ ) + { + OMX_BUFFERHEADERTYPE *pBufferHdr; + CAMHAL_LOGDB("OMX_UseBuffer Capture address: 0x%x, size = %d", + (unsigned int)buffers[index], + (int)imgCaptureData->mBufSize); + + eError = OMX_UseBuffer(mCameraAdapterParameters.mHandleComp, + &pBufferHdr, + mCameraAdapterParameters.mImagePortIndex, + 0, + mCaptureBuffersLength, + (OMX_U8*)buffers[index]); + + CAMHAL_LOGDB("OMX_UseBuffer = 0x%x", eError); + + GOTO_EXIT_IF(( eError != OMX_ErrorNone ), eError); + + pBufferHdr->pAppPrivate = (OMX_PTR) index; + pBufferHdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + pBufferHdr->nVersion.s.nVersionMajor = 1 ; + pBufferHdr->nVersion.s.nVersionMinor = 1 ; + pBufferHdr->nVersion.s.nRevision = 0; + pBufferHdr->nVersion.s.nStep = 0; + imgCaptureData->mBufferHeader[index] = pBufferHdr; + } + + //Wait for the image port enable event + CAMHAL_LOGDA("Waiting for port enable"); + ret = mUseCaptureSem.WaitTimeout(OMX_CMD_TIMEOUT); + if ( ret == NO_ERROR ) + { + CAMHAL_LOGDA("Port enabled"); + } + else + { + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + OMX_EventCmdComplete, + OMX_CommandPortEnable, + mCameraAdapterParameters.mImagePortIndex, + NULL); + CAMHAL_LOGDA("Timeout expired on port enable"); + goto EXIT; + } + + if ( NO_ERROR == ret ) + { + ret = setupEXIF(); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error configuring EXIF Buffer %x", ret); + } + } + + mCapturedFrames = mBurstFrames; + mCaptureConfigured = true; + + EXIT: + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXDefaults.cpp b/camera/OMXCameraAdapter/OMXDefaults.cpp new file mode 100644 index 0000000..670f562 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXDefaults.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXDefaults.cpp +* +* This file contains definitions are OMX Camera defaults +* +*/ + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace android { + +#undef LOG_TAG +#define LOG_TAG "CameraHAL" + +// OMX Camera defaults +const char OMXCameraAdapter::DEFAULT_ANTIBANDING[] = "auto"; +const char OMXCameraAdapter::DEFAULT_BRIGHTNESS[] = "50"; +const char OMXCameraAdapter::DEFAULT_CONTRAST[] = "100"; +const char OMXCameraAdapter::DEFAULT_EFFECT[] = "none"; +const char OMXCameraAdapter::DEFAULT_EV_COMPENSATION[] = "0"; +const char OMXCameraAdapter::DEFAULT_EV_STEP[] = "0.1"; +const char OMXCameraAdapter::DEFAULT_EXPOSURE_MODE[] = "auto"; +const char OMXCameraAdapter::DEFAULT_FLASH_MODE[] = "off"; +const char OMXCameraAdapter::DEFAULT_FOCUS_MODE[] = "infinity"; +const char OMXCameraAdapter::DEFAULT_FRAMERATE_RANGE[] = "20000,30000"; +const char OMXCameraAdapter::DEFAULT_IPP[] = "off"; +const char OMXCameraAdapter::DEFAULT_ISO_MODE[] = "auto"; +const char OMXCameraAdapter::DEFAULT_JPEG_QUALITY[] = "95"; +const char OMXCameraAdapter::DEFAULT_THUMBNAIL_QUALITY[] = "60"; +const char OMXCameraAdapter::DEFAULT_THUMBNAIL_SIZE[] = "160x120"; +const char OMXCameraAdapter::DEFAULT_PICTURE_FORMAT[] = "jpeg"; +const char OMXCameraAdapter::DEFAULT_PICTURE_SIZE[] = "320x240"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_FORMAT[] = "yuv420sp"; +const char OMXCameraAdapter::DEFAULT_FRAMERATE[] = "30"; +const char OMXCameraAdapter::DEFAULT_PREVIEW_SIZE[] = "640x480"; +const char OMXCameraAdapter::DEFAULT_NUM_PREV_BUFS[] = "6"; +const char OMXCameraAdapter::DEFAULT_NUM_PIC_BUFS[] = "1"; +const char OMXCameraAdapter::DEFAULT_MAX_FOCUS_AREAS[] = "1"; +const char OMXCameraAdapter::DEFAULT_SATURATION[] = "100"; +const char OMXCameraAdapter::DEFAULT_SCENE_MODE[] = "auto"; +const char OMXCameraAdapter::DEFAULT_SHARPNESS[] = "100"; +const char OMXCameraAdapter::DEFAULT_VSTAB[] = "0"; +const char OMXCameraAdapter::DEFAULT_WB[] = "auto"; +const char OMXCameraAdapter::DEFAULT_ZOOM[] = "0"; +const char OMXCameraAdapter::DEFAULT_MAX_FD_HW_FACES[] = "35"; +const char OMXCameraAdapter::DEFAULT_MAX_FD_SW_FACES[] = "0"; + +const char OMXCameraAdapter::DEFAULT_AE_LOCK[] = "false"; +const char OMXCameraAdapter::DEFAULT_AWB_LOCK[] = "false"; +const char OMXCameraAdapter::DEFAULT_MAX_NUM_METERING_AREAS[] = "0"; +const char OMXCameraAdapter::DEFAULT_LOCK_SUPPORTED[] = "true"; +const char OMXCameraAdapter::DEFAULT_LOCK_UNSUPPORTED[] = "false"; +}; + diff --git a/camera/OMXCameraAdapter/OMXExif.cpp b/camera/OMXCameraAdapter/OMXExif.cpp new file mode 100644 index 0000000..56b1694 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXExif.cpp @@ -0,0 +1,567 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXExif.cpp +* +* This file contains functionality for handling EXIF insertion. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" +#include <math.h> + +namespace android { + +const char OMXCameraAdapter::EXIFASCIIPrefix [] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 }; + +status_t OMXCameraAdapter::setParametersEXIF(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *valstr = NULL; + double gpsPos; + + LOG_FUNCTION_NAME; + + if( ( valstr = params.get(CameraParameters::KEY_GPS_LATITUDE) ) != NULL ) + { + gpsPos = strtod(valstr, NULL); + + if ( convertGPSCoord( gpsPos, &mEXIFData.mGPSData.mLatDeg, + &mEXIFData.mGPSData.mLatMin, + &mEXIFData.mGPSData.mLatSec ) == NO_ERROR ) + { + + if ( 0 < gpsPos ) + { + strncpy(mEXIFData.mGPSData.mLatRef, GPS_NORTH_REF, GPS_REF_SIZE); + } + else + { + strncpy(mEXIFData.mGPSData.mLatRef, GPS_SOUTH_REF, GPS_REF_SIZE); + } + + mEXIFData.mGPSData.mLatValid = true; + } + else + { + mEXIFData.mGPSData.mLatValid = false; + } + } + else + { + mEXIFData.mGPSData.mLatValid = false; + } + + if( ( valstr = params.get(CameraParameters::KEY_GPS_LONGITUDE) ) != NULL ) + { + gpsPos = strtod(valstr, NULL); + + if ( convertGPSCoord( gpsPos, &mEXIFData.mGPSData.mLongDeg, + &mEXIFData.mGPSData.mLongMin, + &mEXIFData.mGPSData.mLongSec ) == NO_ERROR ) + { + + if ( 0 < gpsPos ) + { + strncpy(mEXIFData.mGPSData.mLongRef, GPS_EAST_REF, GPS_REF_SIZE); + } + else + { + strncpy(mEXIFData.mGPSData.mLongRef, GPS_WEST_REF, GPS_REF_SIZE); + } + + mEXIFData.mGPSData.mLongValid= true; + } + else + { + mEXIFData.mGPSData.mLongValid = false; + } + } + else + { + mEXIFData.mGPSData.mLongValid = false; + } + + if( ( valstr = params.get(CameraParameters::KEY_GPS_ALTITUDE) ) != NULL ) + { + gpsPos = strtod(valstr, NULL); + mEXIFData.mGPSData.mAltitude = floor(fabs(gpsPos)); + if (gpsPos < 0) { + mEXIFData.mGPSData.mAltitudeRef = 1; + } else { + mEXIFData.mGPSData.mAltitudeRef = 0; + } + mEXIFData.mGPSData.mAltitudeValid = true; + } + else + { + mEXIFData.mGPSData.mAltitudeValid= false; + } + + if( (valstr = params.get(CameraParameters::KEY_GPS_TIMESTAMP)) != NULL ) + { + long gpsTimestamp = strtol(valstr, NULL, 10); + struct tm *timeinfo = localtime( ( time_t * ) & (gpsTimestamp) ); + if ( NULL != timeinfo ) + { + mEXIFData.mGPSData.mTimeStampHour = timeinfo->tm_hour; + mEXIFData.mGPSData.mTimeStampMin = timeinfo->tm_min; + mEXIFData.mGPSData.mTimeStampSec = timeinfo->tm_sec; + mEXIFData.mGPSData.mTimeStampValid = true; + } + else + { + mEXIFData.mGPSData.mTimeStampValid = false; + } + } + else + { + mEXIFData.mGPSData.mTimeStampValid = false; + } + + if( ( valstr = params.get(CameraParameters::KEY_GPS_TIMESTAMP) ) != NULL ) + { + long gpsDatestamp = strtol(valstr, NULL, 10); + struct tm *timeinfo = localtime( ( time_t * ) & (gpsDatestamp) ); + if ( NULL != timeinfo ) + { + strftime(mEXIFData.mGPSData.mDatestamp, GPS_DATESTAMP_SIZE, "%Y:%m:%d", timeinfo); + mEXIFData.mGPSData.mDatestampValid = true; + } + else + { + mEXIFData.mGPSData.mDatestampValid = false; + } + } + else + { + mEXIFData.mGPSData.mDatestampValid = false; + } + + if( ( valstr = params.get(CameraParameters::KEY_GPS_PROCESSING_METHOD) ) != NULL ) + { + strncpy(mEXIFData.mGPSData.mProcMethod, valstr, GPS_PROCESSING_SIZE-1); + mEXIFData.mGPSData.mProcMethodValid = true; + } + else + { + mEXIFData.mGPSData.mProcMethodValid = false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_GPS_MAPDATUM) ) != NULL ) + { + strncpy(mEXIFData.mGPSData.mMapDatum, valstr, GPS_MAPDATUM_SIZE-1); + mEXIFData.mGPSData.mMapDatumValid = true; + } + else + { + mEXIFData.mGPSData.mMapDatumValid = false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_GPS_VERSION) ) != NULL ) + { + strncpy(mEXIFData.mGPSData.mVersionId, valstr, GPS_VERSION_SIZE-1); + mEXIFData.mGPSData.mVersionIdValid = true; + } + else + { + mEXIFData.mGPSData.mVersionIdValid = false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_EXIF_MODEL ) ) != NULL ) + { + CAMHAL_LOGVB("EXIF Model: %s", valstr); + mEXIFData.mModelValid= true; + } + else + { + mEXIFData.mModelValid= false; + } + + if( ( valstr = params.get(TICameraParameters::KEY_EXIF_MAKE ) ) != NULL ) + { + CAMHAL_LOGVB("EXIF Make: %s", valstr); + mEXIFData.mMakeValid = true; + } + else + { + mEXIFData.mMakeValid= false; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setupEXIF() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_CONFIG_SHAREDBUFFER sharedBuffer; + OMX_TI_CONFIG_EXIF_TAGS *exifTags; + unsigned char *sharedPtr = NULL; + struct timeval sTv; + struct tm *pTime; + OMXCameraPortParameters * capData = NULL; + MemoryManager memMgr; + OMX_U8** memmgr_buf_array = NULL; + int buf_size = 0; + + LOG_FUNCTION_NAME; + + sharedBuffer.pSharedBuff = NULL; + capData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mImagePortIndex]; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&sharedBuffer, OMX_TI_CONFIG_SHAREDBUFFER); + sharedBuffer.nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + //We allocate the shared buffer dynamically based on the + //requirements of the EXIF tags. The additional buffers will + //get stored after the EXIF configuration structure and the pointers + //will contain offsets within the shared buffer itself. + buf_size = sizeof(OMX_TI_CONFIG_EXIF_TAGS) + + ( EXIF_MODEL_SIZE ) + + ( EXIF_MAKE_SIZE ) + + ( EXIF_DATE_TIME_SIZE ) + + ( GPS_MAPDATUM_SIZE ) + + ( GPS_PROCESSING_SIZE ); + sharedBuffer.nSharedBuffSize = buf_size; + + memmgr_buf_array = (OMX_U8 **)memMgr.allocateBuffer(0, 0, NULL, buf_size, 1); + sharedBuffer.pSharedBuff = ( OMX_U8 * ) memmgr_buf_array[0]; + + if ( NULL == sharedBuffer.pSharedBuff ) + { + CAMHAL_LOGEA("No resources to allocate OMX shared buffer"); + ret = -1; + } + + //Extra data begins right after the EXIF configuration structure. + sharedPtr = sharedBuffer.pSharedBuff + sizeof(OMX_TI_CONFIG_EXIF_TAGS); + } + + if ( NO_ERROR == ret ) + { + exifTags = ( OMX_TI_CONFIG_EXIF_TAGS * ) sharedBuffer.pSharedBuff; + OMX_INIT_STRUCT_PTR (exifTags, OMX_TI_CONFIG_EXIF_TAGS); + exifTags->nPortIndex = mCameraAdapterParameters.mImagePortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigExifTags, + &sharedBuffer ); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while retrieving EXIF configuration structure 0x%x", eError); + ret = -1; + } + } + + if ( NO_ERROR == ret ) + { + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusModel ) && + ( mEXIFData.mModelValid ) ) + { + strncpy(( char * ) sharedPtr, + ( char * ) mParams.get(TICameraParameters::KEY_EXIF_MODEL ), + EXIF_MODEL_SIZE - 1); + + exifTags->pModelBuff = ( OMX_S8 * ) ( sharedPtr - sharedBuffer.pSharedBuff ); + sharedPtr += EXIF_MODEL_SIZE; + exifTags->ulModelBuffSizeBytes = EXIF_MODEL_SIZE; + exifTags->eStatusModel = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusMake) && + ( mEXIFData.mMakeValid ) ) + { + strncpy( ( char * ) sharedPtr, + ( char * ) mParams.get(TICameraParameters::KEY_EXIF_MAKE ), + EXIF_MAKE_SIZE - 1); + + exifTags->pMakeBuff = ( OMX_S8 * ) ( sharedPtr - sharedBuffer.pSharedBuff ); + sharedPtr += EXIF_MAKE_SIZE; + exifTags->ulMakeBuffSizeBytes = EXIF_MAKE_SIZE; + exifTags->eStatusMake = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusFocalLength )) + { + char *ctx; + int len; + char* temp = (char*) mParams.get(CameraParameters::KEY_FOCAL_LENGTH); + char * tempVal = NULL; + if(temp != NULL) + { + len = strlen(temp); + tempVal = (char*) malloc( sizeof(char) * (len + 1)); + } + if(tempVal != NULL) + { + memset(tempVal, '\0', len + 1); + strncpy(tempVal, temp, len); + CAMHAL_LOGDB("KEY_FOCAL_LENGTH = %s", tempVal); + + // convert the decimal string into a rational + size_t den_len; + OMX_U32 numerator = 0; + OMX_U32 denominator = 0; + char* temp = strtok_r(tempVal, ".", &ctx); + + if(temp != NULL) + numerator = atoi(temp); + + temp = strtok_r(NULL, ".", &ctx); + if(temp != NULL) + { + den_len = strlen(temp); + if(HUGE_VAL == den_len ) + { + den_len = 0; + } + denominator = static_cast<OMX_U32>(pow(10, den_len)); + numerator = numerator*denominator + atoi(temp); + }else{ + denominator = 1; + } + + free(tempVal); + + exifTags->ulFocalLength[0] = numerator; + exifTags->ulFocalLength[1] = denominator; + CAMHAL_LOGVB("exifTags->ulFocalLength = [%u] [%u]", + (unsigned int)(exifTags->ulFocalLength[0]), + (unsigned int)(exifTags->ulFocalLength[1])); + exifTags->eStatusFocalLength = OMX_TI_TagUpdated; + } + } + + if ( OMX_TI_TagReadWrite == exifTags->eStatusDateTime ) + { + int status = gettimeofday (&sTv, NULL); + pTime = localtime (&sTv.tv_sec); + if ( ( 0 == status ) && ( NULL != pTime ) ) + { + snprintf(( char * ) sharedPtr, EXIF_DATE_TIME_SIZE, + "%04d:%02d:%02d %02d:%02d:%02d", + pTime->tm_year + 1900, + pTime->tm_mon + 1, + pTime->tm_mday, + pTime->tm_hour, + pTime->tm_min, + pTime->tm_sec ); + } + + exifTags->pDateTimeBuff = ( OMX_S8 * ) ( sharedPtr - sharedBuffer.pSharedBuff ); + sharedPtr += EXIF_DATE_TIME_SIZE; + exifTags->ulDateTimeBuffSizeBytes = EXIF_DATE_TIME_SIZE; + exifTags->eStatusDateTime = OMX_TI_TagUpdated; + } + + if ( OMX_TI_TagReadWrite == exifTags->eStatusImageWidth ) + { + exifTags->ulImageWidth = capData->mWidth; + exifTags->eStatusImageWidth = OMX_TI_TagUpdated; + } + + if ( OMX_TI_TagReadWrite == exifTags->eStatusImageHeight ) + { + exifTags->ulImageHeight = capData->mHeight; + exifTags->eStatusImageHeight = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLatitude ) && + ( mEXIFData.mGPSData.mLatValid ) ) + { + exifTags->ulGpsLatitude[0] = abs(mEXIFData.mGPSData.mLatDeg); + exifTags->ulGpsLatitude[2] = abs(mEXIFData.mGPSData.mLatMin); + exifTags->ulGpsLatitude[4] = abs(mEXIFData.mGPSData.mLatSec); + exifTags->ulGpsLatitude[1] = 1; + exifTags->ulGpsLatitude[3] = 1; + exifTags->ulGpsLatitude[5] = 1; + exifTags->eStatusGpsLatitude = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpslatitudeRef ) && + ( mEXIFData.mGPSData.mLatValid ) ) + { + exifTags->cGpslatitudeRef[0] = ( OMX_S8 ) mEXIFData.mGPSData.mLatRef[0]; + exifTags->cGpslatitudeRef[1] = '\0'; + exifTags->eStatusGpslatitudeRef = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLongitude ) && + ( mEXIFData.mGPSData.mLongValid ) ) + { + exifTags->ulGpsLongitude[0] = abs(mEXIFData.mGPSData.mLongDeg); + exifTags->ulGpsLongitude[2] = abs(mEXIFData.mGPSData.mLongMin); + exifTags->ulGpsLongitude[4] = abs(mEXIFData.mGPSData.mLongSec); + exifTags->ulGpsLongitude[1] = 1; + exifTags->ulGpsLongitude[3] = 1; + exifTags->ulGpsLongitude[5] = 1; + exifTags->eStatusGpsLongitude = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsLongitudeRef ) && + ( mEXIFData.mGPSData.mLongValid ) ) + { + exifTags->cGpsLongitudeRef[0] = ( OMX_S8 ) mEXIFData.mGPSData.mLongRef[0]; + exifTags->cGpsLongitudeRef[1] = '\0'; + exifTags->eStatusGpsLongitudeRef = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsAltitude ) && + ( mEXIFData.mGPSData.mAltitudeValid) ) + { + exifTags->ulGpsAltitude[0] = ( OMX_U32 ) mEXIFData.mGPSData.mAltitude; + exifTags->ulGpsAltitude[1] = 1; + exifTags->eStatusGpsAltitude = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsAltitudeRef ) && + ( mEXIFData.mGPSData.mAltitudeValid) ) + { + exifTags->ucGpsAltitudeRef = (OMX_U8) mEXIFData.mGPSData.mAltitudeRef; + exifTags->eStatusGpsAltitudeRef = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsMapDatum ) && + ( mEXIFData.mGPSData.mMapDatumValid ) ) + { + memcpy(sharedPtr, mEXIFData.mGPSData.mMapDatum, GPS_MAPDATUM_SIZE); + + exifTags->pGpsMapDatumBuff = ( OMX_S8 * ) ( sharedPtr - sharedBuffer.pSharedBuff ); + exifTags->ulGpsMapDatumBuffSizeBytes = GPS_MAPDATUM_SIZE; + exifTags->eStatusGpsMapDatum = OMX_TI_TagUpdated; + sharedPtr += GPS_MAPDATUM_SIZE; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsProcessingMethod ) && + ( mEXIFData.mGPSData.mProcMethodValid ) ) + { + exifTags->pGpsProcessingMethodBuff = ( OMX_S8 * ) ( sharedPtr - sharedBuffer.pSharedBuff ); + memcpy(sharedPtr, EXIFASCIIPrefix, sizeof(EXIFASCIIPrefix)); + sharedPtr += sizeof(EXIFASCIIPrefix); + + memcpy(sharedPtr, + mEXIFData.mGPSData.mProcMethod, + ( GPS_PROCESSING_SIZE - sizeof(EXIFASCIIPrefix) ) ); + exifTags->ulGpsProcessingMethodBuffSizeBytes = GPS_PROCESSING_SIZE; + exifTags->eStatusGpsProcessingMethod = OMX_TI_TagUpdated; + sharedPtr += GPS_PROCESSING_SIZE; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsVersionId ) && + ( mEXIFData.mGPSData.mVersionIdValid ) ) + { + exifTags->ucGpsVersionId[0] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[0]; + exifTags->ucGpsVersionId[1] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[1]; + exifTags->ucGpsVersionId[2] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[2]; + exifTags->ucGpsVersionId[3] = ( OMX_U8 ) mEXIFData.mGPSData.mVersionId[3]; + exifTags->eStatusGpsVersionId = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsTimeStamp ) && + ( mEXIFData.mGPSData.mTimeStampValid ) ) + { + exifTags->ulGpsTimeStamp[0] = mEXIFData.mGPSData.mTimeStampHour; + exifTags->ulGpsTimeStamp[2] = mEXIFData.mGPSData.mTimeStampMin; + exifTags->ulGpsTimeStamp[4] = mEXIFData.mGPSData.mTimeStampSec; + exifTags->ulGpsTimeStamp[1] = 1; + exifTags->ulGpsTimeStamp[3] = 1; + exifTags->ulGpsTimeStamp[5] = 1; + exifTags->eStatusGpsTimeStamp = OMX_TI_TagUpdated; + } + + if ( ( OMX_TI_TagReadWrite == exifTags->eStatusGpsDateStamp ) && + ( mEXIFData.mGPSData.mDatestampValid ) ) + { + strncpy( ( char * ) exifTags->cGpsDateStamp, + ( char * ) mEXIFData.mGPSData.mDatestamp, + GPS_DATESTAMP_SIZE ); + exifTags->eStatusGpsDateStamp = OMX_TI_TagUpdated; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigExifTags, + &sharedBuffer ); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while setting EXIF configuration 0x%x", eError); + ret = -1; + } + } + + if ( NULL != memmgr_buf_array ) + { + memMgr.freeBuffer(memmgr_buf_array); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::convertGPSCoord(double coord, int *deg, int *min, int *sec) +{ + double tmp; + + LOG_FUNCTION_NAME; + + if ( coord == 0 ) { + + LOGE("Invalid GPS coordinate"); + + return -EINVAL; + } + + *deg = (int) floor(fabs(coord)); + tmp = ( fabs(coord) - floor(fabs(coord)) )*60; + *min = (int) floor(tmp); + tmp = ( tmp - floor(tmp) )*60; + *sec = (int) floor(tmp); + + if( *sec >= 60 ) { + *sec = 0; + *min += 1; + } + + if( *min >= 60 ) { + *min = 0; + *deg += 1; + } + + LOG_FUNCTION_NAME_EXIT; + + return NO_ERROR; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXFD.cpp b/camera/OMXCameraAdapter/OMXFD.cpp new file mode 100644 index 0000000..c1617d7 --- /dev/null +++ b/camera/OMXCameraAdapter/OMXFD.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXFD.cpp +* +* This file contains functionality for handling face detection. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace android { + +status_t OMXCameraAdapter::setParametersFD(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::startFaceDetection() +{ + Mutex::Autolock lock(mFaceDetectionLock); + return setFaceDetection(true, mDeviceOrientation); +} + +status_t OMXCameraAdapter::stopFaceDetection() +{ + Mutex::Autolock lock(mFaceDetectionLock); + return setFaceDetection(false, mDeviceOrientation); +} + +status_t OMXCameraAdapter::setFaceDetection(bool enable, OMX_U32 orientation) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXTRADATATYPE extraDataControl; + OMX_CONFIG_OBJDETECTIONTYPE objDetection; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + if ( orientation < 0 || orientation > 270 ) { + orientation = 0; + } + + OMX_INIT_STRUCT_PTR (&objDetection, OMX_CONFIG_OBJDETECTIONTYPE); + objDetection.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + objDetection.nDeviceOrientation = orientation; + if ( enable ) + { + objDetection.bEnable = OMX_TRUE; + } + else + { + objDetection.bEnable = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigImageFaceDetection, + &objDetection); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring face detection 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Face detection configured successfully"); + } + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&extraDataControl, OMX_CONFIG_EXTRADATATYPE); + extraDataControl.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + extraDataControl.eExtraDataType = OMX_FaceDetection; + extraDataControl.eCameraView = OMX_2D; + if ( enable ) + { + extraDataControl.bEnable = OMX_TRUE; + } + else + { + extraDataControl.bEnable = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigOtherExtraDataControl, + &extraDataControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring face detection extra data 0x%x", + eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Face detection extra data configured successfully"); + } + } + + if ( NO_ERROR == ret ) + { + mFaceDetectionRunning = enable; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::detectFaces(OMX_BUFFERHEADERTYPE* pBuffHeader, + sp<CameraFDResult> &result, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_TI_FACERESULT *faceResult; + OMX_OTHER_EXTRADATATYPE *extraData; + OMX_FACEDETECTIONTYPE *faceData; + OMX_TI_PLATFORMPRIVATE *platformPrivate; + camera_frame_metadata_t *faces; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) { + CAMHAL_LOGEA("OMX component is not in executing state"); + return NO_INIT; + } + + if ( NULL == pBuffHeader ) { + CAMHAL_LOGEA("Invalid Buffer header"); + return-EINVAL; + } + + platformPrivate = (OMX_TI_PLATFORMPRIVATE *) (pBuffHeader->pPlatformPrivate); + if ( NULL != platformPrivate ) { + if ( sizeof(OMX_TI_PLATFORMPRIVATE) == platformPrivate->nSize ) { + CAMHAL_LOGVB("Size = %d, sizeof = %d, pAuxBuf = 0x%x, pAuxBufSize= %d, pMetaDataBufer = 0x%x, nMetaDataSize = %d", + platformPrivate->nSize, + sizeof(OMX_TI_PLATFORMPRIVATE), + platformPrivate->pAuxBuf1, + platformPrivate->pAuxBufSize1, + platformPrivate->pMetaDataBuffer, + platformPrivate->nMetaDataSize); + } else { + CAMHAL_LOGEB("OMX_TI_PLATFORMPRIVATE size mismatch: expected = %d, received = %d", + ( unsigned int ) sizeof(OMX_TI_PLATFORMPRIVATE), + ( unsigned int ) platformPrivate->nSize); + ret = -EINVAL; + } + } else { + CAMHAL_LOGEA("Invalid OMX_TI_PLATFORMPRIVATE"); + return-EINVAL; + } + + + if ( 0 >= platformPrivate->nMetaDataSize ) { + CAMHAL_LOGEB("OMX_TI_PLATFORMPRIVATE nMetaDataSize is size is %d", + ( unsigned int ) platformPrivate->nMetaDataSize); + return -EINVAL; + } + + extraData = (OMX_OTHER_EXTRADATATYPE *) (platformPrivate->pMetaDataBuffer); + if ( NULL != extraData ) { + CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x", + extraData->nSize, + sizeof(OMX_OTHER_EXTRADATATYPE), + extraData->eType, + extraData->nDataSize, + extraData->nPortIndex, + extraData->nVersion); + } else { + CAMHAL_LOGEA("Invalid OMX_OTHER_EXTRADATATYPE"); + return -EINVAL; + } + + faceData = ( OMX_FACEDETECTIONTYPE * ) extraData->data; + if ( NULL != faceData ) { + if ( sizeof(OMX_FACEDETECTIONTYPE) == faceData->nSize ) { + CAMHAL_LOGVB("Faces detected %d", + faceData->ulFaceCount, + faceData->nSize, + sizeof(OMX_FACEDETECTIONTYPE), + faceData->eCameraView, + faceData->nPortIndex, + faceData->nVersion); + } else { + CAMHAL_LOGEB("OMX_FACEDETECTIONTYPE size mismatch: expected = %d, received = %d", + ( unsigned int ) sizeof(OMX_FACEDETECTIONTYPE), + ( unsigned int ) faceData->nSize); + return -EINVAL; + } + } else { + CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE"); + return -EINVAL; + } + + ret = encodeFaceCoordinates(faceData, &faces, previewWidth, previewHeight); + + if ( NO_ERROR == ret ) { + result = new CameraFDResult(faces); + } else { + result.clear(); + result = NULL; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData, + camera_frame_metadata_t **pFaces, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + camera_face_t *faces; + camera_frame_metadata_t *faceResult; + size_t hRange, vRange; + double tmp; + + LOG_FUNCTION_NAME; + + if ( NULL == faceData ) { + CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE parameter"); + return EINVAL; + } + + LOG_FUNCTION_NAME + + hRange = CameraFDResult::RIGHT - CameraFDResult::LEFT; + vRange = CameraFDResult::BOTTOM - CameraFDResult::TOP; + + faceResult = ( camera_frame_metadata_t * ) malloc(sizeof(camera_frame_metadata_t)); + if ( NULL == faceResult ) { + return -ENOMEM; + } + + if ( 0 < faceData->ulFaceCount ) { + + faces = ( camera_face_t * ) malloc(sizeof(camera_face_t)*faceData->ulFaceCount); + if ( NULL == faces ) { + return -ENOMEM; + } + + for ( int i = 0 ; i < faceData->ulFaceCount ; i++) + { + + tmp = ( double ) faceData->tFacePosition[i].nLeft / ( double ) previewWidth; + tmp *= hRange; + tmp -= hRange/2; + faces[i].rect[0] = tmp; + + tmp = ( double ) faceData->tFacePosition[i].nTop / ( double )previewHeight; + tmp *= vRange; + tmp -= vRange/2; + faces[i].rect[1] = tmp; + + tmp = ( double ) faceData->tFacePosition[i].nWidth / ( double ) previewWidth; + tmp *= hRange; + faces[i].rect[2] = faces[i].rect[0] + tmp; + + tmp = ( double ) faceData->tFacePosition[i].nHeight / ( double ) previewHeight; + tmp *= vRange; + faces[i].rect[3] = faces[i].rect[1] + tmp; + + faces[i].score = faceData->tFacePosition[i].nScore; + faces[i].id = 0; + faces[i].left_eye[0] = CameraFDResult::INVALID_DATA; + faces[i].left_eye[1] = CameraFDResult::INVALID_DATA; + faces[i].right_eye[0] = CameraFDResult::INVALID_DATA; + faces[i].right_eye[1] = CameraFDResult::INVALID_DATA; + faces[i].mouth[0] = CameraFDResult::INVALID_DATA; + faces[i].mouth[1] = CameraFDResult::INVALID_DATA; + } + + faceResult->number_of_faces = faceData->ulFaceCount; + faceResult->faces = faces; + + } else { + faceResult->number_of_faces = 0; + faceResult->faces = NULL; + } + + *pFaces = faceResult; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXFocus.cpp b/camera/OMXCameraAdapter/OMXFocus.cpp new file mode 100644 index 0000000..19286ea --- /dev/null +++ b/camera/OMXCameraAdapter/OMXFocus.cpp @@ -0,0 +1,673 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXFocus.cpp +* +* This file contains functionality for handling focus configurations. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +#define TOUCH_FOCUS_RANGE 0xFF +#define AF_CALLBACK_TIMEOUT 10000000 //10 seconds timeout + +namespace android { + +status_t OMXCameraAdapter::setParametersFocus(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + const char *str = NULL; + + LOG_FUNCTION_NAME; + + str = params.get(CameraParameters::KEY_FOCUS_AREAS); + mFocusAreas.clear(); + if ( NULL != str ) + { + CameraArea::parseFocusArea(str, strlen(str), mFocusAreas); + } + + LOG_FUNCTION_NAME; + + return ret; +} + +status_t OMXCameraAdapter::doAutoFocus() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; + size_t top, left, width, height, weight; + sp<CameraArea> focusArea = NULL; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + returnFocusStatus(false); + return NO_INIT; + } + + if ( 0 != mDoAFSem.Count() ) + { + CAMHAL_LOGEB("Error mDoAFSem semaphore count %d", mDoAFSem.Count()); + return NO_INIT; + } + + if ( NO_ERROR == ret ) + { + if ( !mFocusAreas.isEmpty() ) + { + focusArea = mFocusAreas.itemAt(0); + } + + OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) mParameters3A.Focus; + + //If touch AF is set, then necessary configuration first + if ( ( NULL != focusArea.get() ) && ( focusArea->isValid() ) ) + { + + //Disable face priority first + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); + + //Enable region algorithm priority + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, true); + + //Set position + OMXCameraPortParameters * mPreviewData = NULL; + mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; + focusArea->transfrom(mPreviewData->mWidth, + mPreviewData->mHeight, + top, + left, + width, + height); + setTouchFocus(left, + top, + width, + height, + mPreviewData->mWidth, + mPreviewData->mHeight); + + //Do normal focus afterwards + focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) OMX_IMAGE_FocusControlExtended; + + } + else if ( FOCUS_FACE_PRIORITY == focusControl.eFocusControl ) + { + + //Disable region priority first + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); + + //Enable face algorithm priority + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, true); + + //Do normal focus afterwards + focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) OMX_IMAGE_FocusControlExtended; + + } + else + { + + //Disable both region and face priority + setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); + + setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); + + } + + if ( ( mParameters3A.Focus != OMX_IMAGE_FocusControlAuto ) && + ( mParameters3A.Focus != OMX_IMAGE_FocusControlAutoInfinity ) ) + { + + ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_IndexConfigCommonFocusStatus, + mDoAFSem); + + if ( NO_ERROR == ret ) + { + ret = setFocusCallback(true); + } + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigFocusControl, + &focusControl); + + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while starting focus 0x%x", eError); + return INVALID_OPERATION; + } + else + { + CAMHAL_LOGDA("Autofocus started successfully"); + } + } + + if ( ( mParameters3A.Focus != OMX_IMAGE_FocusControlAuto ) && + ( mParameters3A.Focus != OMX_IMAGE_FocusControlAutoInfinity ) ) + { + + ret = mDoAFSem.WaitTimeout(AF_CALLBACK_TIMEOUT); + //Disable auto focus callback from Ducati + setFocusCallback(false); + //Signal a dummy AF event so that in case the callback from ducati + //does come then it doesnt crash after + //exiting this function since eventSem will go out of scope. + if(ret != NO_ERROR) + { + CAMHAL_LOGEA("Autofocus callback timeout expired"); + SignalEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_IndexConfigCommonFocusStatus, + NULL ); + returnFocusStatus(true); + } + else + { + CAMHAL_LOGDA("Autofocus callback received"); + ret = returnFocusStatus(false); + } + + } + else + { + if ( NO_ERROR == ret ) + { + ret = returnFocusStatus(true); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopAutoFocus() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + return NO_INIT; + } + + if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity ) { + // No need to stop focus if we are in infinity mode. Nothing to stop. + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + //Disable the callback first + ret = setFocusCallback(false); + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); + focusControl.eFocusControl = OMX_IMAGE_FocusControlOff; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigFocusControl, + &focusControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while stopping focus 0x%x", eError); + ret = -1; + } + else + { + mParameters3A.Focus = OMX_IMAGE_FocusControlOff; + CAMHAL_LOGDA("Autofocus stopped successfully"); + } + } + + //Query current focus distance after AF is complete + updateFocusDistances(mParameters); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::cancelAutoFocus() +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + stopAutoFocus(); + //Signal a dummy AF event so that in case the callback from ducati + //does come then it doesnt crash after + //exiting this function since eventSem will go out of scope. + ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, + (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, + OMX_ALL, + OMX_IndexConfigCommonFocusStatus, + NULL ); + + LOG_FUNCTION_NAME_EXIT; + + return ret; + +} + +status_t OMXCameraAdapter::setFocusCallback(bool enabled) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_CALLBACKREQUESTTYPE focusRequstCallback; + + LOG_FUNCTION_NAME; + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + + OMX_INIT_STRUCT_PTR (&focusRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE); + focusRequstCallback.nPortIndex = OMX_ALL; + focusRequstCallback.nIndex = OMX_IndexConfigCommonFocusStatus; + + if ( enabled ) + { + focusRequstCallback.bEnable = OMX_TRUE; + } + else + { + focusRequstCallback.bEnable = OMX_FALSE; + } + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + (OMX_INDEXTYPE) OMX_IndexConfigCallbackRequest, + &focusRequstCallback); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error registering focus callback 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDB("Autofocus callback for index 0x%x registered successfully", + OMX_IndexConfigCommonFocusStatus); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::returnFocusStatus(bool timeoutReached) +{ + status_t ret = NO_ERROR; + OMX_PARAM_FOCUSSTATUSTYPE eFocusStatus; + bool focusStatus = false; + BaseCameraAdapter::AdapterState state; + BaseCameraAdapter::getState(state); + + LOG_FUNCTION_NAME; + + OMX_INIT_STRUCT(eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); + + if( ( AF_ACTIVE & state ) != AF_ACTIVE ) + { + /// We don't send focus callback if focus was not started + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + + if ( !timeoutReached ) + { + ret = checkFocus(&eFocusStatus); + + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEA("Focus status check failed!"); + } + } + } + + if ( NO_ERROR == ret ) + { + + if ( timeoutReached ) + { + focusStatus = false; + } + else + { + + switch (eFocusStatus.eFocusStatus) + { + case OMX_FocusStatusReached: + { + focusStatus = true; + break; + } + case OMX_FocusStatusOff: + case OMX_FocusStatusUnableToReach: + case OMX_FocusStatusRequest: + default: + { + focusStatus = false; + break; + } + } + + stopAutoFocus(); + } + } + + if ( NO_ERROR == ret ) + { + + ret = BaseCameraAdapter::setState(CAMERA_CANCEL_AUTOFOCUS); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + } + + if ( NO_ERROR == ret ) + { + notifyFocusSubscribers(focusStatus); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + + LOG_FUNCTION_NAME; + + if ( NULL == eFocusStatus ) + { + CAMHAL_LOGEA("Invalid focus status"); + ret = -EINVAL; + } + + if ( OMX_StateExecuting != mComponentState ) + { + CAMHAL_LOGEA("OMX component not in executing state"); + ret = -EINVAL; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonFocusStatus, + eFocusStatus); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while retrieving focus status: 0x%x", eError); + ret = -1; + } + } + + if ( NO_ERROR == ret ) + { + CAMHAL_LOGDB("Focus Status: %d", eFocusStatus->eFocusStatus); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::updateFocusDistances(CameraParameters ¶ms) +{ + OMX_U32 focusNear, focusOptimal, focusFar; + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + ret = getFocusDistances(focusNear, focusOptimal, focusFar); + if ( NO_ERROR == ret) + { + ret = addFocusDistances(focusNear, focusOptimal, focusFar, params); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error in call to addFocusDistances() 0x%x", ret); + } + } + else + { + CAMHAL_LOGEB("Error in call to getFocusDistances() 0x%x", ret); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError; + + OMX_TI_CONFIG_FOCUSDISTANCETYPE focusDist; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = UNKNOWN_ERROR; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR(&focusDist, OMX_TI_CONFIG_FOCUSDISTANCETYPE); + focusDist.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; + + eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFocusDistance, + &focusDist); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while querying focus distances 0x%x", eError); + ret = UNKNOWN_ERROR; + } + + } + + if ( NO_ERROR == ret ) + { + near = focusDist.nFocusDistanceNear; + optimal = focusDist.nFocusDistanceOptimal; + far = focusDist.nFocusDistanceFar; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length) +{ + status_t ret = NO_ERROR; + uint32_t focusScale = 1000; + float distFinal; + + LOG_FUNCTION_NAME; + + if(mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity) + { + dist=0; + } + + if ( NO_ERROR == ret ) + { + if ( 0 == dist ) + { + strncpy(buffer, CameraParameters::FOCUS_DISTANCE_INFINITY, ( length - 1 )); + } + else + { + distFinal = dist; + distFinal /= focusScale; + snprintf(buffer, ( length - 1 ) , "%5.3f", distFinal); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::addFocusDistances(OMX_U32 &near, + OMX_U32 &optimal, + OMX_U32 &far, + CameraParameters& params) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + if ( NO_ERROR == ret ) + { + ret = encodeFocusDistance(near, mFocusDistNear, FOCUS_DIST_SIZE); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + ret = encodeFocusDistance(optimal, mFocusDistOptimal, FOCUS_DIST_SIZE); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + ret = encodeFocusDistance(far, mFocusDistFar, FOCUS_DIST_SIZE); + if ( NO_ERROR != ret ) + { + CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); + } + } + + if ( NO_ERROR == ret ) + { + snprintf(mFocusDistBuffer, ( FOCUS_DIST_BUFFER_SIZE - 1) ,"%s,%s,%s", mFocusDistNear, + mFocusDistOptimal, + mFocusDistFar); + + params.set(CameraParameters::KEY_FOCUS_DISTANCES, mFocusDistBuffer); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::setTouchFocus(size_t posX, + size_t posY, + size_t posWidth, + size_t posHeight, + size_t previewWidth, + size_t previewHeight) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_EXTFOCUSREGIONTYPE touchControl; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&touchControl, OMX_CONFIG_EXTFOCUSREGIONTYPE); + touchControl.nLeft = ( posX * TOUCH_FOCUS_RANGE ) / previewWidth; + touchControl.nTop = ( posY * TOUCH_FOCUS_RANGE ) / previewHeight; + touchControl.nWidth = ( posWidth * TOUCH_FOCUS_RANGE ) / previewWidth; + touchControl.nHeight = ( posHeight * TOUCH_FOCUS_RANGE ) / previewHeight; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + ( OMX_INDEXTYPE ) OMX_IndexConfigExtFocusRegion, + &touchControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while configuring touch focus 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDB("Touch focus %d,%d %d,%d configured successfuly", + ( int ) touchControl.nLeft, + ( int ) touchControl.nTop, + ( int ) touchControl.nWidth, + ( int ) touchControl.nHeight); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +}; diff --git a/camera/OMXCameraAdapter/OMXZoom.cpp b/camera/OMXCameraAdapter/OMXZoom.cpp new file mode 100644 index 0000000..9e59f3d --- /dev/null +++ b/camera/OMXCameraAdapter/OMXZoom.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 OMXZoom.cpp +* +* This file contains functionality for handling zoom configurations. +* +*/ + +#undef LOG_TAG + +#define LOG_TAG "CameraHAL" + +#include "CameraHal.h" +#include "OMXCameraAdapter.h" + +namespace android { + +const int32_t OMXCameraAdapter::ZOOM_STEPS [ZOOM_STAGES] = { + 65536, 68157, 70124, 72745, + 75366, 77988, 80609, 83231, + 86508, 89784, 92406, 95683, + 99615, 102892, 106168, 110100, + 114033, 117965, 122552, 126484, + 131072, 135660, 140247, 145490, + 150733, 155976, 161219, 167117, + 173015, 178913, 185467, 192020, + 198574, 205783, 212992, 220201, + 228065, 236585, 244449, 252969, + 262144, 271319, 281149, 290980, + 300810, 311951, 322437, 334234, + 346030, 357827, 370934, 384041, + 397148, 411566, 425984, 441057, + 456131, 472515, 488899, 506593, + 524288 }; + + +status_t OMXCameraAdapter::setParametersZoom(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state) +{ + status_t ret = NO_ERROR; + Mutex::Autolock lock(mZoomLock); + + LOG_FUNCTION_NAME; + + //Immediate zoom should not be avaialable while smooth zoom is running + if ( ( ZOOM_ACTIVE & state ) != ZOOM_ACTIVE ) + { + int zoom = params.getInt(CameraParameters::KEY_ZOOM); + if( ( zoom >= 0 ) && ( zoom < ZOOM_STAGES ) ) + { + mTargetZoomIdx = zoom; + + //Immediate zoom should be applied instantly ( CTS requirement ) + mCurrentZoomIdx = mTargetZoomIdx; + doZoom(mCurrentZoomIdx); + + CAMHAL_LOGDB("Zoom by App %d", zoom); + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::doZoom(int index) +{ + status_t ret = NO_ERROR; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_SCALEFACTORTYPE zoomControl; + static int prevIndex = 0; + + LOG_FUNCTION_NAME; + + if ( OMX_StateInvalid == mComponentState ) + { + CAMHAL_LOGEA("OMX component is in invalid state"); + ret = -1; + } + + if ( ( 0 > index) || ( ( ZOOM_STAGES - 1 ) < index ) ) + { + CAMHAL_LOGEB("Zoom index %d out of range", index); + ret = -EINVAL; + } + + if ( prevIndex == index ) + { + return NO_ERROR; + } + + if ( NO_ERROR == ret ) + { + OMX_INIT_STRUCT_PTR (&zoomControl, OMX_CONFIG_SCALEFACTORTYPE); + zoomControl.nPortIndex = OMX_ALL; + zoomControl.xHeight = ZOOM_STEPS[index]; + zoomControl.xWidth = ZOOM_STEPS[index]; + + eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, + OMX_IndexConfigCommonDigitalZoom, + &zoomControl); + if ( OMX_ErrorNone != eError ) + { + CAMHAL_LOGEB("Error while applying digital zoom 0x%x", eError); + ret = -1; + } + else + { + CAMHAL_LOGDA("Digital zoom applied successfully"); + prevIndex = index; + } + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::advanceZoom() +{ + status_t ret = NO_ERROR; + AdapterState state; + BaseCameraAdapter::getState(state); + + if ( mReturnZoomStatus ) + { + mTargetZoomIdx = mCurrentZoomIdx; + mReturnZoomStatus = false; + ret = doZoom(mCurrentZoomIdx); + notifyZoomSubscribers(mCurrentZoomIdx, true); + } + else if ( mCurrentZoomIdx != mTargetZoomIdx ) + { + if ( ZOOM_ACTIVE & state ) + { + if ( mCurrentZoomIdx < mTargetZoomIdx ) + { + mZoomInc = 1; + } + else + { + mZoomInc = -1; + } + + mCurrentZoomIdx += mZoomInc; + } + else + { + mCurrentZoomIdx = mTargetZoomIdx; + } + + ret = doZoom(mCurrentZoomIdx); + + if ( ZOOM_ACTIVE & state ) + { + if ( mCurrentZoomIdx == mTargetZoomIdx ) + { + CAMHAL_LOGDB("[Goal Reached] Smooth Zoom notify currentIdx = %d, targetIdx = %d", + mCurrentZoomIdx, + mTargetZoomIdx); + notifyZoomSubscribers(mCurrentZoomIdx, true); + + if ( NO_ERROR == ret ) + { + + ret = BaseCameraAdapter::setState(CAMERA_STOP_SMOOTH_ZOOM); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + + } + } + else + { + CAMHAL_LOGDB("[Advancing] Smooth Zoom notify currentIdx = %d, targetIdx = %d", + mCurrentZoomIdx, + mTargetZoomIdx); + notifyZoomSubscribers(mCurrentZoomIdx, false); + } + } + } + else if ( (mCurrentZoomIdx == mTargetZoomIdx ) && + ( ZOOM_ACTIVE & state ) ) + { + ret = BaseCameraAdapter::setState(CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM); + + if ( NO_ERROR == ret ) + { + ret = BaseCameraAdapter::commitState(); + } + else + { + ret |= BaseCameraAdapter::rollbackState(); + } + } + + return ret; +} + +status_t OMXCameraAdapter::startSmoothZoom(int targetIdx) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mZoomLock); + + CAMHAL_LOGDB("Start smooth zoom target = %d, mCurrentIdx = %d", + targetIdx, + mCurrentZoomIdx); + + if ( ( targetIdx >= 0 ) && ( targetIdx < ZOOM_STAGES ) ) + { + mTargetZoomIdx = targetIdx; + mZoomParameterIdx = mCurrentZoomIdx; + } + else + { + CAMHAL_LOGEB("Smooth value out of range %d!", targetIdx); + ret = -EINVAL; + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t OMXCameraAdapter::stopSmoothZoom() +{ + status_t ret = NO_ERROR; + Mutex::Autolock lock(mZoomLock); + + LOG_FUNCTION_NAME; + + if ( mTargetZoomIdx != mCurrentZoomIdx ) + { + mTargetZoomIdx = mCurrentZoomIdx; + mReturnZoomStatus = true; + CAMHAL_LOGDB("Stop smooth zoom mCurrentZoomIdx = %d, mTargetZoomIdx = %d", + mCurrentZoomIdx, + mTargetZoomIdx); + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +}; diff --git a/camera/SensorListener.cpp b/camera/SensorListener.cpp new file mode 100644 index 0000000..8b3e942 --- /dev/null +++ b/camera/SensorListener.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 SensorListener.cpp +* +* This file listens and propogates sensor events to CameraHal. +* +*/ + +#define LOG_TAG "CameraHAL" + +#include "SensorListener.h" +#include "CameraHal.h" + +#include <stdint.h> +#include <math.h> +#include <sys/types.h> + +namespace android { + +/*** static declarations ***/ +static const float RADIANS_2_DEG = (float) (180 / M_PI); +// measured values on device...might need tuning +static const int DEGREES_90_THRESH = 50; +static const int DEGREES_180_THRESH = 170; +static const int DEGREES_270_THRESH = 250; + +static int sensor_events_listener(int fd, int events, void* data) +{ + SensorListener* listener = (SensorListener*) data; + ssize_t num_sensors; + ASensorEvent sen_events[8]; + while ((num_sensors = listener->mSensorEventQueue->read(sen_events, 8)) > 0) { + for (int i = 0; i < num_sensors; i++) { + if (sen_events[i].type == Sensor::TYPE_ACCELEROMETER) { + float x = sen_events[i].vector.azimuth; + float y = sen_events[i].vector.pitch; + float z = sen_events[i].vector.roll; + float radius = 0; + int tilt = 0, orient = 0; + + CAMHAL_LOGVA("ACCELEROMETER EVENT"); + CAMHAL_LOGVB(" azimuth = %f pitch = %f roll = %f", + sen_events[i].vector.azimuth, + sen_events[i].vector.pitch, + sen_events[i].vector.roll); + // see http://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates + // about conversion from cartesian to spherical for orientation calculations + radius = (float) sqrt(x * x + y * y + z * z); + tilt = (int) asinf(z / radius) * RADIANS_2_DEG; + orient = (int) atan2f(-x, y) * RADIANS_2_DEG; + + if (orient < 0) { + orient += 360; + } + + if (orient >= DEGREES_270_THRESH) { + orient = 270; + } else if (orient >= DEGREES_180_THRESH) { + orient = 180; + } else if (orient >= DEGREES_90_THRESH) { + orient = 90; + } else { + orient = 0; + } + listener->handleOrientation(orient, tilt); + CAMHAL_LOGVB(" tilt = %d orientation = %d", tilt, orient); + } else if (sen_events[i].type == Sensor::TYPE_GYROSCOPE) { + CAMHAL_LOGVA("GYROSCOPE EVENT"); + } + } + } + + if (num_sensors < 0 && num_sensors != -EAGAIN) { + CAMHAL_LOGEB("reading events failed: %s", strerror(-num_sensors)); + } + + return 1; +} + +/****** public - member functions ******/ +SensorListener::SensorListener() { + LOG_FUNCTION_NAME; + + sensorsEnabled = 0; + mOrientationCb = NULL; + mSensorEventQueue = NULL; + mSensorLooperThread = NULL; + + LOG_FUNCTION_NAME_EXIT; +} + +SensorListener::~SensorListener() { + LOG_FUNCTION_NAME; + + CAMHAL_LOGDA("Kill looper thread"); + if (mSensorLooperThread.get()) { + // 1. Request exit + // 2. Wake up looper which should be polling for an event + // 3. Wait for exit + mSensorLooperThread->requestExit(); + mSensorLooperThread->wake(); + mSensorLooperThread->join(); + mSensorLooperThread.clear(); + mSensorLooperThread = NULL; + } + + CAMHAL_LOGDA("Kill looper"); + if (mLooper.get()) { + mLooper->removeFd(mSensorEventQueue->getFd()); + mLooper.clear(); + mLooper = NULL; + } + CAMHAL_LOGDA("SensorListener destroyed"); + + LOG_FUNCTION_NAME_EXIT; +} + +status_t SensorListener::initialize() { + status_t ret = NO_ERROR; + SensorManager& mgr(SensorManager::getInstance()); + Sensor const* const* list; + ssize_t count = 0; + Sensor const* accelerometer; + + LOG_FUNCTION_NAME; + + count = mgr.getSensorList(&list); + CAMHAL_LOGDB("numSensors = %lu", count); + + mSensorEventQueue = mgr.createEventQueue(); + + sp<Looper> mLooper = new Looper(false); + mLooper->addFd(mSensorEventQueue->getFd(), 0, ALOOPER_EVENT_INPUT, sensor_events_listener, this); + + if (mSensorLooperThread.get() == NULL) + mSensorLooperThread = new SensorLooperThread(mLooper.get()); + + if (mSensorLooperThread.get() == NULL) { + CAMHAL_LOGEA("Couldn't create sensor looper thread"); + ret = NO_MEMORY; + goto out; + } + + ret = mSensorLooperThread->run("sensor looper thread", PRIORITY_URGENT_DISPLAY); + if (ret == INVALID_OPERATION){ + CAMHAL_LOGDA("thread already running ?!?"); + } else if (ret != NO_ERROR) { + CAMHAL_LOGEA("couldn't run thread"); + goto out; + } + + out: + LOG_FUNCTION_NAME_EXIT; + return ret; +} + +void SensorListener::setCallbacks(orientation_callback_t orientation_cb, void *cookie) { + LOG_FUNCTION_NAME; + + if (orientation_cb) { + mOrientationCb = orientation_cb; + } + mCbCookie = cookie; + + LOG_FUNCTION_NAME_EXIT; +} + +void SensorListener::handleOrientation(uint32_t orientation, uint32_t tilt) { + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(&mLock); + + if (mOrientationCb && (sensorsEnabled & SENSOR_ORIENTATION)) { + mOrientationCb(orientation, tilt, mCbCookie); + } + + LOG_FUNCTION_NAME_EXIT; +} + +void SensorListener::enableSensor(sensor_type_t type) { + Sensor const* sensor; + SensorManager& mgr(SensorManager::getInstance()); + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(&mLock); + + if ((type & SENSOR_ORIENTATION) && !(sensorsEnabled & SENSOR_ORIENTATION)) { + sensor = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER); + CAMHAL_LOGDB("orientation = %p (%s)", sensor, sensor->getName().string()); + mSensorEventQueue->enableSensor(sensor); + mSensorEventQueue->setEventRate(sensor, ms2ns(100)); + sensorsEnabled |= SENSOR_ORIENTATION; + } + + LOG_FUNCTION_NAME_EXIT; +} + +void SensorListener::disableSensor(sensor_type_t type) { + Sensor const* sensor; + SensorManager& mgr(SensorManager::getInstance()); + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(&mLock); + + if ((type & SENSOR_ORIENTATION) && (sensorsEnabled & SENSOR_ORIENTATION)) { + sensor = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER); + CAMHAL_LOGDB("orientation = %p (%s)", sensor, sensor->getName().string()); + mSensorEventQueue->disableSensor(sensor); + sensorsEnabled &= ~SENSOR_ORIENTATION; + } + + LOG_FUNCTION_NAME_EXIT; +} + +} // namespace android diff --git a/camera/TICameraParameters.cpp b/camera/TICameraParameters.cpp new file mode 100644 index 0000000..2980645 --- /dev/null +++ b/camera/TICameraParameters.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + + + +#define LOG_TAG "CameraHAL" +#include <utils/Log.h> + +#include <string.h> +#include <stdlib.h> +#include <TICameraParameters.h> +#include "CameraHal.h" + +namespace android { + +//TI extensions to camera mode +const char TICameraParameters::HIGH_PERFORMANCE_MODE[] = "high-performance"; +const char TICameraParameters::HIGH_QUALITY_MODE[] = "high-quality"; +const char TICameraParameters::HIGH_QUALITY_ZSL_MODE[] = "high-quality-zsl"; +const char TICameraParameters::VIDEO_MODE[] = "video-mode"; + +// TI extensions to standard android Parameters +const char TICameraParameters::KEY_SUPPORTED_CAMERAS[] = "camera-indexes"; +const char TICameraParameters::KEY_CAMERA[] = "camera-index"; +const char TICameraParameters::KEY_SHUTTER_ENABLE[] = "shutter-enable"; +const char TICameraParameters::KEY_CAMERA_NAME[] = "camera-name"; +const char TICameraParameters::KEY_BURST[] = "burst-capture"; +const char TICameraParameters::KEY_CAP_MODE[] = "mode"; +const char TICameraParameters::KEY_VSTAB[] = "vstab"; +const char TICameraParameters::KEY_VSTAB_VALUES[] = "vstab-values"; +const char TICameraParameters::KEY_VNF[] = "vnf"; +const char TICameraParameters::KEY_SATURATION[] = "saturation"; +const char TICameraParameters::KEY_BRIGHTNESS[] = "brightness"; +const char TICameraParameters::KEY_EXPOSURE_MODE[] = "exposure"; +const char TICameraParameters::KEY_SUPPORTED_EXPOSURE[] = "exposure-mode-values"; +const char TICameraParameters::KEY_CONTRAST[] = "contrast"; +const char TICameraParameters::KEY_SHARPNESS[] = "sharpness"; +const char TICameraParameters::KEY_ISO[] = "iso"; +const char TICameraParameters::KEY_SUPPORTED_ISO_VALUES[] = "iso-mode-values"; +const char TICameraParameters::KEY_SUPPORTED_IPP[] = "ipp-values"; +const char TICameraParameters::KEY_IPP[] = "ipp"; +const char TICameraParameters::KEY_MAN_EXPOSURE[] = "manual-exposure"; +const char TICameraParameters::KEY_METERING_MODE[] = "meter-mode"; +const char TICameraParameters::KEY_PADDED_WIDTH[] = "padded-width"; +const char TICameraParameters::KEY_PADDED_HEIGHT[] = "padded-height"; +const char TICameraParameters::KEY_EXP_BRACKETING_RANGE[] = "exp-bracketing-range"; +const char TICameraParameters::KEY_TEMP_BRACKETING[] = "temporal-bracketing"; +const char TICameraParameters::KEY_TEMP_BRACKETING_RANGE_POS[] = "temporal-bracketing-range-positive"; +const char TICameraParameters::KEY_TEMP_BRACKETING_RANGE_NEG[] = "temporal-bracketing-range-negative"; +const char TICameraParameters::KEY_S3D_SUPPORTED[] = "s3d-supported"; +const char TICameraParameters::KEY_MEASUREMENT_ENABLE[] = "measurement"; +const char TICameraParameters::KEY_GBCE[] = "gbce"; +const char TICameraParameters::KEY_GLBCE[] = "glbce"; +const char TICameraParameters::KEY_CURRENT_ISO[] = "current-iso"; +const char TICameraParameters::KEY_SENSOR_ORIENTATION[] = "sensor-orientation"; +const char TICameraParameters::KEY_SENSOR_ORIENTATION_VALUES[] = "sensor-orientation-values"; +const char TICameraParameters::KEY_MINFRAMERATE[] = "min-framerate"; +const char TICameraParameters::KEY_MAXFRAMERATE[] = "max-framerate"; + +//TI extensions for enabling/disabling GLBCE +const char TICameraParameters::GLBCE_ENABLE[] = "enable"; +const char TICameraParameters::GLBCE_DISABLE[] = "disable"; + +//TI extensions for enabling/disabling GBCE +const char TICameraParameters::GBCE_ENABLE[] = "enable"; +const char TICameraParameters::GBCE_DISABLE[] = "disable"; + +//TI extensions for enabling/disabling measurement +const char TICameraParameters::MEASUREMENT_ENABLE[] = "enable"; +const char TICameraParameters::MEASUREMENT_DISABLE[] = "disable"; + +//TI extensions for zoom +const char TICameraParameters::ZOOM_SUPPORTED[] = "true"; +const char TICameraParameters::ZOOM_UNSUPPORTED[] = "false"; + +// TI extensions for 2D Preview in Stereo Mode +const char TICameraParameters::KEY_S3D2D_PREVIEW[] = "s3d2d-preview"; +const char TICameraParameters::KEY_S3D2D_PREVIEW_MODE[] = "s3d2d-preview-values"; + +//TI extensions for SAC/SMC +const char TICameraParameters::KEY_AUTOCONVERGENCE[] = "auto-convergence"; +const char TICameraParameters::KEY_AUTOCONVERGENCE_MODE[] = "auto-convergence-mode"; +const char TICameraParameters::KEY_MANUALCONVERGENCE_VALUES[] = "manual-convergence-values"; + +//TI extensions for setting EXIF tags +const char TICameraParameters::KEY_EXIF_MODEL[] = "exif-model"; +const char TICameraParameters::KEY_EXIF_MAKE[] = "exif-make"; + +//TI extensions for additiona GPS data +const char TICameraParameters::KEY_GPS_MAPDATUM[] = "gps-mapdatum"; +const char TICameraParameters::KEY_GPS_VERSION[] = "gps-version"; +const char TICameraParameters::KEY_GPS_DATESTAMP[] = "gps-datestamp"; + +//TI extensions for enabling/disabling shutter sound +const char TICameraParameters::SHUTTER_ENABLE[] = "true"; +const char TICameraParameters::SHUTTER_DISABLE[] = "false"; + +//TI extensions for Temporal Bracketing +const char TICameraParameters::BRACKET_ENABLE[] = "enable"; +const char TICameraParameters::BRACKET_DISABLE[] = "disable"; + +//TI extensions to Image post-processing +const char TICameraParameters::IPP_LDCNSF[] = "ldc-nsf"; +const char TICameraParameters::IPP_LDC[] = "ldc"; +const char TICameraParameters::IPP_NSF[] = "nsf"; +const char TICameraParameters::IPP_NONE[] = "off"; + +// TI extensions to standard android pixel formats +const char TICameraParameters::PIXEL_FORMAT_RAW[] = "raw"; +const char TICameraParameters::PIXEL_FORMAT_JPS[] = "jps"; +const char TICameraParameters::PIXEL_FORMAT_MPO[] = "mpo"; +const char TICameraParameters::PIXEL_FORMAT_RAW_JPEG[] = "raw+jpeg"; +const char TICameraParameters::PIXEL_FORMAT_RAW_MPO[] = "raw+mpo"; + +// TI extensions to standard android scene mode settings +const char TICameraParameters::SCENE_MODE_SPORT[] = "sport"; +const char TICameraParameters::SCENE_MODE_CLOSEUP[] = "closeup"; +const char TICameraParameters::SCENE_MODE_AQUA[] = "aqua"; +const char TICameraParameters::SCENE_MODE_SNOWBEACH[] = "snow-beach"; +const char TICameraParameters::SCENE_MODE_MOOD[] = "mood"; +const char TICameraParameters::SCENE_MODE_NIGHT_INDOOR[] = "night-indoor"; +const char TICameraParameters::SCENE_MODE_DOCUMENT[] = "document"; +const char TICameraParameters::SCENE_MODE_BARCODE[] = "barcode"; +const char TICameraParameters::SCENE_MODE_VIDEO_SUPER_NIGHT[] = "super-night"; +const char TICameraParameters::SCENE_MODE_VIDEO_CINE[] = "cine"; +const char TICameraParameters::SCENE_MODE_VIDEO_OLD_FILM[] = "old-film"; + +// TI extensions to standard android white balance values. +const char TICameraParameters::WHITE_BALANCE_TUNGSTEN[] = "tungsten"; +const char TICameraParameters::WHITE_BALANCE_HORIZON[] = "horizon"; +const char TICameraParameters::WHITE_BALANCE_SUNSET[] = "sunset"; +const char TICameraParameters::WHITE_BALANCE_FACE[] = "face-priority"; + +// TI extensions to standard android focus modes. +const char TICameraParameters::FOCUS_MODE_PORTRAIT[] = "portrait"; +const char TICameraParameters::FOCUS_MODE_EXTENDED[] = "extended"; +const char TICameraParameters::FOCUS_MODE_FACE[] = "face-priority"; + +// TI extensions to add values for effect settings. +const char TICameraParameters::EFFECT_NATURAL[] = "natural"; +const char TICameraParameters::EFFECT_VIVID[] = "vivid"; +const char TICameraParameters::EFFECT_COLOR_SWAP[] = "color-swap"; +const char TICameraParameters::EFFECT_BLACKWHITE[] = "blackwhite"; + +// TI extensions to add exposure preset modes +const char TICameraParameters::EXPOSURE_MODE_OFF[] = "off"; +const char TICameraParameters::EXPOSURE_MODE_AUTO[] = "auto"; +const char TICameraParameters::EXPOSURE_MODE_NIGHT[] = "night"; +const char TICameraParameters::EXPOSURE_MODE_BACKLIGHT[] = "backlighting"; +const char TICameraParameters::EXPOSURE_MODE_SPOTLIGHT[] = "spotlight"; +const char TICameraParameters::EXPOSURE_MODE_SPORTS[] = "sports"; +const char TICameraParameters::EXPOSURE_MODE_SNOW[] = "snow"; +const char TICameraParameters::EXPOSURE_MODE_BEACH[] = "beach"; +const char TICameraParameters::EXPOSURE_MODE_APERTURE[] = "aperture"; +const char TICameraParameters::EXPOSURE_MODE_SMALL_APERTURE[] = "small-aperture"; +const char TICameraParameters::EXPOSURE_MODE_FACE[] = "face-priority"; + +// TI extensions to add iso values +const char TICameraParameters::ISO_MODE_AUTO[] = "auto"; +const char TICameraParameters::ISO_MODE_100[] = "100"; +const char TICameraParameters::ISO_MODE_200[] = "200"; +const char TICameraParameters::ISO_MODE_400[] = "400"; +const char TICameraParameters::ISO_MODE_800[] = "800"; +const char TICameraParameters::ISO_MODE_1000[] = "1000"; +const char TICameraParameters::ISO_MODE_1200[] = "1200"; +const char TICameraParameters::ISO_MODE_1600[] = "1600"; + +// TI extensions to add auto convergence values +const char TICameraParameters::AUTOCONVERGENCE_MODE_DISABLE[] = "mode-disable"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_FRAME[] = "mode-frame"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_CENTER[] = "mode-center"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_FFT[] = "mode-fft"; +const char TICameraParameters::AUTOCONVERGENCE_MODE_MANUAL[] = "mode-manual"; + +//TI values for camera direction +const char TICameraParameters::FACING_FRONT[]="front"; +const char TICameraParameters::FACING_BACK[]="back"; + +//TI extensions to flash settings +const char TICameraParameters::FLASH_MODE_FILL_IN[] = "fill-in"; + +//TI extensions to add sensor orientation parameters +const char TICameraParameters::ORIENTATION_SENSOR_NONE[] = "0"; +const char TICameraParameters::ORIENTATION_SENSOR_90[] = "90"; +const char TICameraParameters::ORIENTATION_SENSOR_180[] = "180"; +const char TICameraParameters::ORIENTATION_SENSOR_270[] = "270"; +}; + diff --git a/camera/V4LCameraAdapter/V4LCameraAdapter.cpp b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp new file mode 100644 index 0000000..446a809 --- /dev/null +++ b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp @@ -0,0 +1,615 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 V4LCameraAdapter.cpp +* +* This file maps the Camera Hardware Interface to V4L2. +* +*/ + + +#include "V4LCameraAdapter.h" +#include "CameraHal.h" +#include "TICameraParameters.h" +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/select.h> +#include <linux/videodev.h> + + +#include <cutils/properties.h> +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +static int mDebugFps = 0; + +#define Q16_OFFSET 16 + +#define HERE(Msg) {CAMHAL_LOGEB("--===line %d, %s===--\n", __LINE__, Msg);} + +namespace android { + +#undef LOG_TAG +///Maintain a separate tag for V4LCameraAdapter logs to isolate issues OMX specific +#define LOG_TAG "CameraHAL" + +//frames skipped before recalculating the framerate +#define FPS_PERIOD 30 + +static V4LCameraAdapter *gCameraAdapter = NULL; +Mutex gAdapterLock; +const char *device = DEVICE; + + +/*--------------------Camera Adapter Class STARTS here-----------------------------*/ + +status_t V4LCameraAdapter::initialize(CameraProperties::Properties* caps, int sensor_index) +{ + LOG_FUNCTION_NAME; + + char value[PROPERTY_VALUE_MAX]; + property_get("debug.camera.showfps", value, "0"); + mDebugFps = atoi(value); + + int ret = NO_ERROR; + + // Allocate memory for video info structure + mVideoInfo = (struct VideoInfo *) calloc (1, sizeof (struct VideoInfo)); + if(!mVideoInfo) + { + return NO_MEMORY; + } + + if ((mCameraHandle = open(device, O_RDWR)) == -1) + { + CAMHAL_LOGEB("Error while opening handle to V4L2 Camera: %s", strerror(errno)); + return -EINVAL; + } + + ret = ioctl (mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap); + if (ret < 0) + { + CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera"); + return -EINVAL; + } + + if ((mVideoInfo->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) + { + CAMHAL_LOGEA("Error while adapter initialization: video capture not supported."); + return -EINVAL; + } + + if (!(mVideoInfo->cap.capabilities & V4L2_CAP_STREAMING)) + { + CAMHAL_LOGEA("Error while adapter initialization: Capture device does not support streaming i/o"); + return -EINVAL; + } + + // Initialize flags + mPreviewing = false; + mVideoInfo->isStreaming = false; + mRecording = false; + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType) +{ + + status_t ret = NO_ERROR; + + if ( !mVideoInfo->isStreaming ) + { + return NO_ERROR; + } + + int i = mPreviewBufs.valueFor(( unsigned int )frameBuf); + if(i<0) + { + return BAD_VALUE; + } + + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); + if (ret < 0) { + CAMHAL_LOGEA("Init: VIDIOC_QBUF Failed"); + return -1; + } + + nQueued++; + + return ret; + +} + +status_t V4LCameraAdapter::setParameters(const CameraParameters ¶ms) +{ + LOG_FUNCTION_NAME; + + status_t ret = NO_ERROR; + + int width, height; + + params.getPreviewSize(&width, &height); + + CAMHAL_LOGDB("Width * Height %d x %d format 0x%x", width, height, DEFAULT_PIXEL_FORMAT); + + mVideoInfo->width = width; + mVideoInfo->height = height; + mVideoInfo->framesizeIn = (width * height << 1); + mVideoInfo->formatIn = DEFAULT_PIXEL_FORMAT; + + mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->format.fmt.pix.width = width; + mVideoInfo->format.fmt.pix.height = height; + mVideoInfo->format.fmt.pix.pixelformat = DEFAULT_PIXEL_FORMAT; + + ret = ioctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format); + if (ret < 0) { + CAMHAL_LOGEB("Open: VIDIOC_S_FMT Failed: %s", strerror(errno)); + return ret; + } + + // Udpate the current parameter set + mParams = params; + + LOG_FUNCTION_NAME_EXIT; + return ret; +} + + +void V4LCameraAdapter::getParameters(CameraParameters& params) +{ + LOG_FUNCTION_NAME; + + // Return the current parameter set + params = mParams; + + LOG_FUNCTION_NAME_EXIT; +} + + +///API to give the buffers to Adapter +status_t V4LCameraAdapter::useBuffers(CameraMode mode, void* bufArr, int num, size_t length, unsigned int queueable) +{ + status_t ret = NO_ERROR; + + LOG_FUNCTION_NAME; + + Mutex::Autolock lock(mLock); + + switch(mode) + { + case CAMERA_PREVIEW: + ret = UseBuffersPreview(bufArr, num); + break; + + //@todo Insert Image capture case here + + case CAMERA_VIDEO: + //@warn Video capture is not fully supported yet + ret = UseBuffersPreview(bufArr, num); + break; + + } + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::UseBuffersPreview(void* bufArr, int num) +{ + int ret = NO_ERROR; + + if(NULL == bufArr) + { + return BAD_VALUE; + } + + //First allocate adapter internal buffers at V4L level for USB Cam + //These are the buffers from which we will copy the data into overlay buffers + /* Check if camera can handle NB_BUFFER buffers */ + mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; + mVideoInfo->rb.count = num; + + ret = ioctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); + if (ret < 0) { + CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); + return ret; + } + + for (int i = 0; i < num; i++) { + + memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer)); + + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf); + if (ret < 0) { + CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno)); + return ret; + } + + mVideoInfo->mem[i] = mmap (0, + mVideoInfo->buf.length, + PROT_READ | PROT_WRITE, + MAP_SHARED, + mCameraHandle, + mVideoInfo->buf.m.offset); + + if (mVideoInfo->mem[i] == MAP_FAILED) { + CAMHAL_LOGEB("Unable to map buffer (%s)", strerror(errno)); + return -1; + } + + uint32_t *ptr = (uint32_t*) bufArr; + + //Associate each Camera internal buffer with the one from Overlay + mPreviewBufs.add((int)ptr[i], i); + + } + + // Update the preview buffer count + mPreviewBufferCount = num; + + return ret; +} + +status_t V4LCameraAdapter::startPreview() +{ + status_t ret = NO_ERROR; + + Mutex::Autolock lock(mPreviewBufsLock); + + if(mPreviewing) + { + return BAD_VALUE; + } + + for (int i = 0; i < mPreviewBufferCount; i++) { + + mVideoInfo->buf.index = i; + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); + if (ret < 0) { + CAMHAL_LOGEA("VIDIOC_QBUF Failed"); + return -EINVAL; + } + + nQueued++; + } + + enum v4l2_buf_type bufType; + if (!mVideoInfo->isStreaming) { + bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl (mCameraHandle, VIDIOC_STREAMON, &bufType); + if (ret < 0) { + CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno)); + return ret; + } + + mVideoInfo->isStreaming = true; + } + + // Create and start preview thread for receiving buffers from V4L Camera + mPreviewThread = new PreviewThread(this); + + CAMHAL_LOGDA("Created preview thread"); + + + //Update the flag to indicate we are previewing + mPreviewing = true; + + return ret; + +} + +status_t V4LCameraAdapter::stopPreview() +{ + enum v4l2_buf_type bufType; + int ret = NO_ERROR; + + Mutex::Autolock lock(mPreviewBufsLock); + + if(!mPreviewing) + { + return NO_INIT; + } + + if (mVideoInfo->isStreaming) { + bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType); + if (ret < 0) { + CAMHAL_LOGEB("StopStreaming: Unable to stop capture: %s", strerror(errno)); + return ret; + } + + mVideoInfo->isStreaming = false; + } + + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + nQueued = 0; + nDequeued = 0; + + /* Unmap buffers */ + for (int i = 0; i < mPreviewBufferCount; i++) + if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0) + CAMHAL_LOGEA("Unmap failed"); + + mPreviewBufs.clear(); + + mPreviewThread->requestExitAndWait(); + mPreviewThread.clear(); + + return ret; + +} + +char * V4LCameraAdapter::GetFrame(int &index) +{ + int ret; + + mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; + + /* DQ */ + ret = ioctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf); + if (ret < 0) { + CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed"); + return NULL; + } + nDequeued++; + + index = mVideoInfo->buf.index; + + return (char *)mVideoInfo->mem[mVideoInfo->buf.index]; +} + +//API to get the frame size required to be allocated. This size is used to override the size passed +//by camera service when VSTAB/VNF is turned ON for example +status_t V4LCameraAdapter::getFrameSize(size_t &width, size_t &height) +{ + status_t ret = NO_ERROR; + + // Just return the current preview size, nothing more to do here. + mParams.getPreviewSize(( int * ) &width, + ( int * ) &height); + + LOG_FUNCTION_NAME_EXIT; + + return ret; +} + +status_t V4LCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) +{ + // We don't support meta data, so simply return + return NO_ERROR; +} + +status_t V4LCameraAdapter::getPictureBufferSize(size_t &length, size_t bufferCount) +{ + // We don't support image capture yet, safely return from here without messing up + return NO_ERROR; +} + +static void debugShowFPS() +{ + static int mFrameCount = 0; + static int mLastFrameCount = 0; + static nsecs_t mLastFpsTime = 0; + static float mFps = 0; + mFrameCount++; + if (!(mFrameCount & 0x1F)) { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFpsTime; + mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFpsTime = now; + mLastFrameCount = mFrameCount; + LOGD("Camera %d Frames, %f FPS", mFrameCount, mFps); + } + // XXX: mFPS has the value we want +} + +status_t V4LCameraAdapter::recalculateFPS() +{ + float currentFPS; + + mFrameCount++; + + if ( ( mFrameCount % FPS_PERIOD ) == 0 ) + { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFPSTime; + currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFPSTime = now; + mLastFrameCount = mFrameCount; + + if ( 1 == mIter ) + { + mFPS = currentFPS; + } + else + { + //cumulative moving average + mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter; + } + + mLastFPS = mFPS; + mIter++; + } + + return NO_ERROR; +} + +void V4LCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) +{ + LOG_FUNCTION_NAME; + + LOG_FUNCTION_NAME_EXIT; +} + + +V4LCameraAdapter::V4LCameraAdapter() +{ + LOG_FUNCTION_NAME; + + // Nothing useful to do in the constructor + + LOG_FUNCTION_NAME_EXIT; +} + +V4LCameraAdapter::~V4LCameraAdapter() +{ + LOG_FUNCTION_NAME; + + // Close the camera handle and free the video info structure + close(mCameraHandle); + + if (mVideoInfo) + { + free(mVideoInfo); + mVideoInfo = NULL; + } + + LOG_FUNCTION_NAME_EXIT; +} + +/* Preview Thread */ +// --------------------------------------------------------------------------- + +int V4LCameraAdapter::previewThread() +{ + status_t ret = NO_ERROR; + int width, height; + CameraFrame frame; + + if (mPreviewing) + { + int index = 0; + char *fp = this->GetFrame(index); + if(!fp) + { + return BAD_VALUE; + } + + uint8_t* ptr = (uint8_t*) mPreviewBufs.keyAt(index); + + int width, height; + uint16_t* dest = (uint16_t*)ptr; + uint16_t* src = (uint16_t*) fp; + mParams.getPreviewSize(&width, &height); + for(int i=0;i<height;i++) + { + for(int j=0;j<width;j++) + { + //*dest = *src; + //convert from YUYV to UYVY supported in Camera service + *dest = (((*src & 0xFF000000)>>24)<<16)|(((*src & 0x00FF0000)>>16)<<24) | + (((*src & 0xFF00)>>8)<<0)|(((*src & 0x00FF)>>0)<<8); + src++; + dest++; + } + dest += 4096/2-width; + } + + mParams.getPreviewSize(&width, &height); + frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC; + frame.mBuffer = ptr; + frame.mLength = width*height*2; + frame.mAlignment = width*2; + frame.mOffset = 0; + frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);; + + ret = sendFrameToSubscribers(&frame); + + } + + return ret; +} + +extern "C" CameraAdapter* CameraAdapter_Factory() +{ + Mutex::Autolock lock(gAdapterLock); + + LOG_FUNCTION_NAME; + + if ( NULL == gCameraAdapter ) + { + CAMHAL_LOGDA("Creating new Camera adapter instance"); + gCameraAdapter= new V4LCameraAdapter(); + } + else + { + CAMHAL_LOGDA("Reusing existing Camera adapter instance"); + } + + + LOG_FUNCTION_NAME_EXIT; + + return gCameraAdapter; +} + +extern "C" int CameraAdapter_Capabilities(CameraProperties::Properties* properties_array, + const unsigned int starting_camera, + const unsigned int max_camera) { + int num_cameras_supported = 0; + CameraProperties::Properties* properties = NULL; + + LOG_FUNCTION_NAME; + + if(!properties_array) + { + return -EINVAL; + } + + // TODO: Need to tell camera properties what other cameras we can support + if (starting_camera + num_cameras_supported < max_camera) { + num_cameras_supported++; + properties = properties_array + starting_camera; + properties->set(CameraProperties::CAMERA_NAME, "USBCamera"); + } + + LOG_FUNCTION_NAME_EXIT; + + return num_cameras_supported; +} + +}; + + +/*--------------------Camera Adapter Class ENDS here-----------------------------*/ + diff --git a/camera/inc/ANativeWindowDisplayAdapter.h b/camera/inc/ANativeWindowDisplayAdapter.h new file mode 100644 index 0000000..89c2cf1 --- /dev/null +++ b/camera/inc/ANativeWindowDisplayAdapter.h @@ -0,0 +1,188 @@ +/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * 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.
+ */
+
+
+
+#include "CameraHal.h"
+#include <ui/egl/android_natives.h>
+#include <ui/GraphicBufferMapper.h>
+#include <hal_public.h>
+
+//temporarily define format here
+#define HAL_PIXEL_FORMAT_NV12 0x100
+
+namespace android {
+
+/**
+ * Display handler class - This class basically handles the buffer posting to display
+ */
+
+class ANativeWindowDisplayAdapter : public DisplayAdapter
+{
+public:
+
+ typedef struct
+ {
+ void *mBuffer;
+ void *mUser;
+ int mOffset;
+ int mWidth;
+ int mHeight;
+ int mWidthStride;
+ int mHeightStride;
+ int mLength;
+ CameraFrame::FrameType mType;
+ } DisplayFrame;
+
+ enum DisplayStates
+ {
+ DISPLAY_INIT = 0,
+ DISPLAY_STARTED,
+ DISPLAY_STOPPED,
+ DISPLAY_EXITED
+ };
+
+public:
+
+ ANativeWindowDisplayAdapter();
+ virtual ~ANativeWindowDisplayAdapter();
+
+ ///Initializes the display adapter creates any resources required
+ virtual status_t initialize();
+
+ virtual int setPreviewWindow(struct preview_stream_ops *window);
+ virtual int setFrameProvider(FrameNotifier *frameProvider);
+ virtual int setErrorHandler(ErrorNotifier *errorNotifier);
+ virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL, S3DParameters *s3dParams = NULL);
+ virtual int disableDisplay();
+ virtual status_t pauseDisplay(bool pause);
+
+#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
+
+ //Used for shot to snapshot measurement
+ virtual status_t setSnapshotTimeRef(struct timeval *refTime = NULL);
+
+#endif
+
+ virtual int useBuffers(void* bufArr, int num);
+ virtual bool supportsExternalBuffering();
+
+ //Implementation of inherited interfaces
+ virtual void* allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs);
+ virtual uint32_t * getOffsets() ;
+ virtual int getFd() ;
+ virtual int freeBuffer(void* buf);
+
+ virtual int maxQueueableBuffers(unsigned int& queueable);
+
+ ///Class specific functions
+ static void frameCallbackRelay(CameraFrame* caFrame);
+ void frameCallback(CameraFrame* caFrame);
+
+ void displayThread();
+
+ private:
+ void destroy();
+ bool processHalMsg();
+ status_t PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame);
+ bool handleFrameReturn();
+
+public:
+
+ static const int DISPLAY_TIMEOUT;
+ static const int FAILED_DQS_TO_SUSPEND;
+
+ class DisplayThread : public Thread
+ {
+ ANativeWindowDisplayAdapter* mDisplayAdapter;
+ TIUTILS::MessageQueue mDisplayThreadQ;
+
+ public:
+ DisplayThread(ANativeWindowDisplayAdapter* da)
+ : Thread(false), mDisplayAdapter(da) { }
+
+ ///Returns a reference to the display message Q for display adapter to post messages
+ TIUTILS::MessageQueue& msgQ()
+ {
+ return mDisplayThreadQ;
+ }
+
+ virtual bool threadLoop()
+ {
+ mDisplayAdapter->displayThread();
+ return false;
+ }
+
+ enum DisplayThreadCommands
+ {
+ DISPLAY_START,
+ DISPLAY_STOP,
+ DISPLAY_FRAME,
+ DISPLAY_EXIT
+ };
+ };
+
+ //friend declarations
+friend class DisplayThread;
+
+private:
+ int postBuffer(void* displayBuf);
+
+private:
+ bool mFirstInit;
+ bool mSuspend;
+ int mFailedDQs;
+ bool mPaused; //Pause state
+ preview_stream_ops_t* mANativeWindow;
+ sp<DisplayThread> mDisplayThread;
+ FrameProvider *mFrameProvider; ///Pointer to the frame provider interface
+ TIUTILS::MessageQueue mDisplayQ;
+ unsigned int mDisplayState;
+ ///@todo Have a common class for these members
+ mutable Mutex mLock;
+ bool mDisplayEnabled;
+ int mBufferCount;
+ buffer_handle_t** mBufferHandleMap;
+ IMG_native_handle_t** mGrallocHandleMap;
+ uint32_t* mOffsetsMap;
+ int mFD;
+ KeyedVector<int, int> mFramesWithCameraAdapterMap;
+ sp<ErrorNotifier> mErrorNotifier;
+
+ uint32_t mFrameWidth;
+ uint32_t mFrameHeight;
+ uint32_t mPreviewWidth;
+ uint32_t mPreviewHeight;
+
+ uint32_t mXOff;
+ uint32_t mYOff;
+
+ const char *mPixelFormat;
+
+#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
+ //Used for calculating standby to first shot
+ struct timeval mStandbyToShot;
+ bool mMeasureStandby;
+ //Used for shot to snapshot/shot calculation
+ struct timeval mStartCapture;
+ bool mShotToShot;
+
+#endif
+
+};
+
+};
+
diff --git a/camera/inc/BaseCameraAdapter.h b/camera/inc/BaseCameraAdapter.h new file mode 100644 index 0000000..15fb73f --- /dev/null +++ b/camera/inc/BaseCameraAdapter.h @@ -0,0 +1,245 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef BASE_CAMERA_ADAPTER_H +#define BASE_CAMERA_ADAPTER_H + +#include "CameraHal.h" + +namespace android { + +class BaseCameraAdapter : public CameraAdapter +{ + +public: + + BaseCameraAdapter(); + virtual ~BaseCameraAdapter(); + + ///Initialzes the camera adapter creates any resources required + virtual status_t initialize(CameraProperties::Properties*, int sensor_index = 0) = 0; + + virtual int setErrorHandler(ErrorNotifier *errorNotifier); + + //Message/Frame notification APIs + virtual void enableMsgType(int32_t msgs, frame_callback callback=NULL, event_callback eventCb=NULL, void* cookie=NULL); + virtual void disableMsgType(int32_t msgs, void* cookie); + virtual void returnFrame(void * frameBuf, CameraFrame::FrameType frameType); + + //APIs to configure Camera adapter and get the current parameter set + virtual status_t setParameters(const CameraParameters& params) = 0; + virtual void getParameters(CameraParameters& params) = 0; + + //API to send a command to the camera + virtual status_t sendCommand(CameraCommands operation, int value1 = 0, int value2 = 0, int value3 = 0 ); + + virtual status_t registerImageReleaseCallback(release_image_buffers_callback callback, void *user_data); + + virtual status_t registerEndCaptureCallback(end_image_capture_callback callback, void *user_data); + + //Retrieves the current Adapter state + virtual AdapterState getState(); + //Retrieves the next Adapter state + virtual AdapterState getNextState(); + +protected: + //The first two methods will try to switch the adapter state. + //Every call to setState() should be followed by a corresponding + //call to commitState(). If the state switch fails, then it will + //get reset to the previous state via rollbackState(). + virtual status_t setState(CameraCommands operation); + virtual status_t commitState(); + virtual status_t rollbackState(); + + // Retrieves the current Adapter state - for internal use (not locked) + virtual status_t getState(AdapterState &state); + // Retrieves the next Adapter state - for internal use (not locked) + virtual status_t getNextState(AdapterState &state); + + //-----------Interface that needs to be implemented by deriving classes -------------------- + + //Should be implmented by deriving classes in order to start image capture + virtual status_t takePicture(); + + //Should be implmented by deriving classes in order to start image capture + virtual status_t stopImageCapture(); + + //Should be implmented by deriving classes in order to start temporal bracketing + virtual status_t startBracketing(int range); + + //Should be implemented by deriving classes in order to stop temporal bracketing + virtual status_t stopBracketing(); + + //Should be implemented by deriving classes in oder to initiate autoFocus + virtual status_t autoFocus(); + + //Should be implemented by deriving classes in oder to initiate autoFocus + virtual status_t cancelAutoFocus(); + + //Should be called by deriving classes in order to do some bookkeeping + virtual status_t startVideoCapture(); + + //Should be called by deriving classes in order to do some bookkeeping + virtual status_t stopVideoCapture(); + + //Should be implemented by deriving classes in order to start camera preview + virtual status_t startPreview(); + + //Should be implemented by deriving classes in order to stop camera preview + virtual status_t stopPreview(); + + //Should be implemented by deriving classes in order to start smooth zoom + virtual status_t startSmoothZoom(int targetIdx); + + //Should be implemented by deriving classes in order to stop smooth zoom + virtual status_t stopSmoothZoom(); + + //Should be implemented by deriving classes in order to stop smooth zoom + virtual status_t useBuffers(CameraMode mode, void* bufArr, int num, size_t length, unsigned int queueable); + + //Should be implemented by deriving classes in order queue a released buffer in CameraAdapter + virtual status_t fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType); + + //API to get the frame size required to be allocated. This size is used to override the size passed + //by camera service when VSTAB/VNF is turned ON for example + virtual status_t getFrameSize(size_t &width, size_t &height); + + //API to get required data frame size + virtual status_t getFrameDataSize(size_t &dataFrameSize, size_t bufferCount); + + //API to get required picture buffers size with the current configuration in CameraParameters + virtual status_t getPictureBufferSize(size_t &length, size_t bufferCount); + + // Should be implemented by deriving classes in order to start face detection + // ( if supported ) + virtual status_t startFaceDetection(); + + // Should be implemented by deriving classes in order to stop face detection + // ( if supported ) + virtual status_t stopFaceDetection(); + + // Receive orientation events from CameraHal + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt); + + // ---------------------Interface ends----------------------------------- + + status_t notifyFocusSubscribers(bool status); + status_t notifyShutterSubscribers(); + status_t notifyZoomSubscribers(int zoomIdx, bool targetReached); + status_t notifyFaceSubscribers(sp<CameraFDResult> &faces); + + //Send the frame to subscribers + status_t sendFrameToSubscribers(CameraFrame *frame); + + //Resets the refCount for this particular frame + status_t resetFrameRefCount(CameraFrame &frame); + + //A couple of helper functions + void setFrameRefCount(void* frameBuf, CameraFrame::FrameType frameType, int refCount); + int getFrameRefCount(void* frameBuf, CameraFrame::FrameType frameType); + + enum FrameState { + STOPPED = 0, + RUNNING + }; + + enum FrameCommands { + START_PREVIEW = 0, + START_RECORDING, + RETURN_FRAME, + STOP_PREVIEW, + STOP_RECORDING, + DO_AUTOFOCUS, + TAKE_PICTURE, + FRAME_EXIT + }; + + enum AdapterCommands { + ACK = 0, + ERROR + }; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + struct timeval mStartFocus; + struct timeval mStartCapture; + +#endif + + mutable Mutex mReturnFrameLock; + + //Lock protecting the Adapter state + mutable Mutex mLock; + AdapterState mAdapterState; + AdapterState mNextState; + + //Different frame subscribers get stored using these + KeyedVector<int, frame_callback> mFrameSubscribers; + KeyedVector<int, frame_callback> mFrameDataSubscribers; + KeyedVector<int, frame_callback> mVideoSubscribers; + KeyedVector<int, frame_callback> mImageSubscribers; + KeyedVector<int, frame_callback> mRawSubscribers; + KeyedVector<int, event_callback> mFocusSubscribers; + KeyedVector<int, event_callback> mZoomSubscribers; + KeyedVector<int, event_callback> mShutterSubscribers; + KeyedVector<int, event_callback> mFaceSubscribers; + + //Preview buffer management data + int *mPreviewBuffers; + int mPreviewBufferCount; + size_t mPreviewBuffersLength; + KeyedVector<int, int> mPreviewBuffersAvailable; + mutable Mutex mPreviewBufferLock; + + //Video buffer management data + int *mVideoBuffers; + KeyedVector<int, int> mVideoBuffersAvailable; + int mVideoBuffersCount; + size_t mVideoBuffersLength; + mutable Mutex mVideoBufferLock; + + //Image buffer management data + int *mCaptureBuffers; + KeyedVector<int, bool> mCaptureBuffersAvailable; + int mCaptureBuffersCount; + size_t mCaptureBuffersLength; + mutable Mutex mCaptureBufferLock; + + //Metadata buffermanagement + int *mPreviewDataBuffers; + KeyedVector<int, bool> mPreviewDataBuffersAvailable; + int mPreviewDataBuffersCount; + size_t mPreviewDataBuffersLength; + mutable Mutex mPreviewDataBufferLock; + + TIUTILS::MessageQueue mFrameQ; + TIUTILS::MessageQueue mAdapterQ; + mutable Mutex mSubscriberLock; + ErrorNotifier *mErrorNotifier; + release_image_buffers_callback mReleaseImageBuffersCallback; + end_image_capture_callback mEndImageCaptureCallback; + void *mReleaseData; + void *mEndCaptureData; + bool mRecording; +}; + +}; + +#endif //BASE_CAMERA_ADAPTER_H + + diff --git a/camera/inc/CameraHal.h b/camera/inc/CameraHal.h new file mode 100644 index 0000000..94ed67d --- /dev/null +++ b/camera/inc/CameraHal.h @@ -0,0 +1,1144 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_H +#define ANDROID_HARDWARE_CAMERA_HARDWARE_H + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include <linux/videodev2.h> +#include "binder/MemoryBase.h" +#include "binder/MemoryHeapBase.h" +#include <utils/threads.h> +#include <camera/CameraParameters.h> +#include <hardware/camera.h> +#include "MessageQueue.h" +#include "Semaphore.h" +#include "CameraProperties.h" +#include "DebugUtils.h" +#include "SensorListener.h" + +#define MIN_WIDTH 640 +#define MIN_HEIGHT 480 +#define PICTURE_WIDTH 3264 /* 5mp - 2560. 8mp - 3280 */ /* Make sure it is a multiple of 16. */ +#define PICTURE_HEIGHT 2448 /* 5mp - 2048. 8mp - 2464 */ /* Make sure it is a multiple of 16. */ +#define PREVIEW_WIDTH 176 +#define PREVIEW_HEIGHT 144 +#define PIXEL_FORMAT V4L2_PIX_FMT_UYVY + +#define VIDEO_FRAME_COUNT_MAX 8 //NUM_OVERLAY_BUFFERS_REQUESTED +#define MAX_CAMERA_BUFFERS 8 //NUM_OVERLAY_BUFFERS_REQUESTED +#define MAX_ZOOM 3 +#define THUMB_WIDTH 80 +#define THUMB_HEIGHT 60 +#define PIX_YUV422I 0 +#define PIX_YUV420P 1 + +#define SATURATION_OFFSET 100 +#define SHARPNESS_OFFSET 100 +#define CONTRAST_OFFSET 100 + +//Enables Absolute PPM measurements in logcat +#define PPM_INSTRUMENTATION_ABS 1 + +//Uncomment to enable more verbose/debug logs +//#define DEBUG_LOG + +///Camera HAL Logging Functions +#ifndef DEBUG_LOG + +#define CAMHAL_LOGDA(str) +#define CAMHAL_LOGDB(str, ...) +#define CAMHAL_LOGVA(str) +#define CAMHAL_LOGVB(str, ...) + +#define CAMHAL_LOGEA LOGE +#define CAMHAL_LOGEB LOGE + +#undef LOG_FUNCTION_NAME +#undef LOG_FUNCTION_NAME_EXIT +#define LOG_FUNCTION_NAME +#define LOG_FUNCTION_NAME_EXIT + +#else + +#define CAMHAL_LOGDA DBGUTILS_LOGDA +#define CAMHAL_LOGDB DBGUTILS_LOGDB +#define CAMHAL_LOGVA DBGUTILS_LOGVA +#define CAMHAL_LOGVB DBGUTILS_LOGVB + +#define CAMHAL_LOGEA DBGUTILS_LOGEA +#define CAMHAL_LOGEB DBGUTILS_LOGEB + +#endif + + + +#define NONNEG_ASSIGN(x,y) \ + if(x > -1) \ + y = x + +namespace android { + +#define PARAM_BUFFER 6000 + +///Forward declarations +class CameraHal; +class CameraFrame; +class CameraHalEvent; +class DisplayFrame; + +class CameraArea : public RefBase +{ +public: + + CameraArea(ssize_t top, + ssize_t left, + ssize_t bottom, + ssize_t right, + size_t weight) : mTop(top), + mLeft(left), + mBottom(bottom), + mRight(right), + mWeight(weight) {} + + status_t transfrom(size_t width, + size_t height, + size_t &top, + size_t &left, + size_t &areaWidth, + size_t &areaHeight); + + bool isValid() + { + return ( ( 0 != mTop ) || ( 0 != mLeft ) || ( 0 != mBottom ) || ( 0 != mRight) ); + } + + size_t getWeight() + { + return mWeight; + } + + static status_t parseFocusArea(const char *area, + size_t areaLength, + Vector< sp<CameraArea> > &areas); + +private: + + static const ssize_t TOP = -1000; + static const ssize_t LEFT = -1000; + static const ssize_t BOTTOM = 1000; + static const ssize_t RIGHT = 1000; + + ssize_t mTop; + ssize_t mLeft; + ssize_t mBottom; + ssize_t mRight; + size_t mWeight; +}; + +class CameraFDResult : public RefBase +{ +public: + + CameraFDResult() : mFaceData(NULL) {}; + CameraFDResult(camera_frame_metadata_t *faces) : mFaceData(faces) {}; + + virtual ~CameraFDResult() { + if ( ( NULL != mFaceData ) && ( NULL != mFaceData->faces ) ) { + free(mFaceData->faces); + free(mFaceData); + } + } + + camera_frame_metadata_t *getFaceResult() { return mFaceData; }; + + static const ssize_t TOP = -1000; + static const ssize_t LEFT = -1000; + static const ssize_t BOTTOM = 1000; + static const ssize_t RIGHT = 1000; + static const ssize_t INVALID_DATA = -2000; + +private: + + camera_frame_metadata_t *mFaceData; +}; + +class CameraFrame +{ + public: + + enum FrameType + { + PREVIEW_FRAME_SYNC = 0x1, ///SYNC implies that the frame needs to be explicitly returned after consuming in order to be filled by camera again + PREVIEW_FRAME = 0x2 , ///Preview frame includes viewfinder and snapshot frames + IMAGE_FRAME_SYNC = 0x4, ///Image Frame is the image capture output frame + IMAGE_FRAME = 0x8, + VIDEO_FRAME_SYNC = 0x10, ///Timestamp will be updated for these frames + VIDEO_FRAME = 0x20, + FRAME_DATA_SYNC = 0x40, ///Any extra data assosicated with the frame. Always synced with the frame + FRAME_DATA= 0x80, + RAW_FRAME = 0x100, + SNAPSHOT_FRAME = 0x200, + ALL_FRAMES = 0xFFFF ///Maximum of 16 frame types supported + }; + + //default contrustor + CameraFrame(): + mCookie(NULL), + mBuffer(NULL), + mFrameType(0), + mTimestamp(0), + mWidth(0), + mHeight(0), + mOffset(0), + mAlignment(0), + mFd(0), + mLength(0) {} + + //copy constructor + CameraFrame(const CameraFrame &frame) : + mCookie(frame.mCookie), + mBuffer(frame.mBuffer), + mFrameType(frame.mFrameType), + mTimestamp(frame.mTimestamp), + mWidth(frame.mWidth), + mHeight(frame.mHeight), + mOffset(frame.mOffset), + mAlignment(frame.mAlignment), + mFd(frame.mFd), + mLength(frame.mLength) {} + + void *mCookie; + void *mBuffer; + int mFrameType; + nsecs_t mTimestamp; + unsigned int mWidth, mHeight; + uint32_t mOffset; + unsigned int mAlignment; + int mFd; + size_t mLength; + ///@todo add other member vars like stride etc +}; + +///Common Camera Hal Event class which is visible to CameraAdapter,DisplayAdapter and AppCallbackNotifier +///@todo Rename this class to CameraEvent +class CameraHalEvent +{ +public: + //Enums + enum CameraHalEventType { + NO_EVENTS = 0x0, + EVENT_FOCUS_LOCKED = 0x1, + EVENT_FOCUS_ERROR = 0x2, + EVENT_ZOOM_INDEX_REACHED = 0x4, + EVENT_SHUTTER = 0x8, + EVENT_FACE = 0x10, + ///@remarks Future enum related to display, like frame displayed event, could be added here + ALL_EVENTS = 0xFFFF ///Maximum of 16 event types supported + }; + + ///Class declarations + ///@remarks Add a new class for a new event type added above + + //Shutter event specific data + typedef struct ShutterEventData_t { + bool shutterClosed; + }ShutterEventData; + + ///Focus event specific data + typedef struct FocusEventData_t { + bool focusLocked; + bool focusError; + int currentFocusValue; + } FocusEventData; + + ///Zoom specific event data + typedef struct ZoomEventData_t { + int currentZoomIndex; + bool targetZoomIndexReached; + } ZoomEventData; + + typedef struct FaceData_t { + ssize_t top; + ssize_t left; + ssize_t bottom; + ssize_t right; + size_t score; + } FaceData; + + typedef sp<CameraFDResult> FaceEventData; + + class CameraHalEventData : public RefBase{ + + public: + + CameraHalEvent::FocusEventData focusEvent; + CameraHalEvent::ZoomEventData zoomEvent; + CameraHalEvent::ShutterEventData shutterEvent; + CameraHalEvent::FaceEventData faceEvent; + }; + + //default contrustor + CameraHalEvent(): + mCookie(NULL), + mEventType(NO_EVENTS) {} + + //copy constructor + CameraHalEvent(const CameraHalEvent &event) : + mCookie(event.mCookie), + mEventType(event.mEventType), + mEventData(event.mEventData) {}; + + void* mCookie; + CameraHalEventType mEventType; + sp<CameraHalEventData> mEventData; + +}; + +/// Have a generic callback class based on template - to adapt CameraFrame and Event +typedef void (*frame_callback) (CameraFrame *cameraFrame); +typedef void (*event_callback) (CameraHalEvent *event); + +//signals CameraHAL to relase image buffers +typedef void (*release_image_buffers_callback) (void *userData); +typedef void (*end_image_capture_callback) (void *userData); + +/** + * Interface class implemented by classes that have some events to communicate to dependendent classes + * Dependent classes use this interface for registering for events + */ +class MessageNotifier +{ +public: + static const uint32_t EVENT_BIT_FIELD_POSITION; + static const uint32_t FRAME_BIT_FIELD_POSITION; + + ///@remarks Msg type comes from CameraFrame and CameraHalEvent classes + /// MSB 16 bits is for events and LSB 16 bits is for frame notifications + /// FrameProvider and EventProvider classes act as helpers to event/frame + /// consumers to call this api + virtual void enableMsgType(int32_t msgs, frame_callback frameCb=NULL, event_callback eventCb=NULL, void* cookie=NULL) = 0; + virtual void disableMsgType(int32_t msgs, void* cookie) = 0; + + virtual ~MessageNotifier() {}; +}; + +class ErrorNotifier : public virtual RefBase +{ +public: + virtual void errorNotify(int error) = 0; + + virtual ~ErrorNotifier() {}; +}; + + +/** + * Interace class abstraction for Camera Adapter to act as a frame provider + * This interface is fully implemented by Camera Adapter + */ +class FrameNotifier : public MessageNotifier +{ +public: + virtual void returnFrame(void* frameBuf, CameraFrame::FrameType frameType) = 0; + + virtual ~FrameNotifier() {}; +}; + +/** * Wrapper class around Frame Notifier, which is used by display and notification classes for interacting with Camera Adapter + */ +class FrameProvider +{ + FrameNotifier* mFrameNotifier; + void* mCookie; + frame_callback mFrameCallback; + +public: + FrameProvider(FrameNotifier *fn, void* cookie, frame_callback frameCallback) + :mFrameNotifier(fn), mCookie(cookie),mFrameCallback(frameCallback) { } + + int enableFrameNotification(int32_t frameTypes); + int disableFrameNotification(int32_t frameTypes); + int returnFrame(void *frameBuf, CameraFrame::FrameType frameType); +}; + +/** Wrapper class around MessageNotifier, which is used by display and notification classes for interacting with + * Camera Adapter + */ +class EventProvider +{ +public: + MessageNotifier* mEventNotifier; + void* mCookie; + event_callback mEventCallback; + +public: + EventProvider(MessageNotifier *mn, void* cookie, event_callback eventCallback) + :mEventNotifier(mn), mCookie(cookie), mEventCallback(eventCallback) {} + + int enableEventNotification(int32_t eventTypes); + int disableEventNotification(int32_t eventTypes); +}; + +/* + * Interface for providing buffers + */ +class BufferProvider +{ +public: + virtual void* allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs) = 0; + + //additional methods used for memory mapping + virtual uint32_t * getOffsets() = 0; + virtual int getFd() = 0; + + virtual int freeBuffer(void* buf) = 0; + + virtual ~BufferProvider() {} +}; + +/** + * Class for handling data and notify callbacks to application + */ +class AppCallbackNotifier: public ErrorNotifier , public virtual RefBase +{ + +public: + + ///Constants + static const int NOTIFIER_TIMEOUT; + static const int32_t MAX_BUFFERS = 8; + + enum NotifierCommands + { + NOTIFIER_CMD_PROCESS_EVENT, + NOTIFIER_CMD_PROCESS_FRAME, + NOTIFIER_CMD_PROCESS_ERROR + }; + + enum NotifierState + { + NOTIFIER_STOPPED, + NOTIFIER_STARTED, + NOTIFIER_EXITED + }; + +public: + + ~AppCallbackNotifier(); + + ///Initialzes the callback notifier, creates any resources required + status_t initialize(); + + ///Starts the callbacks to application + status_t start(); + + ///Stops the callbacks from going to application + status_t stop(); + + void setEventProvider(int32_t eventMask, MessageNotifier * eventProvider); + void setFrameProvider(FrameNotifier *frameProvider); + + //All sub-components of Camera HAL call this whenever any error happens + virtual void errorNotify(int error); + + status_t startPreviewCallbacks(CameraParameters ¶ms, void *buffers, uint32_t *offsets, int fd, size_t length, size_t count); + status_t stopPreviewCallbacks(); + + status_t enableMsgType(int32_t msgType); + status_t disableMsgType(int32_t msgType); + + //API for enabling/disabling measurement data + void setMeasurements(bool enable); + + //thread loops + void notificationThread(); + + ///Notification callback functions + static void frameCallbackRelay(CameraFrame* caFrame); + static void eventCallbackRelay(CameraHalEvent* chEvt); + void frameCallback(CameraFrame* caFrame); + void eventCallback(CameraHalEvent* chEvt); + + void setCallbacks(CameraHal *cameraHal, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user); + + //Set Burst mode + void setBurst(bool burst); + + //Notifications from CameraHal for video recording case + status_t startRecording(); + status_t stopRecording(); + status_t initSharedVideoBuffers(void *buffers, uint32_t *offsets, int fd, size_t length, size_t count); + status_t releaseRecordingFrame(const void *opaque); + + status_t useMetaDataBufferMode(bool enable); + + //Internal class definitions + class NotificationThread : public Thread { + AppCallbackNotifier* mAppCallbackNotifier; + TIUTILS::MessageQueue mNotificationThreadQ; + public: + enum NotificationThreadCommands + { + NOTIFIER_START, + NOTIFIER_STOP, + NOTIFIER_EXIT, + }; + public: + NotificationThread(AppCallbackNotifier* nh) + : Thread(false), mAppCallbackNotifier(nh) { } + virtual bool threadLoop() { + mAppCallbackNotifier->notificationThread(); + return false; + } + + TIUTILS::MessageQueue &msgQ() { return mNotificationThreadQ;} + }; + + //Friend declarations + friend class NotificationThread; + +private: + void notifyEvent(); + void notifyFrame(); + bool processMessage(); + void releaseSharedVideoBuffers(); + +private: + mutable Mutex mLock; + mutable Mutex mBurstLock; + CameraHal* mCameraHal; + camera_notify_callback mNotifyCb; + camera_data_callback mDataCb; + camera_data_timestamp_callback mDataCbTimestamp; + camera_request_memory mRequestMemory; + void *mCallbackCookie; + + //Keeps Video MemoryHeaps and Buffers within + //these objects + KeyedVector<unsigned int, unsigned int> mVideoHeaps; + KeyedVector<unsigned int, unsigned int> mVideoBuffers; + KeyedVector<unsigned int, unsigned int> mVideoMap; + + //Keeps list of Gralloc handles and associated Video Metadata Buffers + KeyedVector<uint32_t, uint32_t> mVideoMetadataBufferMemoryMap; + KeyedVector<uint32_t, uint32_t> mVideoMetadataBufferReverseMap; + + bool mBufferReleased; + + sp< NotificationThread> mNotificationThread; + EventProvider *mEventProvider; + FrameProvider *mFrameProvider; + TIUTILS::MessageQueue mEventQ; + TIUTILS::MessageQueue mFrameQ; + NotifierState mNotifierState; + + bool mPreviewing; + camera_memory_t* mPreviewMemory; + unsigned char* mPreviewBufs[MAX_BUFFERS]; + int mPreviewBufCount; + const char *mPreviewPixelFormat; + KeyedVector<unsigned int, sp<MemoryHeapBase> > mSharedPreviewHeaps; + KeyedVector<unsigned int, sp<MemoryBase> > mSharedPreviewBuffers; + + //Burst mode active + bool mBurst; + mutable Mutex mRecordingLock; + bool mRecording; + bool mMeasurementEnabled; + + bool mUseMetaDataBufferMode; + +}; + + +/** + * Class used for allocating memory for JPEG bit stream buffers, output buffers of camera in no overlay case + */ +class MemoryManager : public BufferProvider, public virtual RefBase +{ +public: + ///Initializes the display adapter creates any resources required + status_t initialize(){ return NO_ERROR; } + + int setErrorHandler(ErrorNotifier *errorNotifier); + virtual void* allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs); + virtual uint32_t * getOffsets(); + virtual int getFd() ; + virtual int freeBuffer(void* buf); + +private: + + sp<ErrorNotifier> mErrorNotifier; +}; + + + + +/** + * CameraAdapter interface class + * Concrete classes derive from this class and provide implementations based on the specific camera h/w interface + */ + +class CameraAdapter: public FrameNotifier, public virtual RefBase +{ +protected: + enum AdapterActiveStates { + INTIALIZED_ACTIVE = 1 << 0, + LOADED_PREVIEW_ACTIVE = 1 << 1, + PREVIEW_ACTIVE = 1 << 2, + LOADED_CAPTURE_ACTIVE = 1 << 3, + CAPTURE_ACTIVE = 1 << 4, + BRACKETING_ACTIVE = 1 << 5, + AF_ACTIVE = 1 << 6, + ZOOM_ACTIVE = 1 << 7, + VIDEO_ACTIVE = 1 << 8, + }; +public: + typedef struct + { + void *mBuffers; + uint32_t *mOffsets; + int mFd; + size_t mLength; + size_t mCount; + size_t mMaxQueueable; + } BuffersDescriptor; + + enum CameraCommands + { + CAMERA_START_PREVIEW = 0, + CAMERA_STOP_PREVIEW = 1, + CAMERA_START_VIDEO = 2, + CAMERA_STOP_VIDEO = 3, + CAMERA_START_IMAGE_CAPTURE = 4, + CAMERA_STOP_IMAGE_CAPTURE = 5, + CAMERA_PERFORM_AUTOFOCUS = 6, + CAMERA_CANCEL_AUTOFOCUS = 7, + CAMERA_PREVIEW_FLUSH_BUFFERS = 8, + CAMERA_START_SMOOTH_ZOOM = 9, + CAMERA_STOP_SMOOTH_ZOOM = 10, + CAMERA_USE_BUFFERS_PREVIEW = 11, + CAMERA_SET_TIMEOUT = 12, + CAMERA_CANCEL_TIMEOUT = 13, + CAMERA_START_BRACKET_CAPTURE = 14, + CAMERA_STOP_BRACKET_CAPTURE = 15, + CAMERA_QUERY_RESOLUTION_PREVIEW = 16, + CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE = 17, + CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA = 18, + CAMERA_USE_BUFFERS_IMAGE_CAPTURE = 19, + CAMERA_USE_BUFFERS_PREVIEW_DATA = 20, + CAMERA_TIMEOUT_EXPIRED = 21, + CAMERA_START_FD = 22, + CAMERA_STOP_FD = 23, + }; + + enum CameraMode + { + CAMERA_PREVIEW, + CAMERA_IMAGE_CAPTURE, + CAMERA_VIDEO, + CAMERA_MEASUREMENT + }; + + enum AdapterState { + INTIALIZED_STATE = INTIALIZED_ACTIVE, + LOADED_PREVIEW_STATE = LOADED_PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + PREVIEW_STATE = PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + LOADED_CAPTURE_STATE = LOADED_CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + CAPTURE_STATE = CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + BRACKETING_STATE = BRACKETING_ACTIVE | CAPTURE_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE , + AF_STATE = AF_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + ZOOM_STATE = ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_STATE = VIDEO_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + VIDEO_ZOOM_STATE = VIDEO_ACTIVE | ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + AF_ZOOM_STATE = AF_ACTIVE | ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + BRACKETING_ZOOM_STATE = BRACKETING_ACTIVE | ZOOM_ACTIVE | PREVIEW_ACTIVE | INTIALIZED_ACTIVE, + }; + +public: + + ///Initialzes the camera adapter creates any resources required + virtual int initialize(CameraProperties::Properties*, int sensor_index=0) = 0; + + virtual int setErrorHandler(ErrorNotifier *errorNotifier) = 0; + + //Message/Frame notification APIs + virtual void enableMsgType(int32_t msgs, + frame_callback callback = NULL, + event_callback eventCb = NULL, + void *cookie = NULL) = 0; + virtual void disableMsgType(int32_t msgs, void* cookie) = 0; + virtual void returnFrame(void* frameBuf, CameraFrame::FrameType frameType) = 0; + + //APIs to configure Camera adapter and get the current parameter set + virtual int setParameters(const CameraParameters& params) = 0; + virtual void getParameters(CameraParameters& params) = 0; + + //API to flush the buffers from Camera + status_t flushBuffers() + { + return sendCommand(CameraAdapter::CAMERA_PREVIEW_FLUSH_BUFFERS); + } + + //Registers callback for returning image buffers back to CameraHAL + virtual int registerImageReleaseCallback(release_image_buffers_callback callback, void *user_data) = 0; + + //Registers callback, which signals a completed image capture + virtual int registerEndCaptureCallback(end_image_capture_callback callback, void *user_data) = 0; + + //API to send a command to the camera + virtual status_t sendCommand(CameraCommands operation, int value1=0, int value2=0, int value3=0) = 0; + + virtual ~CameraAdapter() {}; + + //Retrieves the current Adapter state + virtual AdapterState getState() = 0; + + //Retrieves the next Adapter state + virtual AdapterState getNextState() = 0; + + // Receive orientation events from CameraHal + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt) = 0; +protected: + //The first two methods will try to switch the adapter state. + //Every call to setState() should be followed by a corresponding + //call to commitState(). If the state switch fails, then it will + //get reset to the previous state via rollbackState(). + virtual status_t setState(CameraCommands operation) = 0; + virtual status_t commitState() = 0; + virtual status_t rollbackState() = 0; + + // Retrieves the current Adapter state - for internal use (not locked) + virtual status_t getState(AdapterState &state) = 0; + // Retrieves the next Adapter state - for internal use (not locked) + virtual status_t getNextState(AdapterState &state) = 0; +}; + +class DisplayAdapter : public BufferProvider, public virtual RefBase +{ +public: + typedef struct S3DParameters_t + { + int mode; + int framePacking; + int order; + int subSampling; + } S3DParameters; + + ///Initializes the display adapter creates any resources required + virtual int initialize() = 0; + + virtual int setPreviewWindow(struct preview_stream_ops *window) = 0; + virtual int setFrameProvider(FrameNotifier *frameProvider) = 0; + virtual int setErrorHandler(ErrorNotifier *errorNotifier) = 0; + virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL, S3DParameters *s3dParams = NULL) = 0; + virtual int disableDisplay() = 0; + //Used for Snapshot review temp. pause + virtual int pauseDisplay(bool pause) = 0; + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + //Used for shot to snapshot measurement + virtual int setSnapshotTimeRef(struct timeval *refTime = NULL) = 0; +#endif + + virtual int useBuffers(void *bufArr, int num) = 0; + virtual bool supportsExternalBuffering() = 0; + + // Get max queueable buffers display supports + // This function should only be called after + // allocateBuffer + virtual int maxQueueableBuffers(unsigned int& queueable) = 0; +}; + +static void releaseImageBuffers(void *userData); + +static void endImageCapture(void *userData); + + /** + Implementation of the Android Camera hardware abstraction layer + + This class implements the interface methods defined in CameraHardwareInterface + for the OMAP4 platform + +*/ +class CameraHal + +{ + +public: + ///Constants + static const int NO_BUFFERS_PREVIEW; + static const int NO_BUFFERS_IMAGE_CAPTURE; + static const uint32_t VFR_SCALE = 1000; + + + /*--------------------Interface Methods---------------------------------*/ + + //@{ +public: + + /** Set the notification and data callbacks */ + void 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); + + /** Receives orientation events from SensorListener **/ + void onOrientationEvent(uint32_t orientation, uint32_t tilt); + + /** + * The following three functions all take a msgtype, + * which is a bitmask of the messages defined in + * include/ui/Camera.h + */ + + /** + * Enable a message, or set of messages. + */ + void enableMsgType(int32_t msgType); + + /** + * Disable a message, or a set of messages. + */ + void disableMsgType(int32_t msgType); + + /** + * 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. + */ + int msgTypeEnabled(int32_t msgType); + + /** + * Start preview mode. + */ + int startPreview(); + + /** + * Only used if overlays are used for camera preview. + */ + int setPreviewWindow(struct preview_stream_ops *window); + + /** + * Stop a previously started preview. + */ + void stopPreview(); + + /** + * Returns true if preview is enabled. + */ + bool previewEnabled(); + + /** + * 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 calling releaseRecordingFrame(). + */ + int startRecording(); + + /** + * Stop a previously started recording. + */ + void stopRecording(); + + /** + * Returns true if recording is enabled. + */ + int recordingEnabled(); + + /** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME. + */ + void releaseRecordingFrame(const void *opaque); + + /** + * Set the camera parameters specific to Video Recording. + */ + status_t setVideoModeParameters(); + + /** + * 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. + */ + int 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. + */ + int cancelAutoFocus(); + + /** + * Take a picture. + */ + int takePicture(); + + /** + * Cancel a picture that was started with takePicture. Calling this + * method when no picture is being taken is a no-op. + */ + int cancelPicture(); + + /** Set the camera parameters. */ + int setParameters(const char* params); + int setParameters(const CameraParameters& params); + + /** Return the camera parameters. */ + char* getParameters(); + void putParameters(char *); + + /** + * Send command to camera driver. + */ + int sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); + + /** + * Release the hardware resources owned by this object. Note that this is + * *not* done in the destructor. + */ + void release(); + + /** + * Dump state of the camera hardware + */ + int dump(int fd) const; + + + status_t storeMetaDataInBuffers(bool enable); + + //@} + +/*--------------------Internal Member functions - Public---------------------------------*/ + +public: + /** @name internalFunctionsPublic */ + //@{ + + /** Constructor of CameraHal */ + CameraHal(int cameraId); + + // Destructor of CameraHal + ~CameraHal(); + + /** Initialize CameraHal */ + status_t initialize(CameraProperties::Properties*); + + /** Deinitialize CameraHal */ + void deinitialize(); + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Uses the constructor timestamp as a reference to calcluate the + // elapsed time + static void PPM(const char *); + //Uses a user provided timestamp as a reference to calcluate the + // elapsed time + static void PPM(const char *, struct timeval*, ...); + +#endif + + /** Free image bufs */ + status_t freeImageBufs(); + + //Signals the end of image capture + status_t signalEndImageCapture(); + + //Events + static void eventCallbackRelay(CameraHalEvent* event); + void eventCallback(CameraHalEvent* event); + void setEventProvider(int32_t eventMask, MessageNotifier * eventProvider); + +/*--------------------Internal Member functions - Private---------------------------------*/ +private: + + /** @name internalFunctionsPrivate */ + //@{ + + status_t parseResolution(const char *resStr, int &width, int &height); + + void insertSupportedParams(); + + /** Allocate preview data buffers */ + status_t allocPreviewDataBufs(size_t size, size_t bufferCount); + + /** Free preview data buffers */ + status_t freePreviewDataBufs(); + + /** Allocate preview buffers */ + status_t allocPreviewBufs(int width, int height, const char* previewFormat, unsigned int bufferCount, unsigned int &max_queueable); + + /** Allocate video buffers */ + status_t allocVideoBufs(int width, int height, const char* previewFormat); + + /** Allocate image capture buffers */ + status_t allocImageBufs(unsigned int width, unsigned int height, size_t length, const char* previewFormat, unsigned int bufferCount); + + /** Free preview buffers */ + status_t freePreviewBufs(); + + /** Free video bufs */ + status_t freeVideoBufs(); + + //Check if a given resolution is supported by the current camera + //instance + bool isResolutionValid(unsigned int width, unsigned int height, const char *supportedResolutions); + + //Check if a given parameter is supported by the current camera + // instance + bool isParameterValid(const char *param, const char *supportedParams); + bool isParameterValid(int param, const char *supportedParams); + + /** Initialize default parameters */ + void initDefaultParameters(); + + void dumpProperties(CameraProperties::Properties& cameraProps); + + status_t startImageBracketing(); + + status_t stopImageBracketing(); + + void setShutter(bool enable); + + void forceStopPreview(); + + //@} + + +/*----------Member variables - Public ---------------------*/ +public: + int32_t mMsgEnabled; + bool mRecordEnabled; + nsecs_t mCurrentTime; + bool mFalsePreview; + bool mPreviewEnabled; + uint32_t mTakePictureQueue; + bool mBracketingEnabled; + bool mBracketingRunning; + //User shutter override + bool mShutterEnabled; + bool mMeasurementEnabled; + //Google's parameter delimiter + static const char PARAMS_DELIMITER[]; + + CameraAdapter *mCameraAdapter; + sp<AppCallbackNotifier> mAppCallbackNotifier; + sp<DisplayAdapter> mDisplayAdapter; + sp<MemoryManager> mMemoryManager; + + sp<IMemoryHeap> mPictureHeap; + + int* mGrallocHandles; + + + +///static member vars + +#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS + + //Timestamp from the CameraHal constructor + static struct timeval ppm_start; + //Timestamp of the autoFocus command + static struct timeval mStartFocus; + //Timestamp of the startPreview command + static struct timeval mStartPreview; + //Timestamp of the takePicture command + static struct timeval mStartCapture; + +#endif + +/*----------Member variables - Private ---------------------*/ +private: + //keeps paused state of display + bool mDisplayPaused; + //Index of current camera adapter + int mCameraIndex; + + mutable Mutex mLock; + + sp<SensorListener> mSensorListener; + + void* mCameraAdapterHandle; + + CameraParameters mParameters; + bool mPreviewRunning; + bool mPreviewStateOld; + bool mRecordingEnabled; + EventProvider *mEventProvider; + + int32_t *mPreviewDataBufs; + uint32_t *mPreviewDataOffsets; + int mPreviewDataFd; + int mPreviewDataLength; + int32_t *mImageBufs; + uint32_t *mImageOffsets; + int mImageFd; + int mImageLength; + int32_t *mPreviewBufs; + uint32_t *mPreviewOffsets; + int mPreviewLength; + int mPreviewFd; + int32_t *mVideoBufs; + uint32_t *mVideoOffsets; + int mVideoFd; + int mVideoLength; + + int32_t mLastPreviewFramerate; + + int mBracketRangePositive; + int mBracketRangeNegative; + + ///@todo Rename this as preview buffer provider + BufferProvider *mBufProvider; + BufferProvider *mVideoBufProvider; + + + CameraProperties::Properties* mCameraProperties; + + bool mPreviewStartInProgress; + + bool mSetPreviewWindowCalled; + + uint32_t mPreviewWidth; + uint32_t mPreviewHeight; + int32_t mMaxZoomSupported; +}; + + +}; // namespace android + +#endif diff --git a/camera/inc/CameraProperties.h b/camera/inc/CameraProperties.h new file mode 100644 index 0000000..83d1b10 --- /dev/null +++ b/camera/inc/CameraProperties.h @@ -0,0 +1,180 @@ +/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#ifndef CAMERA_PROPERTIES_H
+#define CAMERA_PROPERTIES_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+
+#define MAX_CAMERAS_SUPPORTED 2
+#define MAX_PROP_NAME_LENGTH 50
+#define MAX_PROP_VALUE_LENGTH 2048
+
+#define EXIF_MAKE_DEFAULT "default_make"
+#define EXIF_MODEL_DEFAULT "default_model"
+
+// Class that handles the Camera Properties
+class CameraProperties
+{
+public:
+ static const char INVALID[];
+ static const char CAMERA_NAME[];
+ static const char CAMERA_SENSOR_INDEX[];
+ static const char ORIENTATION_INDEX[];
+ static const char FACING_INDEX[];
+ static const char S3D_SUPPORTED[];
+ static const char SUPPORTED_PREVIEW_SIZES[];
+ static const char SUPPORTED_PREVIEW_FORMATS[];
+ static const char SUPPORTED_PREVIEW_FRAME_RATES[];
+ static const char SUPPORTED_PICTURE_SIZES[];
+ static const char SUPPORTED_PICTURE_FORMATS[];
+ static const char SUPPORTED_THUMBNAIL_SIZES[];
+ static const char SUPPORTED_WHITE_BALANCE[];
+ static const char SUPPORTED_EFFECTS[];
+ static const char SUPPORTED_ANTIBANDING[];
+ static const char SUPPORTED_EXPOSURE_MODES[];
+ static const char SUPPORTED_EV_MIN[];
+ static const char SUPPORTED_EV_MAX[];
+ static const char SUPPORTED_EV_STEP[];
+ static const char SUPPORTED_ISO_VALUES[];
+ static const char SUPPORTED_SCENE_MODES[];
+ static const char SUPPORTED_FLASH_MODES[];
+ static const char SUPPORTED_FOCUS_MODES[];
+ static const char REQUIRED_PREVIEW_BUFS[];
+ static const char REQUIRED_IMAGE_BUFS[];
+ static const char SUPPORTED_ZOOM_RATIOS[];
+ static const char SUPPORTED_ZOOM_STAGES[];
+ static const char SUPPORTED_IPP_MODES[];
+ static const char SMOOTH_ZOOM_SUPPORTED[];
+ static const char ZOOM_SUPPORTED[];
+ static const char PREVIEW_SIZE[];
+ static const char PREVIEW_FORMAT[];
+ static const char PREVIEW_FRAME_RATE[];
+ static const char ZOOM[];
+ static const char PICTURE_SIZE[];
+ static const char PICTURE_FORMAT[];
+ static const char JPEG_THUMBNAIL_SIZE[];
+ static const char WHITEBALANCE[];
+ static const char EFFECT[];
+ static const char ANTIBANDING[];
+ static const char EXPOSURE_MODE[];
+ static const char EV_COMPENSATION[];
+ static const char ISO_MODE[];
+ static const char FOCUS_MODE[];
+ static const char SCENE_MODE[];
+ static const char FLASH_MODE[];
+ static const char JPEG_QUALITY[];
+ static const char BRIGHTNESS[];
+ static const char SATURATION[];
+ static const char SHARPNESS[];
+ static const char CONTRAST[];
+ static const char IPP[];
+ static const char AUTOCONVERGENCE[];
+ static const char AUTOCONVERGENCE_MODE[];
+ static const char MANUALCONVERGENCE_VALUES[];
+ static const char SENSOR_ORIENTATION[];
+ static const char SENSOR_ORIENTATION_VALUES[];
+ static const char REVISION[];
+ static const char FOCAL_LENGTH[];
+ static const char HOR_ANGLE[];
+ static const char VER_ANGLE[];
+ static const char EXIF_MAKE[];
+ static const char EXIF_MODEL[];
+ static const char JPEG_THUMBNAIL_QUALITY[];
+ static const char MAX_FOCUS_AREAS[];
+ static const char MAX_FD_HW_FACES[];
+ static const char MAX_FD_SW_FACES[];
+
+ static const char PARAMS_DELIMITER [];
+
+ static const char S3D2D_PREVIEW[];
+ static const char S3D2D_PREVIEW_MODES[];
+ static const char VSTAB[];
+ static const char VSTAB_VALUES[];
+ static const char FRAMERATE_RANGE[];
+ static const char FRAMERATE_RANGE_SUPPORTED[];
+
+ static const char DEFAULT_VALUE[];
+
+ static const char AUTO_EXPOSURE_LOCK[];
+ static const char AUTO_EXPOSURE_LOCK_SUPPORTED[];
+ static const char AUTO_WHITEBALANCE_LOCK[];
+ static const char AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
+ static const char MAX_NUM_METERING_AREAS[];
+ static const char METERING_AREAS[];
+
+ CameraProperties();
+ ~CameraProperties();
+
+ // container class passed around for accessing properties
+ class Properties
+ {
+ public:
+ Properties()
+ {
+ mProperties = new DefaultKeyedVector<String8, String8>(String8(DEFAULT_VALUE));
+ // set properties that are same for all cameras
+ set(EXIF_MAKE, EXIF_MAKE_DEFAULT);
+ set(EXIF_MODEL, EXIF_MODEL_DEFAULT);
+ }
+ ~Properties()
+ {
+ delete mProperties;
+ }
+ ssize_t set(const char *prop, const char *value);
+ ssize_t set(const char *prop, int value);
+ const char* get(const char * prop);
+ void dump();
+
+ protected:
+ const char* keyAt(unsigned int);
+ const char* valueAt(unsigned int);
+
+ private:
+ DefaultKeyedVector<String8, String8>* mProperties;
+
+ };
+
+ ///Initializes the CameraProperties class
+ status_t initialize();
+ status_t loadProperties();
+ int camerasSupported();
+ int getProperties(int cameraIndex, Properties** properties);
+
+private:
+
+ uint32_t mCamerasSupported;
+ int mInitialized;
+
+ Properties mCameraProps[MAX_CAMERAS_SUPPORTED];
+
+};
+
+};
+
+#endif //CAMERA_PROPERTIES_H
+
diff --git a/camera/inc/General3A_Settings.h b/camera/inc/General3A_Settings.h new file mode 100644 index 0000000..af33518 --- /dev/null +++ b/camera/inc/General3A_Settings.h @@ -0,0 +1,262 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 General3A_Settings.h +* +* This file maps the Camera Hardware Interface to OMX. +* +*/ + +#include "OMX_TI_IVCommon.h" +#include "OMX_TI_Common.h" +#include "OMX_TI_Index.h" +#include "TICameraParameters.h" + +#ifndef GENERAL_3A_SETTINGS_H +#define GENERAL_3A_SETTINGS_H + +#define FOCUS_FACE_PRIORITY OMX_IMAGE_FocusControlMax -1 +#define FOCUS_REGION_PRIORITY OMX_IMAGE_FocusControlMax -2 +#define WB_FACE_PRIORITY OMX_WhiteBalControlMax -1 +#define EXPOSURE_FACE_PRIORITY OMX_ExposureControlMax - 1 + +namespace android { + +struct userToOMX_LUT{ + const char * userDefinition; + int omxDefinition; +}; + +struct LUTtype{ + int size; + const userToOMX_LUT *Table; +}; + +const userToOMX_LUT isoUserToOMX[] = { + { TICameraParameters::ISO_MODE_AUTO, 0 }, + { TICameraParameters::ISO_MODE_100, 100 }, + { TICameraParameters::ISO_MODE_200, 200 }, + { TICameraParameters::ISO_MODE_400, 400 }, + { TICameraParameters::ISO_MODE_800, 800 }, + { TICameraParameters::ISO_MODE_1000, 1000 }, + { TICameraParameters::ISO_MODE_1200, 1200 }, + { TICameraParameters::ISO_MODE_1600, 1600 }, +}; + +const userToOMX_LUT effects_UserToOMX [] = { + { CameraParameters::EFFECT_NONE, OMX_ImageFilterNone }, + { CameraParameters::EFFECT_NEGATIVE, OMX_ImageFilterNegative }, + { CameraParameters::EFFECT_SOLARIZE, OMX_ImageFilterSolarize }, + { CameraParameters::EFFECT_SEPIA, OMX_ImageFilterSepia }, + { CameraParameters::EFFECT_MONO, OMX_ImageFilterGrayScale }, + { TICameraParameters::EFFECT_NATURAL, OMX_ImageFilterNatural }, + { TICameraParameters::EFFECT_VIVID, OMX_ImageFilterVivid }, + { TICameraParameters::EFFECT_COLOR_SWAP, OMX_ImageFilterColourSwap }, + { CameraParameters::EFFECT_BLACKBOARD, OMX_TI_ImageFilterBlackBoard }, + { CameraParameters::EFFECT_WHITEBOARD, OMX_TI_ImageFilterWhiteBoard }, + { CameraParameters::EFFECT_AQUA, OMX_TI_ImageFilterAqua }, + { CameraParameters::EFFECT_POSTERIZE, OMX_TI_ImageFilterPosterize }, + { TICameraParameters::EFFECT_BLACKWHITE, OMX_TI_ImageFilterBlackWhite } +}; + +const userToOMX_LUT scene_UserToOMX [] = { + { CameraParameters::SCENE_MODE_AUTO, OMX_Manual }, + { TICameraParameters::SCENE_MODE_CLOSEUP, OMX_Closeup }, + { CameraParameters::SCENE_MODE_LANDSCAPE, OMX_Landscape }, + { TICameraParameters::SCENE_MODE_AQUA, OMX_Underwater }, + { TICameraParameters::SCENE_MODE_SPORT, OMX_Sport }, + { TICameraParameters::SCENE_MODE_MOOD, OMX_Mood }, + { CameraParameters::SCENE_MODE_NIGHT_PORTRAIT, OMX_NightPortrait }, + { TICameraParameters::SCENE_MODE_NIGHT_INDOOR, OMX_NightIndoor }, + { CameraParameters::SCENE_MODE_FIREWORKS, OMX_Fireworks }, + { TICameraParameters::SCENE_MODE_DOCUMENT, OMX_Document }, + { TICameraParameters::SCENE_MODE_BARCODE, OMX_Barcode }, + { TICameraParameters::SCENE_MODE_VIDEO_SUPER_NIGHT, OMX_SuperNight }, + { TICameraParameters::SCENE_MODE_VIDEO_CINE, OMX_Cine }, + { TICameraParameters::SCENE_MODE_VIDEO_OLD_FILM, OMX_OldFilm }, + { CameraParameters::SCENE_MODE_ACTION, OMX_TI_Action }, + { CameraParameters::SCENE_MODE_BEACH, OMX_TI_Beach }, + { CameraParameters::SCENE_MODE_CANDLELIGHT, OMX_TI_Candlelight }, + { CameraParameters::SCENE_MODE_NIGHT, OMX_TI_Night }, + { CameraParameters::SCENE_MODE_PARTY, OMX_TI_Party }, + { CameraParameters::SCENE_MODE_PORTRAIT, OMX_TI_Portrait }, + { CameraParameters::SCENE_MODE_SNOW, OMX_TI_Snow }, + { CameraParameters::SCENE_MODE_STEADYPHOTO, OMX_TI_Steadyphoto }, + { CameraParameters::SCENE_MODE_SUNSET, OMX_TI_Sunset }, + { CameraParameters::SCENE_MODE_THEATRE, OMX_TI_Theatre } +}; + +const userToOMX_LUT whiteBal_UserToOMX [] = { + { CameraParameters::WHITE_BALANCE_AUTO, OMX_WhiteBalControlAuto }, + { CameraParameters::WHITE_BALANCE_DAYLIGHT, OMX_WhiteBalControlSunLight }, + { CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT, OMX_WhiteBalControlCloudy }, + { TICameraParameters::WHITE_BALANCE_TUNGSTEN, OMX_WhiteBalControlTungsten }, + { CameraParameters::WHITE_BALANCE_FLUORESCENT, OMX_WhiteBalControlFluorescent }, + { CameraParameters::WHITE_BALANCE_INCANDESCENT, OMX_WhiteBalControlIncandescent }, + { TICameraParameters::WHITE_BALANCE_HORIZON, OMX_WhiteBalControlHorizon }, + { CameraParameters::WHITE_BALANCE_SHADE, OMX_TI_WhiteBalControlShade }, + { CameraParameters::WHITE_BALANCE_TWILIGHT, OMX_TI_WhiteBalControlTwilight }, + { CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT, OMX_TI_WhiteBalControlWarmFluorescent }, + { TICameraParameters::WHITE_BALANCE_FACE, WB_FACE_PRIORITY }, + { TICameraParameters::WHITE_BALANCE_SUNSET, OMX_TI_WhiteBalControlSunset } +}; + +const userToOMX_LUT antibanding_UserToOMX [] = { + { CameraParameters::ANTIBANDING_OFF, OMX_FlickerCancelOff }, + { CameraParameters::ANTIBANDING_AUTO, OMX_FlickerCancelAuto }, + { CameraParameters::ANTIBANDING_50HZ, OMX_FlickerCancel50 }, + { CameraParameters::ANTIBANDING_60HZ, OMX_FlickerCancel60 } +}; + +const userToOMX_LUT focus_UserToOMX [] = { + { CameraParameters::FOCUS_MODE_AUTO, OMX_IMAGE_FocusControlAutoLock }, + { CameraParameters::FOCUS_MODE_INFINITY, OMX_IMAGE_FocusControlAutoInfinity }, + { CameraParameters::FOCUS_MODE_MACRO, OMX_IMAGE_FocusControlAutoMacro }, + { TICameraParameters::FOCUS_MODE_PORTRAIT, OMX_IMAGE_FocusControlPortrait }, + { TICameraParameters::FOCUS_MODE_EXTENDED, OMX_IMAGE_FocusControlExtended }, + { CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO, OMX_IMAGE_FocusControlAuto }, + { TICameraParameters::FOCUS_MODE_FACE , FOCUS_FACE_PRIORITY }, + +}; + +const userToOMX_LUT exposure_UserToOMX [] = { + { TICameraParameters::EXPOSURE_MODE_OFF, OMX_ExposureControlOff }, + { TICameraParameters::EXPOSURE_MODE_AUTO, OMX_ExposureControlAuto }, + { TICameraParameters::EXPOSURE_MODE_NIGHT, OMX_ExposureControlNight }, + { TICameraParameters::EXPOSURE_MODE_BACKLIGHT, OMX_ExposureControlBackLight }, + { TICameraParameters::EXPOSURE_MODE_SPOTLIGHT, OMX_ExposureControlSpotLight}, + { TICameraParameters::EXPOSURE_MODE_SPORTS, OMX_ExposureControlSports }, + { TICameraParameters::EXPOSURE_MODE_SNOW, OMX_ExposureControlSnow }, + { TICameraParameters::EXPOSURE_MODE_BEACH, OMX_ExposureControlBeach }, + { TICameraParameters::EXPOSURE_MODE_APERTURE, OMX_ExposureControlLargeAperture }, + { TICameraParameters::EXPOSURE_MODE_SMALL_APERTURE, OMX_ExposureControlSmallApperture }, + { TICameraParameters::EXPOSURE_MODE_FACE, EXPOSURE_FACE_PRIORITY }, +}; + +const userToOMX_LUT flash_UserToOMX [] = { + { CameraParameters::FLASH_MODE_OFF ,OMX_IMAGE_FlashControlOff }, + { CameraParameters::FLASH_MODE_ON ,OMX_IMAGE_FlashControlOn }, + { CameraParameters::FLASH_MODE_AUTO ,OMX_IMAGE_FlashControlAuto }, + { CameraParameters::FLASH_MODE_TORCH ,OMX_IMAGE_FlashControlTorch }, + { CameraParameters::FLASH_MODE_RED_EYE ,OMX_IMAGE_FlashControlRedEyeReduction }, + { TICameraParameters::FLASH_MODE_FILL_IN ,OMX_IMAGE_FlashControlFillin } +}; + +const LUTtype ExpLUT = + { + sizeof(exposure_UserToOMX)/sizeof(exposure_UserToOMX[0]), + exposure_UserToOMX + }; + +const LUTtype WBalLUT = + { + sizeof(whiteBal_UserToOMX)/sizeof(whiteBal_UserToOMX[0]), + whiteBal_UserToOMX + }; + +const LUTtype FlickerLUT = + { + sizeof(antibanding_UserToOMX)/sizeof(antibanding_UserToOMX[0]), + antibanding_UserToOMX + }; + +const LUTtype SceneLUT = + { + sizeof(scene_UserToOMX)/sizeof(scene_UserToOMX[0]), + scene_UserToOMX + }; + +const LUTtype FlashLUT = + { + sizeof(flash_UserToOMX)/sizeof(flash_UserToOMX[0]), + flash_UserToOMX + }; + +const LUTtype EffLUT = + { + sizeof(effects_UserToOMX)/sizeof(effects_UserToOMX[0]), + effects_UserToOMX + }; + +const LUTtype FocusLUT = + { + sizeof(focus_UserToOMX)/sizeof(focus_UserToOMX[0]), + focus_UserToOMX + }; + +const LUTtype IsoLUT = + { + sizeof(isoUserToOMX)/sizeof(isoUserToOMX[0]), + isoUserToOMX + }; + +/* +* class Gen3A_settings +* stores the 3A settings +* also defines the look up tables +* for mapping settings from Hal to OMX +*/ +class Gen3A_settings{ + public: + + int Exposure; + int WhiteBallance; + int Flicker; + int SceneMode; + int Effect; + int Focus; + int EVCompensation; + int Contrast; + int Saturation; + int Sharpness; + int ISO; + int FlashMode; + + unsigned int Brightness; + OMX_BOOL ExposureLock; + OMX_BOOL WhiteBalanceLock; +}; + +/* +* Flags raised when a setting is changed +*/ +enum E3ASettingsFlags +{ + SetSceneMode = 1 << 0, + SetEVCompensation = 1 << 1, + SetWhiteBallance = 1 << 2, + SetFlicker = 1 << 3, + SetExposure = 1 << 4, + SetSharpness = 1 << 5, + SetBrightness = 1 << 6, + SetContrast = 1 << 7, + SetISO = 1 << 8, + SetSaturation = 1 << 9, + SetEffect = 1 << 10, + SetFocus = 1 << 11, + SetExpMode = 1 << 14, + SetFlash = 1 << 15, + SetExpLock = 1 << 16, + SetWBLock = 1 << 17, + + E3aSettingMax, + E3AsettingsAll = ( ((E3aSettingMax -1 ) << 1) -1 ) /// all possible flags raised +}; + +}; + +#endif //GENERAL_3A_SETTINGS_H diff --git a/camera/inc/OMXCameraAdapter/OMXCameraAdapter.h b/camera/inc/OMXCameraAdapter/OMXCameraAdapter.h new file mode 100644 index 0000000..2a41ba0 --- /dev/null +++ b/camera/inc/OMXCameraAdapter/OMXCameraAdapter.h @@ -0,0 +1,834 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef OMX_CAMERA_ADAPTER_H +#define OMX_CAMERA_ADAPTER_H + +#include "CameraHal.h" +#include "OMX_Types.h" +#include "OMX_Core.h" +#include "OMX_CoreExt.h" +#include "OMX_IVCommon.h" +#include "OMX_Component.h" +#include "OMX_Index.h" +#include "OMX_IndexExt.h" +#include "OMX_TI_Index.h" +#include "OMX_TI_IVCommon.h" +#include "OMX_TI_Common.h" +#include "OMX_TI_Image.h" +#include "General3A_Settings.h" + +#include "BaseCameraAdapter.h" +#include "DebugUtils.h" + + +extern "C" +{ +#include "timm_osal_error.h" +#include "timm_osal_events.h" +#include "timm_osal_trace.h" +#include "timm_osal_semaphores.h" +} + +namespace android { + +#define Q16_OFFSET 16 + +#define OMX_CMD_TIMEOUT 3000000 //3 sec. +#define AF_CALLBACK_TIMEOUT 10000000 //10 seconds timeout +#define OMX_CAPTURE_TIMEOUT 5000000 //5 sec. + +#define FOCUS_THRESHOLD 5 //[s.] + +#define MIN_JPEG_QUALITY 1 +#define MAX_JPEG_QUALITY 100 +#define EXP_BRACKET_RANGE 10 + +#define FOCUS_DIST_SIZE 100 +#define FOCUS_DIST_BUFFER_SIZE 500 + +#define TOUCH_DATA_SIZE 200 +#define DEFAULT_THUMB_WIDTH 160 +#define DEFAULT_THUMB_HEIGHT 120 +#define FRAME_RATE_FULL_HD 27 +#define ZOOM_STAGES 61 + +#define FACE_DETECTION_BUFFER_SIZE 0x1000 + +#define EXIF_MODEL_SIZE 100 +#define EXIF_MAKE_SIZE 100 +#define EXIF_DATE_TIME_SIZE 20 + +#define GPS_TIMESTAMP_SIZE 6 +#define GPS_DATESTAMP_SIZE 11 +#define GPS_REF_SIZE 2 +#define GPS_MAPDATUM_SIZE 100 +#define GPS_PROCESSING_SIZE 100 +#define GPS_VERSION_SIZE 4 +#define GPS_NORTH_REF "N" +#define GPS_SOUTH_REF "S" +#define GPS_EAST_REF "E" +#define GPS_WEST_REF "W" + +/* Default portstartnumber of Camera component */ +#define OMX_CAMERA_DEFAULT_START_PORT_NUM 0 + +/* Define number of ports for differt domains */ +#define OMX_CAMERA_PORT_OTHER_NUM 1 +#define OMX_CAMERA_PORT_VIDEO_NUM 4 +#define OMX_CAMERA_PORT_IMAGE_NUM 1 +#define OMX_CAMERA_PORT_AUDIO_NUM 0 +#define OMX_CAMERA_NUM_PORTS (OMX_CAMERA_PORT_OTHER_NUM + OMX_CAMERA_PORT_VIDEO_NUM + OMX_CAMERA_PORT_IMAGE_NUM + OMX_CAMERA_PORT_AUDIO_NUM) + +/* Define start port number for differt domains */ +#define OMX_CAMERA_PORT_OTHER_START OMX_CAMERA_DEFAULT_START_PORT_NUM +#define OMX_CAMERA_PORT_VIDEO_START (OMX_CAMERA_PORT_OTHER_START + OMX_CAMERA_PORT_OTHER_NUM) +#define OMX_CAMERA_PORT_IMAGE_START (OMX_CAMERA_PORT_VIDEO_START + OMX_CAMERA_PORT_VIDEO_NUM) +#define OMX_CAMERA_PORT_AUDIO_START (OMX_CAMERA_PORT_IMAGE_START + OMX_CAMERA_PORT_IMAGE_NUM) + +/* Port index for camera component */ +#define OMX_CAMERA_PORT_OTHER_IN (OMX_CAMERA_PORT_OTHER_START + 0) +#define OMX_CAMERA_PORT_VIDEO_IN_VIDEO (OMX_CAMERA_PORT_VIDEO_START + 0) +#define OMX_CAMERA_PORT_VIDEO_OUT_PREVIEW (OMX_CAMERA_PORT_VIDEO_START + 1) +#define OMX_CAMERA_PORT_VIDEO_OUT_VIDEO (OMX_CAMERA_PORT_VIDEO_START + 2) +#define OMX_CAMERA_PORT_VIDEO_OUT_MEASUREMENT (OMX_CAMERA_PORT_VIDEO_START + 3) +#define OMX_CAMERA_PORT_IMAGE_OUT_IMAGE (OMX_CAMERA_PORT_IMAGE_START + 0) + + +#define OMX_INIT_STRUCT(_s_, _name_) \ + memset(&(_s_), 0x0, sizeof(_name_)); \ + (_s_).nSize = sizeof(_name_); \ + (_s_).nVersion.s.nVersionMajor = 0x1; \ + (_s_).nVersion.s.nVersionMinor = 0x1; \ + (_s_).nVersion.s.nRevision = 0x0; \ + (_s_).nVersion.s.nStep = 0x0 + +#define OMX_INIT_STRUCT_PTR(_s_, _name_) \ + memset((_s_), 0x0, sizeof(_name_)); \ + (_s_)->nSize = sizeof(_name_); \ + (_s_)->nVersion.s.nVersionMajor = 0x1; \ + (_s_)->nVersion.s.nVersionMinor = 0x1; \ + (_s_)->nVersion.s.nRevision = 0x0; \ + (_s_)->nVersion.s.nStep = 0x0 + +#define GOTO_EXIT_IF(_CONDITION,_ERROR) { \ + if ((_CONDITION)) { \ + eError = (_ERROR); \ + goto EXIT; \ + } \ +} + +///OMX Specific Functions +static OMX_ERRORTYPE OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + +static OMX_ERRORTYPE OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + +static OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_PTR pAppData, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader); + +struct CapResolution { + size_t width, height; + const char *param; +}; + +struct CapPixelformat { + OMX_COLOR_FORMATTYPE pixelformat; + const char *param; +}; + +struct CapU32 { + OMX_U32 num; + const char *param; +}; + +struct CapS32 { + OMX_S32 num; + const char *param; +}; + +typedef CapU32 CapFramerate; +typedef CapU32 CapISO; +typedef CapU32 CapSensorName; +typedef CapS32 CapZoom; +typedef CapS32 CapEVComp; + +/** + * Class which completely abstracts the camera hardware interaction from camera hal + * TODO: Need to list down here, all the message types that will be supported by this class + Need to implement BufferProvider interface to use AllocateBuffer of OMX if needed + */ +class OMXCameraAdapter : public BaseCameraAdapter +{ +public: + + /*--------------------Constant declarations----------------------------------------*/ + static const int32_t MAX_NO_BUFFERS = 20; + + ///@remarks OMX Camera has six ports - buffer input, time input, preview, image, video, and meta data + static const int MAX_NO_PORTS = 6; + + ///Five second timeout + static const int CAMERA_ADAPTER_TIMEOUT = 5000*1000; + + //EXIF ASCII prefix + static const char EXIFASCIIPrefix[]; + + enum OMXCameraEvents + { + CAMERA_PORT_ENABLE = 0x1, + CAMERA_PORT_FLUSH = 0x2, + CAMERA_PORT_DISABLE = 0x4, + }; + + enum CaptureMode + { + HIGH_SPEED = 1, + HIGH_QUALITY = 2, + VIDEO_MODE = 3, + HIGH_QUALITY_ZSL = 4, + }; + + enum IPPMode + { + IPP_NONE = 0, + IPP_NSF, + IPP_LDC, + IPP_LDCNSF, + }; + + enum CodingMode + { + CodingNone = 0, + CodingJPS, + CodingMPO, + CodingRAWJPEG, + CodingRAWMPO, + }; + + enum Algorithm3A + { + WHITE_BALANCE_ALGO = 0x1, + EXPOSURE_ALGO = 0x2, + FOCUS_ALGO = 0x4, + }; + + enum AlgoPriority + { + FACE_PRIORITY = 0, + REGION_PRIORITY, + }; + + enum BrightnessMode + { + BRIGHTNESS_OFF = 0, + BRIGHTNESS_ON, + BRIGHTNESS_AUTO, + }; + + class GPSData + { + public: + int mLongDeg, mLongMin, mLongSec; + char mLongRef[GPS_REF_SIZE]; + bool mLongValid; + int mLatDeg, mLatMin, mLatSec; + char mLatRef[GPS_REF_SIZE]; + bool mLatValid; + int mAltitude; + unsigned char mAltitudeRef; + bool mAltitudeValid; + char mMapDatum[GPS_MAPDATUM_SIZE]; + bool mMapDatumValid; + char mVersionId[GPS_VERSION_SIZE]; + bool mVersionIdValid; + char mProcMethod[GPS_PROCESSING_SIZE]; + bool mProcMethodValid; + char mDatestamp[GPS_DATESTAMP_SIZE]; + bool mDatestampValid; + uint32_t mTimeStampHour; + uint32_t mTimeStampMin; + uint32_t mTimeStampSec; + bool mTimeStampValid; + }; + + class EXIFData + { + public: + GPSData mGPSData; + bool mMakeValid; + bool mModelValid; + }; + + ///Parameters specific to any port of the OMX Camera component + class OMXCameraPortParameters + { + public: + OMX_U32 mHostBufaddr[MAX_NO_BUFFERS]; + OMX_BUFFERHEADERTYPE *mBufferHeader[MAX_NO_BUFFERS]; + OMX_U32 mWidth; + OMX_U32 mHeight; + OMX_U32 mStride; + OMX_U8 mNumBufs; + + // defines maximum number of buffers our of mNumBufs + // queueable at given moment + OMX_U8 mMaxQueueable; + + OMX_U32 mBufSize; + OMX_COLOR_FORMATTYPE mColorFormat; + OMX_PARAM_VIDEONOISEFILTERTYPE mVNFMode; + OMX_PARAM_VIDEOYUVRANGETYPE mYUVRange; + OMX_CONFIG_BOOLEANTYPE mVidStabParam; + OMX_CONFIG_FRAMESTABTYPE mVidStabConfig; + OMX_U32 mCapFrame; + OMX_U32 mFrameRate; + OMX_S32 mMinFrameRate; + OMX_S32 mMaxFrameRate; + CameraFrame::FrameType mImageType; + }; + + ///Context of the OMX Camera component + class OMXCameraAdapterComponentContext + { + public: + OMX_HANDLETYPE mHandleComp; + OMX_U32 mNumPorts; + OMX_STATETYPE mState ; + OMX_U32 mVideoPortIndex; + OMX_U32 mPrevPortIndex; + OMX_U32 mImagePortIndex; + OMX_U32 mMeasurementPortIndex; + OMXCameraPortParameters mCameraPortParams[MAX_NO_PORTS]; + }; + +public: + + OMXCameraAdapter(); + ~OMXCameraAdapter(); + + ///Initialzes the camera adapter creates any resources required + virtual status_t initialize(CameraProperties::Properties*, int sensor_index=0); + + //APIs to configure Camera adapter and get the current parameter set + virtual status_t setParameters(const CameraParameters& params); + virtual void getParameters(CameraParameters& params); + + // API + virtual status_t UseBuffersPreview(void* bufArr, int num); + + //API to flush the buffers for preview + status_t flushBuffers(); + + // API + virtual status_t setFormat(OMX_U32 port, OMXCameraPortParameters &cap); + + // Function to get and populate caps from handle + static status_t getCaps(CameraProperties::Properties* props, OMX_HANDLETYPE handle); + static const char* getLUTvalue_OMXtoHAL(int OMXValue, LUTtype LUT); + static int getLUTvalue_HALtoOMX(const char * HalValue, LUTtype LUT); + + OMX_ERRORTYPE OMXCameraAdapterEventHandler(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + + OMX_ERRORTYPE OMXCameraAdapterEmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); + + OMX_ERRORTYPE OMXCameraAdapterFillBufferDone(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_BUFFERHEADERTYPE* pBuffHeader); +protected: + + //Parent class method implementation + virtual status_t takePicture(); + virtual status_t stopImageCapture(); + virtual status_t startBracketing(int range); + virtual status_t stopBracketing(); + virtual status_t autoFocus(); + virtual status_t cancelAutoFocus(); + virtual status_t startSmoothZoom(int targetIdx); + virtual status_t stopSmoothZoom(); + virtual status_t startVideoCapture(); + virtual status_t stopVideoCapture(); + virtual status_t startPreview(); + virtual status_t stopPreview(); + virtual status_t useBuffers(CameraMode mode, void* bufArr, int num, size_t length, unsigned int queueable); + virtual status_t fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType); + virtual status_t getFrameSize(size_t &width, size_t &height); + virtual status_t getPictureBufferSize(size_t &length, size_t bufferCount); + virtual status_t getFrameDataSize(size_t &dataFrameSize, size_t bufferCount); + virtual status_t startFaceDetection(); + virtual status_t stopFaceDetection(); + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt); + +private: + + status_t switchToLoaded(); + + OMXCameraPortParameters *getPortParams(CameraFrame::FrameType frameType); + + OMX_ERRORTYPE SignalEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN OMX_PTR pEventData); + + status_t RegisterForEvent(OMX_IN OMX_HANDLETYPE hComponent, + OMX_IN OMX_EVENTTYPE eEvent, + OMX_IN OMX_U32 nData1, + OMX_IN OMX_U32 nData2, + OMX_IN Semaphore &semaphore); + + status_t setPictureRotation(unsigned int degree); + status_t setSensorOrientation(unsigned int degree); + status_t setImageQuality(unsigned int quality); + status_t setThumbnailParams(unsigned int width, unsigned int height, unsigned int quality); + + //EXIF + status_t setParametersEXIF(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t convertGPSCoord(double coord, int *deg, int *min, int *sec); + status_t setupEXIF(); + + //Focus functionality + status_t doAutoFocus(); + status_t stopAutoFocus(); + status_t checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus); + status_t returnFocusStatus(bool timeoutReached); + + //Focus distances + status_t setParametersFocus(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t addFocusDistances(OMX_U32 &near, + OMX_U32 &optimal, + OMX_U32 &far, + CameraParameters& params); + status_t encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length); + status_t getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far); + + //VSTAB and VNF Functionality + status_t enableVideoNoiseFilter(bool enable); + status_t enableVideoStabilization(bool enable); + + //Digital zoom + status_t setParametersZoom(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t doZoom(int index); + status_t advanceZoom(); + + //3A related parameters + status_t setParameters3A(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t setScene(Gen3A_settings& Gen3A); + + //Flash modes + status_t setFlashMode(Gen3A_settings& Gen3A); + status_t setFocusMode(Gen3A_settings& Gen3A); + + //Exposure Modes + status_t setExposureMode(Gen3A_settings& Gen3A); + status_t setEVCompensation(Gen3A_settings& Gen3A); + status_t setWBMode(Gen3A_settings& Gen3A); + status_t setFlicker(Gen3A_settings& Gen3A); + status_t setBrightness(Gen3A_settings& Gen3A); + status_t setContrast(Gen3A_settings& Gen3A); + status_t setSharpness(Gen3A_settings& Gen3A); + status_t setSaturation(Gen3A_settings& Gen3A); + status_t setISO(Gen3A_settings& Gen3A); + status_t setEffect(Gen3A_settings& Gen3A); + + status_t setExposureLock(Gen3A_settings& Gen3A); + status_t setWhiteBalanceLock(Gen3A_settings& Gen3A); + status_t release3ALock(); + + //API to set FrameRate using VFR interface + status_t setVFramerate(OMX_U32 minFrameRate,OMX_U32 maxFrameRate); + + status_t setParametersAlgo(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + + //Noise filtering + status_t setNSF(OMXCameraAdapter::IPPMode mode); + + //LDC + status_t setLDC(OMXCameraAdapter::IPPMode mode); + + //GLBCE + status_t setGLBCE(OMXCameraAdapter::BrightnessMode mode); + + //GBCE + status_t setGBCE(OMXCameraAdapter::BrightnessMode mode); + + status_t printComponentVersion(OMX_HANDLETYPE handle); + + //Touch AF + status_t setTouchFocus(size_t posX, + size_t posY, + size_t posWidth, + size_t posHeight, + size_t previewWidth, + size_t previewHeight); + + //Face detection + status_t setParametersFD(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + status_t updateFocusDistances(CameraParameters ¶ms); + status_t setFaceDetection(bool enable, OMX_U32 orientation); + status_t detectFaces(OMX_BUFFERHEADERTYPE* pBuffHeader, + sp<CameraFDResult> &result, + size_t previewWidth, + size_t previewHeight); + status_t encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData, + camera_frame_metadata_t **pFaces, + size_t previewWidth, + size_t previewHeight); + + //3A Algorithms priority configuration + status_t setAlgoPriority(AlgoPriority priority, Algorithm3A algo, bool enable); + + //Sensor overclocking + status_t setSensorOverclock(bool enable); + + // Utility methods for OMX Capabilities + static status_t insertCapabilities(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t encodeSizeCap(OMX_TI_CAPRESTYPE&, const CapResolution *, size_t, char *, size_t); + static status_t encodeISOCap(OMX_U32, const CapISO*, size_t, char*, size_t); + static size_t encodeZoomCap(OMX_S32, const CapZoom*, size_t, char*, size_t); + static status_t encodeFramerateCap(OMX_U32, OMX_U32, const CapFramerate*, size_t, char*, size_t); + static status_t encodeVFramerateCap(OMX_TI_CAPTYPE&, char*, char*, size_t); + static status_t encodePixelformatCap(OMX_COLOR_FORMATTYPE, + const CapPixelformat*, + size_t, + char*, + size_t); + static status_t insertImageSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertPreviewSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertThumbSizes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertZoomStages(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertImageFormats(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertPreviewFormats(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFramerates(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertVFramerates(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertEVs(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertISOModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertIPPModes(CameraProperties::Properties*, OMX_TI_CAPTYPE &); + static status_t insertWBModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertEffects(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertExpModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertSceneModes(CameraProperties::Properties*, OMX_TI_CAPTYPE &); + static status_t insertFocusModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFlickerModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertFlashModes(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertSenMount(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertDefaults(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + static status_t insertLocks(CameraProperties::Properties*, OMX_TI_CAPTYPE&); + + status_t setParametersCapture(const CameraParameters ¶ms, + BaseCameraAdapter::AdapterState state); + + //Exposure Bracketing + status_t setExposureBracketing(int *evValues, size_t evCount, size_t frameCount); + status_t parseExpRange(const char *rangeStr, int * expRange, size_t count, size_t &validEntries); + + //Temporal Bracketing + status_t doBracketing(OMX_BUFFERHEADERTYPE *pBuffHeader, CameraFrame::FrameType typeOfFrame); + status_t sendBracketFrames(); + + // Image Capture Service + status_t startImageCapture(); + + //Shutter callback notifications + status_t setShutterCallback(bool enabled); + + //Sets eithter HQ or HS mode and the frame count + status_t setCaptureMode(OMXCameraAdapter::CaptureMode mode); + status_t UseBuffersCapture(void* bufArr, int num); + status_t UseBuffersPreviewData(void* bufArr, int num); + + //Used for calculation of the average frame rate during preview + status_t recalculateFPS(); + + //Helper method for initializing a CameFrame object + status_t initCameraFrame(CameraFrame &frame, OMX_IN OMX_BUFFERHEADERTYPE *pBuffHeader, int typeOfFrame, OMXCameraPortParameters *port); + + //Sends the incoming OMX buffer header to subscribers + status_t sendFrame(CameraFrame &frame); + + status_t apply3Asettings( Gen3A_settings& Gen3A ); + + // AutoConvergence + status_t setAutoConvergence(OMX_TI_AUTOCONVERGENCEMODETYPE pACMode, OMX_S32 pManualConverence); + status_t getAutoConvergence(OMX_TI_AUTOCONVERGENCEMODETYPE *pACMode, OMX_S32 *pManualConverence); + + class CommandHandler : public Thread { + public: + CommandHandler(OMXCameraAdapter* ca) + : Thread(false), mCameraAdapter(ca) { } + + virtual bool threadLoop() { + bool ret; + ret = Handler(); + return ret; + } + + status_t put(TIUTILS::Message* msg){ + return mCommandMsgQ.put(msg); + } + + enum { + COMMAND_EXIT = -1, + CAMERA_START_IMAGE_CAPTURE = 0, + CAMERA_PERFORM_AUTOFOCUS + }; + + private: + bool Handler(); + TIUTILS::MessageQueue mCommandMsgQ; + OMXCameraAdapter* mCameraAdapter; + }; + sp<CommandHandler> mCommandHandler; + +public: + + class OMXCallbackHandler : public Thread { + public: + OMXCallbackHandler(OMXCameraAdapter* ca) + : Thread(false), mCameraAdapter(ca) { } + + virtual bool threadLoop() { + bool ret; + ret = Handler(); + return ret; + } + + status_t put(TIUTILS::Message* msg){ + return mCommandMsgQ.put(msg); + } + + enum { + COMMAND_EXIT = -1, + CAMERA_FILL_BUFFER_DONE, + }; + + private: + bool Handler(); + TIUTILS::MessageQueue mCommandMsgQ; + OMXCameraAdapter* mCameraAdapter; + }; + + sp<OMXCallbackHandler> mOMXCallbackHandler; + +private: + + //AF callback + status_t setFocusCallback(bool enabled); + + //OMX Capabilities data + static const CapResolution mImageCapRes []; + static const CapResolution mPreviewRes []; + static const CapResolution mThumbRes []; + static const CapPixelformat mPixelformats []; + static const CapFramerate mFramerates []; + static const CapU32 mSensorNames[] ; + static const CapZoom mZoomStages []; + static const CapEVComp mEVCompRanges []; + static const CapISO mISOStages []; + + // OMX Camera defaults + static const char DEFAULT_ANTIBANDING[]; + static const char DEFAULT_BRIGHTNESS[]; + static const char DEFAULT_CONTRAST[]; + static const char DEFAULT_EFFECT[]; + static const char DEFAULT_EV_COMPENSATION[]; + static const char DEFAULT_EV_STEP[]; + static const char DEFAULT_EXPOSURE_MODE[]; + static const char DEFAULT_FLASH_MODE[]; + static const char DEFAULT_FOCUS_MODE[]; + static const char DEFAULT_FRAMERATE_RANGE[]; + static const char DEFAULT_IPP[]; + static const char DEFAULT_ISO_MODE[]; + static const char DEFAULT_JPEG_QUALITY[]; + static const char DEFAULT_THUMBNAIL_QUALITY[]; + static const char DEFAULT_THUMBNAIL_SIZE[]; + static const char DEFAULT_PICTURE_FORMAT[]; + static const char DEFAULT_PICTURE_SIZE[]; + static const char DEFAULT_PREVIEW_FORMAT[]; + static const char DEFAULT_FRAMERATE[]; + static const char DEFAULT_PREVIEW_SIZE[]; + static const char DEFAULT_NUM_PREV_BUFS[]; + static const char DEFAULT_NUM_PIC_BUFS[]; + static const char DEFAULT_MAX_FOCUS_AREAS[]; + static const char DEFAULT_SATURATION[]; + static const char DEFAULT_SCENE_MODE[]; + static const char DEFAULT_SHARPNESS[]; + static const char DEFAULT_VSTAB[]; + static const char DEFAULT_WB[]; + static const char DEFAULT_ZOOM[]; + static const char DEFAULT_MAX_FD_HW_FACES[]; + static const char DEFAULT_MAX_FD_SW_FACES[]; + static const char DEFAULT_AE_LOCK[]; + static const char DEFAULT_AWB_LOCK[]; + static const char DEFAULT_MAX_NUM_METERING_AREAS[]; + static const char DEFAULT_LOCK_SUPPORTED[]; + static const char DEFAULT_LOCK_UNSUPPORTED[]; + + OMX_VERSIONTYPE mCompRevision; + + //OMX Component UUID + OMX_UUIDTYPE mCompUUID; + + //Current Focus distances + char mFocusDistNear[FOCUS_DIST_SIZE]; + char mFocusDistOptimal[FOCUS_DIST_SIZE]; + char mFocusDistFar[FOCUS_DIST_SIZE]; + char mFocusDistBuffer[FOCUS_DIST_BUFFER_SIZE]; + + // Current Focus areas + Vector< sp<CameraArea> > mFocusAreas; + + CaptureMode mCapMode; + size_t mBurstFrames; + size_t mCapturedFrames; + + bool mMeasurementEnabled; + + //Exposure Bracketing + int mExposureBracketingValues[EXP_BRACKET_RANGE]; + size_t mExposureBracketingValidEntries; + + mutable Mutex mFaceDetectionLock; + //Face detection status + bool mFaceDetectionRunning; + + //Geo-tagging + EXIFData mEXIFData; + + //Image post-processing + IPPMode mIPP; + + //jpeg Picture Quality + unsigned int mPictureQuality; + + //thumbnail resolution + unsigned int mThumbWidth, mThumbHeight; + + //thumbnail quality + unsigned int mThumbQuality; + + //variables holding the estimated framerate + float mFPS, mLastFPS; + + //automatically disable AF after a given amount of frames + unsigned int mFocusThreshold; + + //This is needed for the CTS tests. They falsely assume, that during + //smooth zoom the current zoom stage will not change within the + //zoom callback scope, which in a real world situation is not always the + //case. This variable will "simulate" the expected behavior + unsigned int mZoomParameterIdx; + + //current zoom + Mutex mZoomLock; + unsigned int mCurrentZoomIdx, mTargetZoomIdx; + int mZoomInc; + bool mReturnZoomStatus; + static const int32_t ZOOM_STEPS []; + + //local copy + OMX_VERSIONTYPE mLocalVersionParam; + + unsigned int mPending3Asettings; + Gen3A_settings mParameters3A; + + CameraParameters mParams; + CameraProperties::Properties* mCapabilities; + unsigned int mPictureRotation; + bool mWaitingForSnapshot; + int mSnapshotCount; + bool mCaptureConfigured; + + //Temporal bracketing management data + mutable Mutex mBracketingLock; + bool *mBracketingBuffersQueued; + int mBracketingBuffersQueuedCount; + int mLastBracetingBufferIdx; + bool mBracketingEnabled; + int mBracketingRange; + + CameraParameters mParameters; + OMXCameraAdapterComponentContext mCameraAdapterParameters; + bool mFirstTimeInit; + + ///Semaphores used internally + Semaphore mDoAFSem; + Semaphore mInitSem; + Semaphore mFlushSem; + Semaphore mUsePreviewDataSem; + Semaphore mUsePreviewSem; + Semaphore mUseCaptureSem; + Semaphore mStartPreviewSem; + Semaphore mStopPreviewSem; + Semaphore mStartCaptureSem; + Semaphore mStopCaptureSem; + Semaphore mSwitchToLoadedSem; + + Vector<struct TIUTILS::Message *> mEventSignalQ; + Mutex mEventLock; + + OMX_STATETYPE mComponentState; + + bool mVnfEnabled; + bool mVstabEnabled; + + int mSensorOrientation; + int mDeviceOrientation; + bool mSensorOverclock; + + //Indicates if we should leave + //OMX_Executing state during + //stop-/startPreview + bool mOMXStateSwitch; + + int mFrameCount; + int mLastFrameCount; + unsigned int mIter; + nsecs_t mLastFPSTime; + + int mSensorIndex; + CodingMode mCodingMode; + + // Time source delta of ducati & system time + OMX_TICKS mTimeSourceDelta; + bool onlyOnce; + + Semaphore mCaptureSem; + bool mCaptureSignalled; + +}; +}; //// namespace +#endif //OMX_CAMERA_ADAPTER_H + diff --git a/camera/inc/SensorListener.h b/camera/inc/SensorListener.h new file mode 100644 index 0000000..913eb95 --- /dev/null +++ b/camera/inc/SensorListener.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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 SensorListener.h +* +* This defines API for camerahal to get sensor events +* +*/ + +#ifndef ANDROID_CAMERA_HARDWARE_SENSOR_LISTENER_H +#define ANDROID_CAMERA_HARDWARE_SENSOR_LISTENER_H + +#include <android/sensor.h> +#include <gui/Sensor.h> +#include <gui/SensorManager.h> +#include <gui/SensorEventQueue.h> +#include <utils/Looper.h> + +namespace android { + +/** + * SensorListner class - Registers with sensor manager to get sensor events + */ + +typedef void (*orientation_callback_t) (uint32_t orientation, uint32_t tilt, void* cookie); + +class SensorLooperThread : public Thread { + public: + SensorLooperThread(Looper* looper) + : Thread(false) { + mLooper = sp<Looper>(looper); + } + ~SensorLooperThread() { + mLooper.clear(); + } + + virtual bool threadLoop() { + int32_t ret = mLooper->pollOnce(-1); + return true; + } + + // force looper wake up + void wake() { + mLooper->wake(); + } + private: + sp<Looper> mLooper; +}; + + +class SensorListener : public RefBase +{ +/* public - types */ +public: + typedef enum { + SENSOR_ACCELEROMETER = 1 << 0, + SENSOR_MAGNETIC_FIELD = 1 << 1, + SENSOR_GYROSCOPE = 1 << 2, + SENSOR_LIGHT = 1 << 3, + SENSOR_PROXIMITY = 1 << 4, + SENSOR_ORIENTATION = 1 << 5, + } sensor_type_t; +/* public - functions */ +public: + SensorListener(); + ~SensorListener(); + status_t initialize(); + void setCallbacks(orientation_callback_t orientation_cb, void *cookie); + void enableSensor(sensor_type_t type); + void disableSensor(sensor_type_t type); + void handleOrientation(uint32_t orientation, uint32_t tilt); +/* public - member variables */ +public: + sp<SensorEventQueue> mSensorEventQueue; +/* private - member variables */ +private: + int sensorsEnabled; + orientation_callback_t mOrientationCb; + void *mCbCookie; + sp<Looper> mLooper; + sp<SensorLooperThread> mSensorLooperThread; + Mutex mLock; +}; + +} + +#endif diff --git a/camera/inc/TICameraParameters.h b/camera/inc/TICameraParameters.h new file mode 100644 index 0000000..1886d0c --- /dev/null +++ b/camera/inc/TICameraParameters.h @@ -0,0 +1,241 @@ +/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#ifndef TI_CAMERA_PARAMETERS_H
+#define TI_CAMERA_PARAMETERS_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+///TI Specific Camera Parameters
+class TICameraParameters
+{
+public:
+
+// Supported Camera indexes
+// Example value: "0,1,2,3", where 0-primary, 1-secondary1, 2-secondary2, 3-sterocamera
+static const char KEY_SUPPORTED_CAMERAS[];
+// Select logical Camera index
+static const char KEY_CAMERA[];
+static const char KEY_CAMERA_NAME[];
+static const char KEY_S3D_SUPPORTED[];
+static const char KEY_BURST[];
+static const char KEY_CAP_MODE[];
+static const char KEY_VSTAB[];
+static const char KEY_VSTAB_VALUES[];
+static const char KEY_VNF[];
+static const char KEY_SATURATION[];
+static const char KEY_BRIGHTNESS[];
+static const char KEY_EXPOSURE_MODE[];
+static const char KEY_SUPPORTED_EXPOSURE[];
+static const char KEY_CONTRAST[];
+static const char KEY_SHARPNESS[];
+static const char KEY_ISO[];
+static const char KEY_SUPPORTED_ISO_VALUES[];
+static const char KEY_SUPPORTED_IPP[];
+static const char KEY_IPP[];
+static const char KEY_MAN_EXPOSURE[];
+static const char KEY_METERING_MODE[];
+static const char KEY_PADDED_WIDTH[];
+static const char KEY_PADDED_HEIGHT[];
+static const char KEY_EXP_BRACKETING_RANGE[];
+static const char KEY_TEMP_BRACKETING[];
+static const char KEY_TEMP_BRACKETING_RANGE_POS[];
+static const char KEY_TEMP_BRACKETING_RANGE_NEG[];
+static const char KEY_SHUTTER_ENABLE[];
+static const char KEY_MEASUREMENT_ENABLE[];
+static const char KEY_INITIAL_VALUES[];
+static const char KEY_GBCE[];
+static const char KEY_GLBCE[];
+static const char KEY_MINFRAMERATE[];
+static const char KEY_MAXFRAMERATE[];
+
+static const char KEY_CURRENT_ISO[];
+
+static const char KEY_SENSOR_ORIENTATION[];
+static const char KEY_SENSOR_ORIENTATION_VALUES[];
+
+//TI extensions for zoom
+static const char ZOOM_SUPPORTED[];
+static const char ZOOM_UNSUPPORTED[];
+
+//TI extensions for camera capabilies
+static const char INITIAL_VALUES_TRUE[];
+static const char INITIAL_VALUES_FALSE[];
+
+//TI extensions for enabling/disabling measurements
+static const char MEASUREMENT_ENABLE[];
+static const char MEASUREMENT_DISABLE[];
+
+// TI extensions to add values for ManualConvergence and AutoConvergence mode
+static const char KEY_AUTOCONVERGENCE[];
+static const char KEY_AUTOCONVERGENCE_MODE[];
+static const char KEY_MANUALCONVERGENCE_VALUES[];
+
+//TI extensions for enabling/disabling GLBCE
+static const char GLBCE_ENABLE[];
+static const char GLBCE_DISABLE[];
+
+//TI extensions for enabling/disabling GBCE
+static const char GBCE_ENABLE[];
+static const char GBCE_DISABLE[];
+
+// TI extensions to add Min frame rate Values
+static const char VIDEO_MINFRAMERATE_5[];
+static const char VIDEO_MINFRAMERATE_10[];
+static const char VIDEO_MINFRAMERATE_15[];
+static const char VIDEO_MINFRAMERATE_20[];
+static const char VIDEO_MINFRAMERATE_24[];
+static const char VIDEO_MINFRAMERATE_25[];
+static const char VIDEO_MINFRAMERATE_30[];
+static const char VIDEO_MINFRAMERATE_33[];
+
+// TI extensions for Manual Gain and Manual Exposure
+static const char KEY_MANUAL_EXPOSURE_LEFT[];
+static const char KEY_MANUAL_EXPOSURE_RIGHT[];
+static const char KEY_MANUAL_EXPOSURE_MODES[];
+static const char KEY_MANUAL_GAIN_EV_RIGHT[];
+static const char KEY_MANUAL_GAIN_EV_LEFT[];
+static const char KEY_MANUAL_GAIN_ISO_RIGHT[];
+static const char KEY_MANUAL_GAIN_ISO_LEFT[];
+static const char KEY_MANUAL_GAIN_MODES[];
+
+//TI extensions for setting EXIF tags
+static const char KEY_EXIF_MODEL[];
+static const char KEY_EXIF_MAKE[];
+
+//TI extensions for additional GPS data
+static const char KEY_GPS_MAPDATUM[];
+static const char KEY_GPS_VERSION[];
+static const char KEY_GPS_DATESTAMP[];
+
+//TI extensions for enabling/disabling shutter sound
+static const char SHUTTER_ENABLE[];
+static const char SHUTTER_DISABLE[];
+
+//TI extensions for Temporal bracketing
+static const char BRACKET_ENABLE[];
+static const char BRACKET_DISABLE[];
+
+//TI extensions to Image post-processing
+static const char IPP_LDCNSF[];
+static const char IPP_LDC[];
+static const char IPP_NSF[];
+static const char IPP_NONE[];
+
+//TI extensions to camera mode
+static const char HIGH_PERFORMANCE_MODE[];
+static const char HIGH_QUALITY_MODE[];
+static const char HIGH_QUALITY_ZSL_MODE[];
+static const char VIDEO_MODE[];
+
+
+// TI extensions to standard android pixel formats
+static const char PIXEL_FORMAT_RAW[];
+static const char PIXEL_FORMAT_JPS[];
+static const char PIXEL_FORMAT_MPO[];
+static const char PIXEL_FORMAT_RAW_JPEG[];
+static const char PIXEL_FORMAT_RAW_MPO[];
+
+// TI extensions to standard android scene mode settings
+static const char SCENE_MODE_SPORT[];
+static const char SCENE_MODE_CLOSEUP[];
+static const char SCENE_MODE_AQUA[];
+static const char SCENE_MODE_SNOWBEACH[];
+static const char SCENE_MODE_MOOD[];
+static const char SCENE_MODE_NIGHT_INDOOR[];
+static const char SCENE_MODE_DOCUMENT[];
+static const char SCENE_MODE_BARCODE[];
+static const char SCENE_MODE_VIDEO_SUPER_NIGHT[];
+static const char SCENE_MODE_VIDEO_CINE[];
+static const char SCENE_MODE_VIDEO_OLD_FILM[];
+
+// TI extensions to standard android white balance settings.
+static const char WHITE_BALANCE_TUNGSTEN[];
+static const char WHITE_BALANCE_HORIZON[];
+static const char WHITE_BALANCE_SUNSET[];
+static const char WHITE_BALANCE_FACE[];
+
+// TI extensions to add exposure preset modes to android api
+static const char EXPOSURE_MODE_OFF[];
+static const char EXPOSURE_MODE_AUTO[];
+static const char EXPOSURE_MODE_NIGHT[];
+static const char EXPOSURE_MODE_BACKLIGHT[];
+static const char EXPOSURE_MODE_SPOTLIGHT[];
+static const char EXPOSURE_MODE_SPORTS[];
+static const char EXPOSURE_MODE_SNOW[];
+static const char EXPOSURE_MODE_BEACH[];
+static const char EXPOSURE_MODE_APERTURE[];
+static const char EXPOSURE_MODE_SMALL_APERTURE[];
+static const char EXPOSURE_MODE_FACE[];
+
+// TI extensions to standard android focus presets.
+static const char FOCUS_MODE_PORTRAIT[];
+static const char FOCUS_MODE_EXTENDED[];
+static const char FOCUS_MODE_FACE[];
+
+// TI extensions to add iso values
+static const char ISO_MODE_AUTO[];
+static const char ISO_MODE_100[];
+static const char ISO_MODE_200[];
+static const char ISO_MODE_400[];
+static const char ISO_MODE_800[];
+static const char ISO_MODE_1000[];
+static const char ISO_MODE_1200[];
+static const char ISO_MODE_1600[];
+
+// TI extensions to add values for effect settings.
+static const char EFFECT_NATURAL[];
+static const char EFFECT_VIVID[];
+static const char EFFECT_COLOR_SWAP[];
+static const char EFFECT_BLACKWHITE[];
+
+static const char KEY_S3D2D_PREVIEW[];
+static const char KEY_S3D2D_PREVIEW_MODE[];
+
+// TI extensions to add values for AutoConvergence settings.
+static const char AUTOCONVERGENCE_MODE_DISABLE[];
+static const char AUTOCONVERGENCE_MODE_FRAME[];
+static const char AUTOCONVERGENCE_MODE_CENTER[];
+static const char AUTOCONVERGENCE_MODE_FFT[];
+static const char AUTOCONVERGENCE_MODE_MANUAL[];
+
+
+//TI extensions for flash mode settings
+static const char FLASH_MODE_FILL_IN[];
+
+//TI extensions to add sensor orientation parameters
+static const char ORIENTATION_SENSOR_NONE[];
+static const char ORIENTATION_SENSOR_90[];
+static const char ORIENTATION_SENSOR_180[];
+static const char ORIENTATION_SENSOR_270[];
+
+
+//TI values for camera direction
+static const char FACING_FRONT[];
+static const char FACING_BACK[];
+
+};
+
+};
+
+#endif
+
diff --git a/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h b/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h new file mode 100644 index 0000000..b9d3952 --- /dev/null +++ b/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef V4L_CAMERA_ADAPTER_H +#define V4L_CAMERA_ADAPTER_H + +#include "CameraHal.h" +#include "BaseCameraAdapter.h" +#include "DebugUtils.h" + +namespace android { + +#define DEFAULT_PIXEL_FORMAT V4L2_PIX_FMT_YUYV +#define NB_BUFFER 10 +#define DEVICE "/dev/video4" + + +struct VideoInfo { + struct v4l2_capability cap; + struct v4l2_format format; + struct v4l2_buffer buf; + struct v4l2_requestbuffers rb; + void *mem[NB_BUFFER]; + bool isStreaming; + int width; + int height; + int formatIn; + int framesizeIn; +}; + + +/** + * Class which completely abstracts the camera hardware interaction from camera hal + * TODO: Need to list down here, all the message types that will be supported by this class + Need to implement BufferProvider interface to use AllocateBuffer of OMX if needed + */ +class V4LCameraAdapter : public BaseCameraAdapter +{ +public: + + /*--------------------Constant declarations----------------------------------------*/ + static const int32_t MAX_NO_BUFFERS = 20; + + ///@remarks OMX Camera has six ports - buffer input, time input, preview, image, video, and meta data + static const int MAX_NO_PORTS = 6; + + ///Five second timeout + static const int CAMERA_ADAPTER_TIMEOUT = 5000*1000; + +public: + + V4LCameraAdapter(); + ~V4LCameraAdapter(); + + + ///Initialzes the camera adapter creates any resources required + virtual status_t initialize(CameraProperties::Properties*, int sensor_index=0); + + //APIs to configure Camera adapter and get the current parameter set + virtual status_t setParameters(const CameraParameters& params); + virtual void getParameters(CameraParameters& params); + + // API + virtual status_t UseBuffersPreview(void* bufArr, int num); + + //API to flush the buffers for preview + status_t flushBuffers(); + +protected: + +//----------Parent class method implementation------------------------------------ + virtual status_t startPreview(); + virtual status_t stopPreview(); + virtual status_t useBuffers(CameraMode mode, void* bufArr, int num, size_t length, unsigned int queueable); + virtual status_t fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType); + virtual status_t getFrameSize(size_t &width, size_t &height); + virtual status_t getPictureBufferSize(size_t &length, size_t bufferCount); + virtual status_t getFrameDataSize(size_t &dataFrameSize, size_t bufferCount); + virtual void onOrientationEvent(uint32_t orientation, uint32_t tilt); +//----------------------------------------------------------------------------- + + +private: + + class PreviewThread : public Thread { + V4LCameraAdapter* mAdapter; + public: + PreviewThread(V4LCameraAdapter* hw) : + Thread(false), mAdapter(hw) { } + virtual void onFirstRef() { + run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY); + } + virtual bool threadLoop() { + mAdapter->previewThread(); + // loop until we need to quit + return true; + } + }; + + //Used for calculation of the average frame rate during preview + status_t recalculateFPS(); + + char * GetFrame(int &index); + + int previewThread(); + +public: + +private: + int mPreviewBufferCount; + KeyedVector<int, int> mPreviewBufs; + mutable Mutex mPreviewBufsLock; + + CameraParameters mParams; + + bool mPreviewing; + bool mCapturing; + Mutex mLock; + + int mFrameCount; + int mLastFrameCount; + unsigned int mIter; + nsecs_t mLastFPSTime; + + //variables holding the estimated framerate + float mFPS, mLastFPS; + + int mSensorIndex; + + // protected by mLock + sp<PreviewThread> mPreviewThread; + + struct VideoInfo *mVideoInfo; + int mCameraHandle; + + + int nQueued; + int nDequeued; + +}; +}; //// namespace +#endif //V4L_CAMERA_ADAPTER_H + diff --git a/camera/inc/VideoMetadata.h b/camera/inc/VideoMetadata.h new file mode 100644 index 0000000..f05ee50 --- /dev/null +++ b/camera/inc/VideoMetadata.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VIDEO_METADATA_H +#define VIDEO_METADATA_H + +/* This structure is used to pass buffer offset from Camera-Hal to Encoder component + * for specific algorithms like VSTAB & VNF + */ + +typedef struct +{ + int metadataBufferType; + void* handle; + int offset; +} +video_metadata_t; + +#endif diff --git a/heaptracked-executable.mk b/heaptracked-executable.mk new file mode 100644 index 0000000..f09f7cf --- /dev/null +++ b/heaptracked-executable.mk @@ -0,0 +1,7 @@ +LOCAL_SRC_FILES += $(OMAP4_DEBUG_SRC) +LOCAL_SHARED_LIBRARIES += $(OMAP4_DEBUG_SHARED_LIBRARIES) +LOCAL_STATIC_LIBRARIES:= libheaptracker +LOCAL_CFLAGS += $(OMAP4_DEBUG_CFLAGS) +LOCAL_LDFLAGS += $(OMAP4_DEBUG_LDFLAGS) + +include $(BUILD_EXECUTABLE) diff --git a/heaptracked-shared-library.mk b/heaptracked-shared-library.mk new file mode 100644 index 0000000..7fddc10 --- /dev/null +++ b/heaptracked-shared-library.mk @@ -0,0 +1,7 @@ +LOCAL_SRC_FILES += $(OMAP4_DEBUG_SRC) +LOCAL_SHARED_LIBRARIES += $(OMAP4_DEBUG_SHARED_LIBRARIES) +LOCAL_WHOLE_STATIC_LIBRARIES:= libheaptracker +LOCAL_CFLAGS += $(OMAP4_DEBUG_CFLAGS) +LOCAL_LDFLAGS += $(OMAP4_DEBUG_LDFLAGS) + +include $(BUILD_SHARED_LIBRARY) diff --git a/heaptracker.c b/heaptracker.c new file mode 100644 index 0000000..6f2dcfe --- /dev/null +++ b/heaptracker.c @@ -0,0 +1,576 @@ +/* +** +** Copyright (C) 2008-2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <android/log.h> +#include <pthread.h> +#include <time.h> +#include <stdarg.h> + +#include "mapinfo.h" + +extern int heaptracker_stacktrace(intptr_t*, size_t); +extern void *__real_malloc(size_t size); +extern void *__real_realloc(void *ptr, size_t size); +extern void *__real_calloc(int nmemb, int size); +extern void __real_free(void *ptr); + +static mapinfo *milist; + +#define MAX_BACKTRACE_DEPTH 15 +#define ALLOCATION_TAG 0x1ee7d00d +#define BACKLOG_TAG 0xbabecafe +#define FREE_POISON 0xa5 +#define BACKLOG_MAX 50 +#define FRONT_GUARD 0xaa +#define FRONT_GUARD_LEN (1<<4) +#define REAR_GUARD 0xbb +#define REAR_GUARD_LEN (1<<4) +#define SCANNER_SLEEP_S 3 + +struct hdr { + uint32_t tag; + struct hdr *prev; + struct hdr *next; + intptr_t bt[MAX_BACKTRACE_DEPTH]; + int bt_depth; + intptr_t freed_bt[MAX_BACKTRACE_DEPTH]; + int freed_bt_depth; + size_t size; + char front_guard[FRONT_GUARD_LEN]; +} __attribute__((packed)); + +struct ftr { + char rear_guard[REAR_GUARD_LEN]; +} __attribute__((packed)); + +static inline struct ftr * to_ftr(struct hdr *hdr) +{ + return (struct ftr *)(((char *)(hdr + 1)) + hdr->size); +} + +static inline void *user(struct hdr *hdr) +{ + return hdr + 1; +} + +static inline struct hdr *meta(void *user) +{ + return ((struct hdr *)user) - 1; +} + +extern int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap); +static void default_log(const char *fmt, ...) +{ + va_list lst; + va_start(lst, fmt); + __android_log_vprint(ANDROID_LOG_ERROR, "DEBUG", fmt, lst); + va_end(lst); +} + +/* Override this for non-printf reporting */ +void (*malloc_log)(const char *fmt, ...) = default_log; +/* Call this ad dlclose() to get leaked memory */ +void free_leaked_memory(void); + +static unsigned num; +static struct hdr *first; +static struct hdr *last; +static pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; + +static unsigned backlog_num; +static struct hdr *backlog_first; +static struct hdr *backlog_last; +static pthread_rwlock_t backlog_lock = PTHREAD_RWLOCK_INITIALIZER; + +static void print_backtrace(const intptr_t *bt, int depth) +{ + mapinfo *mi; + int cnt, rel_pc; + malloc_log("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); + for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) { + mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc); + malloc_log("\t#%02d pc %08x %s\n", cnt, + mi ? rel_pc : bt[cnt], + mi ? mi->name : "(unknown)"); + } +} + +static inline void init_front_guard(struct hdr *hdr) +{ + memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN); +} + +static inline int is_front_guard_valid(struct hdr *hdr) +{ + unsigned i; + for (i = 0; i < FRONT_GUARD_LEN; i++) + if (hdr->front_guard[i] != FRONT_GUARD) + return 0; + return 1; +} + +static inline void init_rear_guard(struct hdr *hdr) +{ + struct ftr *ftr = to_ftr(hdr); + memset(ftr->rear_guard, REAR_GUARD, REAR_GUARD_LEN); +} + +static inline int is_rear_guard_valid(struct hdr *hdr) +{ + unsigned i; + int valid = 1; + int first_mismatch = -1; + struct ftr *ftr = to_ftr(hdr); + for (i = 0; i < REAR_GUARD_LEN; i++) { + if (ftr->rear_guard[i] != REAR_GUARD) { + if (first_mismatch < 0) + first_mismatch = i; + valid = 0; + } + else if (first_mismatch >= 0) { + malloc_log("+++ REAR GUARD MISMATCH [%d, %d)\n", first_mismatch, i); + first_mismatch = -1; + } + } + + if (first_mismatch >= 0) + malloc_log("+++ REAR GUARD MISMATCH [%d, %d)\n", first_mismatch, i); + return valid; +} + +static inline void __add(struct hdr *hdr, struct hdr **first, struct hdr **last) +{ + hdr->prev = 0; + hdr->next = *last; + if (*last) + (*last)->prev = hdr; + else + *first = hdr; + *last = hdr; +} + +static inline int __del(struct hdr *hdr, struct hdr **first, struct hdr **last) +{ + if (hdr->prev) + hdr->prev->next = hdr->next; + else + *last = hdr->next; + if (hdr->next) + hdr->next->prev = hdr->prev; + else + *first = hdr->prev; + return 0; +} + +static inline void add(struct hdr *hdr, size_t size) +{ + pthread_rwlock_wrlock(&lock); + hdr->tag = ALLOCATION_TAG; + hdr->size = size; + init_front_guard(hdr); + init_rear_guard(hdr); + num++; + __add(hdr, &first, &last); + pthread_rwlock_unlock(&lock); +} + +static inline int del(struct hdr *hdr) +{ + if (hdr->tag != ALLOCATION_TAG) + return -1; + + pthread_rwlock_wrlock(&lock); + __del(hdr, &first, &last); + num--; + pthread_rwlock_unlock(&lock); + return 0; +} + +static inline void poison(struct hdr *hdr) +{ + memset(user(hdr), FREE_POISON, hdr->size); +} + +static int was_used_after_free(struct hdr *hdr) +{ + unsigned i; + const char *data = (const char *)user(hdr); + for (i = 0; i < hdr->size; i++) + if (data[i] != FREE_POISON) + return 1; + return 0; +} + +/* returns 1 if valid, *safe == 1 if safe to dump stack */ +static inline int check_guards(struct hdr *hdr, int *safe) +{ + *safe = 1; + if (!is_front_guard_valid(hdr)) { + if (hdr->front_guard[0] == FRONT_GUARD) { + malloc_log("+++ ALLOCATION %p SIZE %d HAS A CORRUPTED FRONT GUARD\n", + user(hdr), hdr->size); + } else { + malloc_log("+++ ALLOCATION %p HAS A CORRUPTED FRONT GUARD "\ + "(NOT DUMPING STACKTRACE)\n", user(hdr)); + /* Allocation header is probably corrupt, do not print stack trace */ + *safe = 0; + } + return 0; + } + + if (!is_rear_guard_valid(hdr)) { + malloc_log("+++ ALLOCATION %p SIZE %d HAS A CORRUPTED REAR GUARD\n", + user(hdr), hdr->size); + return 0; + } + + return 1; +} + +/* returns 1 if valid, *safe == 1 if safe to dump stack */ +static inline int __check_allocation(struct hdr *hdr, int *safe) +{ + int valid = 1; + *safe = 1; + + if (hdr->tag != ALLOCATION_TAG && hdr->tag != BACKLOG_TAG) { + malloc_log("+++ ALLOCATION %p HAS INVALID TAG %08x (NOT DUMPING STACKTRACE)\n", + user(hdr), hdr->tag); + /* Allocation header is probably corrupt, do not dequeue or dump stack + * trace. + */ + *safe = 0; + return 0; + } + + if (hdr->tag == BACKLOG_TAG && was_used_after_free(hdr)) { + malloc_log("+++ ALLOCATION %p SIZE %d WAS USED AFTER BEING FREED\n", + user(hdr), hdr->size); + valid = 0; + /* check the guards to see if it's safe to dump a stack trace */ + (void)check_guards(hdr, safe); + } + else + valid = check_guards(hdr, safe); + + if (!valid && *safe) { + malloc_log("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", + user(hdr), hdr->size); + print_backtrace(hdr->bt, hdr->bt_depth); + if (hdr->tag == BACKLOG_TAG) { + malloc_log("+++ ALLOCATION %p SIZE %d FREED HERE:\n", + user(hdr), hdr->size); + print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + } + } + + return valid; +} + +static inline int __del_and_check(struct hdr *hdr, + struct hdr **first, struct hdr **last, unsigned *cnt, + int *safe) +{ + int valid; + valid = __check_allocation(hdr, safe); + if (safe) { + (*cnt)--; + __del(hdr, first, last); + } + return valid; +} + +static inline void __del_from_backlog(struct hdr *hdr) +{ + int safe; + (void)__del_and_check(hdr, + &backlog_first, &backlog_last, &backlog_num, + &safe); + hdr->tag = 0; /* clear the tag */ +} + +static inline void del_from_backlog(struct hdr *hdr) +{ + pthread_rwlock_wrlock(&backlog_lock); + __del_from_backlog(hdr); + pthread_rwlock_unlock(&backlog_lock); +} + +static inline int del_leak(struct hdr *hdr, int *safe) +{ + int valid; + pthread_rwlock_wrlock(&lock); + valid = __del_and_check(hdr, + &first, &last, &num, + safe); + pthread_rwlock_unlock(&lock); + return valid; +} + +static inline void add_to_backlog(struct hdr *hdr) +{ + pthread_rwlock_wrlock(&backlog_lock); + hdr->tag = BACKLOG_TAG; + backlog_num++; + __add(hdr, &backlog_first, &backlog_last); + poison(hdr); + /* If we've exceeded the maximum backlog, clear it up */ + while (backlog_num > BACKLOG_MAX) { + struct hdr *gone = backlog_first; + __del_from_backlog(gone); + __real_free(gone); + } + pthread_rwlock_unlock(&backlog_lock); +} + +void* __wrap_malloc(size_t size) +{ +// malloc_tracker_log("%s: %s\n", __FILE__, __FUNCTION__); + struct hdr *hdr = __real_malloc(sizeof(struct hdr) + size + + sizeof(struct ftr)); + if (hdr) { + hdr->bt_depth = heaptracker_stacktrace( + hdr->bt, MAX_BACKTRACE_DEPTH); + add(hdr, size); + return hdr+1; + } + return NULL; +} + +void __wrap_free(void *ptr) +{ + struct hdr *hdr; + if (!ptr) /* ignore free(NULL) */ + return; + + hdr = meta(ptr); + + if (del(hdr) < 0) { + intptr_t bt[MAX_BACKTRACE_DEPTH]; + int depth; + depth = heaptracker_stacktrace(bt, MAX_BACKTRACE_DEPTH); + if (hdr->tag == BACKLOG_TAG) { + malloc_log("+++ ALLOCATION %p SIZE %d BYTES MULTIPLY FREED!\n", + user(hdr), hdr->size); + malloc_log("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", + user(hdr), hdr->size); + print_backtrace(hdr->bt, hdr->bt_depth); + /* hdr->freed_bt_depth should be nonzero here */ + malloc_log("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", + user(hdr), hdr->size); + print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + malloc_log("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n", + user(hdr), hdr->size); + print_backtrace(bt, depth); + } + else { + malloc_log("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", + user(hdr)); + print_backtrace(bt, depth); + /* Leak here so that we do not crash */ + //__real_free(user(hdr)); + } + } + else { + hdr->freed_bt_depth = heaptracker_stacktrace(hdr->freed_bt, + MAX_BACKTRACE_DEPTH); + add_to_backlog(hdr); + } +} + +void *__wrap_realloc(void *ptr, size_t size) +{ + struct hdr *hdr; + + if (!size) { + __wrap_free(ptr); + return NULL; + } + + if (!ptr) + return __wrap_malloc(size); + + hdr = meta(ptr); + +// malloc_log("%s: %s\n", __FILE__, __FUNCTION__); + if (del(hdr) < 0) { + intptr_t bt[MAX_BACKTRACE_DEPTH]; + int depth; + depth = heaptracker_stacktrace(bt, MAX_BACKTRACE_DEPTH); + if (hdr->tag == BACKLOG_TAG) { + malloc_log("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n", + user(hdr), size, hdr->size); + malloc_log("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", + user(hdr), hdr->size); + print_backtrace(hdr->bt, hdr->bt_depth); + /* hdr->freed_bt_depth should be nonzero here */ + malloc_log("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", + user(hdr), hdr->size); + print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + malloc_log("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n", + user(hdr), hdr->size); + print_backtrace(bt, depth); + + /* We take the memory out of the backlog and fall through so the + * reallocation below succeeds. Since we didn't really free it, we + * can default to this behavior. + */ + del_from_backlog(hdr); + } + else { + malloc_log("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", + user(hdr), size); + print_backtrace(bt, depth); + // just get a whole new allocation and leak the old one + return __real_realloc(0, size); + // return __real_realloc(user(hdr), size); // assuming it was allocated externally + } + } + + hdr = __real_realloc(hdr, sizeof(struct hdr) + size); + if (hdr) { + hdr->bt_depth = heaptracker_stacktrace(hdr->bt, MAX_BACKTRACE_DEPTH); + add(hdr, size); + return user(hdr); + } + + return NULL; +} + +void *__wrap_calloc(int nmemb, size_t size) +{ +// malloc_tracker_log("%s: %s\n", __FILE__, __FUNCTION__); + struct hdr *hdr; + size_t __size = nmemb * size; + hdr = __real_calloc(1, sizeof(struct hdr) + __size); + if (hdr) { + hdr->bt_depth = heaptracker_stacktrace( + hdr->bt, MAX_BACKTRACE_DEPTH); + add(hdr, __size); + return user(hdr); + } + return NULL; +} + +void heaptracker_free_leaked_memory(void) +{ + struct hdr *del; int cnt; + + if (num) + malloc_log("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num); + + while (last) { + int safe; + del = last; + malloc_log("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n", + del->size, user(del), num); + if (del_leak(del, &safe)) { + /* safe == 1, because the allocation is valid */ + malloc_log("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", + user(del), del->size); + print_backtrace(del->bt, del->bt_depth); + } + __real_free(del); + } + +// malloc_log("+++ DELETING %d BACKLOGGED ALLOCATIONS\n", backlog_num); + while (backlog_last) { + del = backlog_first; + del_from_backlog(del); + __real_free(del); + } +} + +static int check_list(struct hdr *list, pthread_rwlock_t *rwlock) +{ + struct hdr *hdr; + int safe, num_checked; + + pthread_rwlock_rdlock(rwlock); + num_checked = 0; + hdr = list; + while (hdr) { + (void)__check_allocation(hdr, &safe); + hdr = hdr->next; + num_checked++; + } + pthread_rwlock_unlock(rwlock); + + return num_checked; +} + +static pthread_t scanner_thread; +static pthread_cond_t scanner_cond = PTHREAD_COND_INITIALIZER; +static int scanner_stop; +static pthread_mutex_t scanner_lock = PTHREAD_MUTEX_INITIALIZER; + +static void* scanner(void *data __attribute__((unused))) +{ + struct timespec ts; + int num_checked, num_checked_backlog; + + while (1) { + num_checked = check_list(last, &lock); + num_checked_backlog = check_list(backlog_last, &backlog_lock); + +// malloc_log("@@@ scanned %d/%d allocs and %d/%d freed\n", +// num_checked, num, +// num_checked_backlog, backlog_num); + + pthread_mutex_lock(&scanner_lock); + if (!scanner_stop) { + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += SCANNER_SLEEP_S; + pthread_cond_timedwait(&scanner_cond, &scanner_lock, &ts); + } + if (scanner_stop) { + pthread_mutex_unlock(&scanner_lock); + break; + } + pthread_mutex_unlock(&scanner_lock); + } + +// malloc_log("@@@ scanner thread exiting"); + return NULL; +} + +static void init(void) __attribute__((constructor)); +static void init(void) +{ +// malloc_log("@@@ start scanner thread"); + milist = init_mapinfo(getpid()); + pthread_create(&scanner_thread, + NULL, + scanner, + NULL); +} + +static void deinit(void) __attribute__((destructor)); +static void deinit(void) +{ +// malloc_log("@@@ signal stop to scanner thread"); + pthread_mutex_lock(&scanner_lock); + scanner_stop = 1; + pthread_cond_signal(&scanner_cond); + pthread_mutex_unlock(&scanner_lock); +// malloc_log("@@@ wait for scanner thread to exit"); + pthread_join(scanner_thread, NULL); +// malloc_log("@@@ scanner thread stopped"); + + heaptracker_free_leaked_memory(); + deinit_mapinfo(milist); +} diff --git a/hwc/Android.mk b/hwc/Android.mk new file mode 100644 index 0000000..af72df2 --- /dev/null +++ b/hwc/Android.mk @@ -0,0 +1,19 @@ +# HWC under heavy development and should not be included in builds for now +LOCAL_PATH := $(call my-dir) + +# HAL module implementation, not prelinked and stored in +# hw/<HWCOMPOSE_HARDWARE_MODULE_ID>.<ro.product.board>.so +include $(CLEAR_VARS) +LOCAL_PRELINK_MODULE := false +LOCAL_ARM_MODE := arm +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/../vendor/lib/hw +LOCAL_SHARED_LIBRARIES := liblog libEGL libcutils libutils libhardware +LOCAL_SRC_FILES := hwc.c + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := hwcomposer.omap4 +LOCAL_CFLAGS := -DLOG_TAG=\"ti_hwc\" +# LOG_NDEBUG=0 means verbose logging enabled +# LOCAL_CFLAGS += -DLOG_NDEBUG=0 +include $(BUILD_SHARED_LIBRARY) diff --git a/hwc/hal_public.h b/hwc/hal_public.h new file mode 100644 index 0000000..62c7849 --- /dev/null +++ b/hwc/hal_public.h @@ -0,0 +1,162 @@ +/* Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HAL_PUBLIC_H +#define HAL_PUBLIC_H + +/* Authors of third party hardware composer (HWC) modules will need to include + * this header to access functionality in the gralloc and framebuffer HALs. + */ + +#include <hardware/gralloc.h> + +#define ALIGN(x,a) (((x) + (a) - 1L) & ~((a) - 1L)) +#define HW_ALIGN 32 + +/* This can be tuned down as appropriate for the SOC. + * + * IMG formats are usually a single sub-alloc. + * Some OEM video formats are two sub-allocs (Y, UV planes). + * Future OEM video formats might be three sub-allocs (Y, U, V planes). + */ +#define MAX_SUB_ALLOCS 3 + +typedef struct +{ + native_handle_t base; + + /* These fields can be sent cross process. They are also valid + * to duplicate within the same process. + * + * A table is stored within psPrivateData on gralloc_module_t (this + * is obviously per-process) which maps stamps to a mapped + * PVRSRV_CLIENT_MEM_INFO in that process. Each map entry has a lock + * count associated with it, satisfying the requirements of the + * Android API. This also prevents us from leaking maps/allocations. + * + * This table has entries inserted either by alloc() + * (alloc_device_t) or map() (gralloc_module_t). Entries are removed + * by free() (alloc_device_t) and unmap() (gralloc_module_t). + * + * As a special case for framebuffer_device_t, framebuffer_open() + * will add and framebuffer_close() will remove from this table. + */ + +#define IMG_NATIVE_HANDLE_NUMFDS MAX_SUB_ALLOCS + /* The `fd' field is used to "export" a meminfo to another process. + * Therefore, it is allocated by alloc_device_t, and consumed by + * gralloc_module_t. The framebuffer_device_t does not need a handle, + * and the special value IMG_FRAMEBUFFER_FD is used instead. + */ + int fd[MAX_SUB_ALLOCS]; + +#define IMG_NATIVE_HANDLE_NUMINTS ((sizeof(unsigned long long) / sizeof(int)) + 5) + /* A KERNEL unique identifier for any exported kernel meminfo. Each + * exported kernel meminfo will have a unique stamp, but note that in + * userspace, several meminfos across multiple processes could have + * the same stamp. As the native_handle can be dup(2)'d, there could be + * multiple handles with the same stamp but different file descriptors. + */ + unsigned long long ui64Stamp; + + /* This is used for buffer usage validation when locking a buffer, + * and also in WSEGL (for the composition bypass feature). + */ + int usage; + + /* In order to do efficient cache flushes we need the buffer dimensions + * and format. These are available on the ANativeWindowBuffer, + * but the platform doesn't pass them down to the graphics HAL. + * + * These fields are also used in the composition bypass. In this + * capacity, these are the "real" values for the backing allocation. + */ + int iWidth; + int iHeight; + int iFormat; + unsigned int uiBpp; +} +__attribute__((aligned(sizeof(int)),packed)) IMG_native_handle_t; + +typedef struct +{ + framebuffer_device_t base; + + /* The HWC was loaded. post() is no longer responsible for presents */ + int bBypassPost; + + /* Custom-blit components in lieu of overlay hardware */ + int (*Blit)(framebuffer_device_t *device, buffer_handle_t src, + buffer_handle_t dest, int w, int h, int x, int y); + + /* HWC path for present posts */ + int (*Post2)(framebuffer_device_t *fb, buffer_handle_t *buffers, + int num_buffers, void *data, int data_length); +} +IMG_framebuffer_device_public_t; + +typedef struct IMG_gralloc_module_public_t +{ + gralloc_module_t base; + + /* If the framebuffer has been opened, this will point to the + * framebuffer device data required by the allocator, WSEGL + * modules and composerhal. + */ + IMG_framebuffer_device_public_t *psFrameBufferDevice; + + int (*GetPhyAddrs)(struct IMG_gralloc_module_public_t const* module, + buffer_handle_t handle, + unsigned int auiPhyAddr[MAX_SUB_ALLOCS]); +} +IMG_gralloc_module_public_t; + +typedef struct +{ + int l, t, w, h; +} +IMG_write_lock_rect_t; + +typedef struct IMG_buffer_format_public_t +{ + /* Buffer formats are returned as a linked list */ + struct IMG_buffer_format_public_t *psNext; + + /* HAL_PIXEL_FORMAT_... enumerant */ + int iHalPixelFormat; + + /* WSEGL_PIXELFORMAT_... enumerant */ + int iWSEGLPixelFormat; + + /* Friendly name for format */ + const char *const szName; + + /* Bits (not bytes) per pixel */ + unsigned int uiBpp; + + /* GPU output format (creates EGLConfig for format) */ + int bGPURenderable; +} +IMG_buffer_format_public_t; + +#endif /* HAL_PUBLIC_H */ diff --git a/hwc/hwc.c b/hwc/hwc.c new file mode 100644 index 0000000..5f33764 --- /dev/null +++ b/hwc/hwc.c @@ -0,0 +1,693 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + +#include <errno.h> +#include <malloc.h> +#include <stdlib.h> +#include <stdarg.h> + +#include <cutils/properties.h> +#include <cutils/log.h> +#include <cutils/native_handle.h> +#include <hardware/hardware.h> +#include <hardware/hwcomposer.h> +#include <EGL/egl.h> +#include <utils/Timers.h> + +#include <video/dsscomp.h> + +#include "hal_public.h" + +#define MAX_HW_OVERLAYS 4 +#define MAX_SCALING_OVERLAYS 3 +#define HAL_PIXEL_FORMAT_BGRX_8888 0x1FF +#define HAL_PIXEL_FORMAT_TI_NV12 0x100 +#define HAL_PIXEL_FORMAT_TI_NV12_PADDED 0x101 +#define MAX_TILER_SLOT (4 << 20) + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x))) + +struct omap4_hwc_module { + hwc_module_t base; + + IMG_framebuffer_device_public_t *fb_dev; +}; +typedef struct omap4_hwc_module omap4_hwc_module_t; + +struct omap4_hwc_device { + hwc_composer_device_t base; + + IMG_framebuffer_device_public_t *fb_dev; + struct dsscomp_setup_dispc_data dsscomp_data; + + buffer_handle_t *buffers; + int use_sgx; + + int flags_rgb_order; + int flags_nv12_only; +}; +typedef struct omap4_hwc_device omap4_hwc_device_t; + +static int debug = 0; + +static void dump_layer(hwc_layer_t const* l) +{ + LOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", + l->compositionType, l->flags, l->handle, l->transform, l->blending, + l->sourceCrop.left, + l->sourceCrop.top, + l->sourceCrop.right, + l->sourceCrop.bottom, + l->displayFrame.left, + l->displayFrame.top, + l->displayFrame.right, + l->displayFrame.bottom); +} + +static void dump_dsscomp(struct dsscomp_setup_dispc_data *d) +{ + struct dss2_mgr_info *mi = &d->mgr; + + LOGE("[%08x] set: %c%c%c(dis%d alpha=%d col=%08x ilace=%d n=%d)\n", + d->sync_id, + (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-', + (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-', + (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-', + mi->ix, + mi->alpha_blending, mi->default_color, + mi->interlaced, + d->num_ovls); + + unsigned i; + for (i = 0; i < d->num_ovls; i++) { + struct dss2_ovl_info *oi = d->ovls + i; + struct dss2_ovl_cfg *c = &oi->cfg; + if (c->zonly) + LOGE("ovl%d(%s z%d)\n", + c->ix, c->enabled ? "ON" : "off", c->zorder); + else + LOGE("ovl%d(%s z%d %x%s *%d%% %d*%d:%d,%d+%d,%d rot%d%s => %d,%d+%d,%d %p/%p|%d)\n", + c->ix, c->enabled ? "ON" : "off", c->zorder, c->color_mode, + c->pre_mult_alpha ? " premult" : "", + (c->global_alpha * 100 + 128) / 255, + c->width, c->height, c->crop.x, c->crop.y, + c->crop.w, c->crop.h, + c->rotation, c->mirror ? "+mir" : "", + c->win.x, c->win.y, c->win.w, c->win.h, + (void *) oi->ba, (void *) oi->uv, c->stride); + } +} + +static int omap4_hwc_is_valid_format(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_BGRX_8888: + case HAL_PIXEL_FORMAT_TI_NV12: + case HAL_PIXEL_FORMAT_TI_NV12_PADDED: + return 1; + + default: + LOGI("invalid format %d", format); + return 0; + } +} + +static int scaled(hwc_layer_t *layer) +{ + int w = layer->sourceCrop.right - layer->sourceCrop.left; + int h = layer->sourceCrop.bottom - layer->sourceCrop.top; + /* TODO: skip w/h if rotated by 90 */ + return (layer->displayFrame.right - layer->displayFrame.left != w || + layer->displayFrame.bottom - layer->displayFrame.top != h); +} + +static int sync_id = 0; + +#define is_ALPHA(format) ((format) == HAL_PIXEL_FORMAT_BGRA_8888 || (format) == HAL_PIXEL_FORMAT_RGBA_8888) +#define is_RGB(format) ((format) == HAL_PIXEL_FORMAT_BGRA_8888 || (format) == HAL_PIXEL_FORMAT_RGB_565 || (format) == HAL_PIXEL_FORMAT_BGRX_8888) +#define is_BGR(format) ((format) == HAL_PIXEL_FORMAT_RGBX_8888 || (format) == HAL_PIXEL_FORMAT_RGBA_8888) +#define is_NV12(format) ((format) == HAL_PIXEL_FORMAT_TI_NV12 || (format) == HAL_PIXEL_FORMAT_TI_NV12_PADDED) + +static void +omap4_hwc_setup_layer_base(struct dss2_ovl_cfg *oc, int index, int format, int width, int height) +{ + unsigned int bits_per_pixel; + + /* YUV2RGB conversion */ + const struct omap_dss_cconv_coefs ctbl_bt601_5 = { + 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, + }; + + /* convert color format */ + switch (format) { + case HAL_PIXEL_FORMAT_RGBX_8888: + /* Should be XBGR32, but this isn't supported */ + oc->color_mode = OMAP_DSS_COLOR_RGB24U; + bits_per_pixel = 32; + break; + + case HAL_PIXEL_FORMAT_RGBA_8888: + /* Should be ABGR32, but this isn't supported */ + oc->color_mode = OMAP_DSS_COLOR_ARGB32; + bits_per_pixel = 32; + break; + + case HAL_PIXEL_FORMAT_BGRA_8888: + oc->color_mode = OMAP_DSS_COLOR_ARGB32; + bits_per_pixel = 32; + break; + + case HAL_PIXEL_FORMAT_BGRX_8888: + oc->color_mode = OMAP_DSS_COLOR_RGB24U; + bits_per_pixel = 32; + break; + + case HAL_PIXEL_FORMAT_RGB_565: + oc->color_mode = OMAP_DSS_COLOR_RGB16; + bits_per_pixel = 16; + break; + + case HAL_PIXEL_FORMAT_TI_NV12: + case HAL_PIXEL_FORMAT_TI_NV12_PADDED: + oc->color_mode = OMAP_DSS_COLOR_NV12; + bits_per_pixel = 8; + oc->cconv = ctbl_bt601_5; + break; + + default: + /* Should have been filtered out */ + LOGV("Unsupported pixel format"); + return; + } + + oc->width = width; + oc->height = height; + oc->stride = ALIGN(width, HW_ALIGN) * bits_per_pixel / 8; + + oc->enabled = 1; + oc->global_alpha = 255; + oc->zorder = index; + oc->ix = 0; + + /* defaults for SGX framebuffer renders */ + oc->crop.w = oc->win.w = width; + oc->crop.h = oc->win.h = height; + + /* for now interlacing and vc1 info is not supplied */ + oc->ilace = OMAP_DSS_ILACE_NONE; + oc->vc1.enable = 0; +} + +static void +omap4_hwc_setup_layer(omap4_hwc_device_t *hwc_dev, struct dss2_ovl_info *ovl, + hwc_layer_t *layer, int index, + int format, int width, int height) +{ + struct dss2_ovl_cfg *oc = &ovl->cfg; + + //dump_layer(layer); + + omap4_hwc_setup_layer_base(oc, index, format, width, height); + + /* convert transformation - assuming 0-set config */ + if (layer->transform & HWC_TRANSFORM_FLIP_H) + oc->mirror = 1; + if (layer->transform & HWC_TRANSFORM_FLIP_V) { + oc->rotation = 2; + oc->mirror = !oc->mirror; + } + if (layer->transform & HWC_TRANSFORM_ROT_90) { + oc->rotation += oc->mirror ? -1 : 1; + oc->rotation &= 3; + } + + oc->pre_mult_alpha = layer->blending == HWC_BLENDING_PREMULT; + + /* display position */ + oc->win.x = layer->displayFrame.left; + oc->win.y = layer->displayFrame.top; + oc->win.w = layer->displayFrame.right - layer->displayFrame.left; + oc->win.h = layer->displayFrame.bottom - layer->displayFrame.top; + + /* crop */ + oc->crop.x = layer->sourceCrop.left; + oc->crop.y = layer->sourceCrop.top; + oc->crop.w = layer->sourceCrop.right - layer->sourceCrop.left; + oc->crop.h = layer->sourceCrop.bottom - layer->sourceCrop.top; +} + +static int omap4_hwc_is_valid_layer(hwc_layer_t *layer, + IMG_native_handle_t *handle) +{ + /* Skip layers are handled by SF */ + if ((layer->flags & HWC_SKIP_LAYER) || !handle) + return 0; + + if (!omap4_hwc_is_valid_format(handle->iFormat)) + return 0; + + /* 1D buffers: no transform, must fit in TILER slot */ + if (!is_NV12(handle->iFormat)) { + if (layer->transform) + return 0; + int bpp = (handle->iFormat == HAL_PIXEL_FORMAT_RGB_565 ? 2 : 4); + int stride = ALIGN(handle->iWidth, HW_ALIGN) * bpp; + if (stride * handle->iHeight > MAX_TILER_SLOT) + return 0; + } + return 1; +} + +static int omap4_hwc_prepare(struct hwc_composer_device *dev, hwc_layer_list_t* list) +{ + omap4_hwc_device_t *hwc_dev = (omap4_hwc_device_t *)dev; + struct dsscomp_setup_dispc_data *dsscomp = &hwc_dev->dsscomp_data; + unsigned int num_possible_overlay_layers = 0; + unsigned int num_composited_layers = 0; + unsigned int num_scaled_layers = 0; + unsigned int i; + unsigned int num_RGB = 0; + unsigned int num_BGR = 0; + + memset(dsscomp, 0x0, sizeof(*dsscomp)); + dsscomp->sync_id = sync_id++; + + /* Figure out how many layers we can support via DSS */ + num_composited_layers = list->numHwLayers; + + for (i = 0; i < list->numHwLayers; i++) { + hwc_layer_t *layer = &list->hwLayers[i]; + IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle; + + layer->compositionType = HWC_FRAMEBUFFER; + + if (omap4_hwc_is_valid_layer(layer, handle)) { + num_possible_overlay_layers++; + + if (scaled(layer)) + num_scaled_layers++; + + if (is_BGR(handle->iFormat)) + num_BGR++; + else if (is_RGB(handle->iFormat)) + num_RGB++; + } + } + + /* phase 2 logic: all DSS rendering */ + if (num_possible_overlay_layers <= MAX_HW_OVERLAYS && + num_possible_overlay_layers == num_composited_layers && + num_scaled_layers <= MAX_SCALING_OVERLAYS && + (num_BGR == 0 || num_RGB == 0 || !hwc_dev->flags_rgb_order) && + num_possible_overlay_layers) { + /* All layers can be handled by the DSS -- don't use SGX for composition */ + hwc_dev->use_sgx = 0; + dsscomp->mgr.swap_rb = num_BGR != 0; + } else { + /* Use SGX for composition plus first 3 layers that are DSS renderable */ + hwc_dev->use_sgx = 1; + dsscomp->mgr.swap_rb = is_BGR(hwc_dev->fb_dev->base.format); + } + if (debug) { + LOGD("prepare (%d) %d layers - %s (poss=%d/%d scaled, comp=%d, rgb=%d,bgr=%d)\n", + dsscomp->sync_id, list->numHwLayers, + hwc_dev->use_sgx ? "SGX+OVL" : "all-OVL", + num_possible_overlay_layers, num_scaled_layers, num_composited_layers, num_RGB, num_BGR); + } + + /* setup pipes */ + dsscomp->num_ovls = hwc_dev->use_sgx; + int z = 0; + int fb_z = -1, fb_zmax = 0; + int scaled_gfx = 0; + + /* set up if DSS layers */ + for (i = 0; i < list->numHwLayers && dsscomp->num_ovls < MAX_HW_OVERLAYS; i++) { + hwc_layer_t *layer = &list->hwLayers[i]; + IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle; + + if (handle && + omap4_hwc_is_valid_layer(layer, handle) && + /* can't have a transparent overlay in the middle of the framebuffer stack */ + !(is_ALPHA(handle->iFormat) && fb_z >= 0) && + /* skip non-NV12 layers if also using SGX (if nv12_only flag is set) */ + (!hwc_dev->flags_nv12_only || (!hwc_dev->use_sgx || is_NV12(handle->iFormat))) && + /* make sure RGB ordering is consistent (if rgb_order flag is set) */ + (!(dsscomp->mgr.swap_rb ? is_RGB(handle->iFormat) : is_BGR(handle->iFormat)) || + !hwc_dev->flags_rgb_order)) { + /* render via DSS overlay */ + layer->compositionType = HWC_OVERLAY; + /* clear layers above DSS layer areas */ + layer->hints |= HWC_HINT_CLEAR_FB; + hwc_dev->buffers[dsscomp->num_ovls] = layer->handle; + + omap4_hwc_setup_layer(hwc_dev, + &dsscomp->ovls[dsscomp->num_ovls], + &list->hwLayers[i], + z, + handle->iFormat, + handle->iWidth, + handle->iHeight); + /* TODO: we need to use gfx for the a layer that is not scaled */ + dsscomp->ovls[dsscomp->num_ovls].cfg.ix = dsscomp->num_ovls; + /* just marking dss layers */ + dsscomp->ovls[dsscomp->num_ovls].address = (void *) (dsscomp->num_ovls * 4096 + 0xA0000000); + dsscomp->ovls[dsscomp->num_ovls].uv = (__u32) hwc_dev->buffers[dsscomp->num_ovls]; + + /* ensure GFX layer is never scaled */ + if (dsscomp->num_ovls == 0) { + scaled_gfx = scaled(layer); + } else if (scaled_gfx && !scaled(layer)) { + /* swap GFX layer with this one */ + dsscomp->ovls[dsscomp->num_ovls].cfg.ix = 0; + dsscomp->ovls[0].cfg.ix = dsscomp->num_ovls; + scaled_gfx = 0; + } + + dsscomp->num_ovls++; + z++; + } else if (hwc_dev->use_sgx) { + if (fb_z < 0) { + /* NOTE: we are not handling transparent cutout for now */ + fb_z = fb_zmax = z; + z++; + } else { + /* move fb z-order up (by lowering dss layers) */ + while (fb_zmax < z - 1) + dsscomp->ovls[1 + fb_zmax++].cfg.zorder--; + } + } + } + + /* clear FB above DSS layers */ + /* FIXME: for now assume full screen layers. later this can be optimized */ + int obstructed = 0; + if (dsscomp->num_ovls > hwc_dev->use_sgx) { + for (i = list->numHwLayers; i > 0;) { + i--; + hwc_layer_t *layer = &list->hwLayers[i]; + if ((layer->flags & HWC_SKIP_LAYER) || !layer->handle) + continue; + if (layer->compositionType != HWC_OVERLAY) + obstructed = 1; + else if (obstructed) + layer->hints |= HWC_HINT_CLEAR_FB; + } + } + + /* if scaling GFX (e.g. only 1 scaled surface) use a VID pipe */ + if (scaled_gfx) + dsscomp->ovls[0].cfg.ix = 1; + + /* assign a z-layer for fb */ + if (hwc_dev->use_sgx && fb_z < 0) { + fb_z = z; + z++; + } + + if (z != dsscomp->num_ovls || dsscomp->num_ovls > MAX_HW_OVERLAYS) + LOGE("**** used %d z-layers for %d overlays\n", z, dsscomp->num_ovls); + + if (hwc_dev->use_sgx) { + hwc_dev->buffers[0] = NULL; + omap4_hwc_setup_layer_base(&dsscomp->ovls[0].cfg, fb_z, + hwc_dev->fb_dev->base.format, + hwc_dev->fb_dev->base.width, + hwc_dev->fb_dev->base.height); + dsscomp->ovls[0].uv = (__u32) hwc_dev->buffers[0]; + } + + dsscomp->mode = DSSCOMP_SETUP_DISPLAY; + dsscomp->mgr.ix = 0; + dsscomp->mgr.alpha_blending = 1; + + return 0; +} + +static int omap4_hwc_set(struct hwc_composer_device *dev, hwc_display_t dpy, + hwc_surface_t sur, hwc_layer_list_t* list) +{ + omap4_hwc_device_t *hwc_dev = (omap4_hwc_device_t *)dev; + struct dsscomp_setup_dispc_data *dsscomp = &hwc_dev->dsscomp_data; + int err; + unsigned int i; + + if (!list) { + LOGE("list is NULL"); + return 0; + } + + char big_log[1024]; + int e = sizeof(big_log); + char *end = big_log + e; + e -= snprintf(end - e, e, "set H{"); + for (i = 0; i < list->numHwLayers; i++) { + if (i) + e -= snprintf(end - e, e, " "); + hwc_layer_t *layer = &list->hwLayers[i]; + IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle; + e -= snprintf(end - e, e, "%p:%s,", handle, layer->compositionType == HWC_OVERLAY ? "DSS" : "SGX"); + if ((layer->flags & HWC_SKIP_LAYER) || !handle) { + e -= snprintf(end - e, e, "SKIP"); + continue; + } + if (layer->flags & HWC_HINT_CLEAR_FB) + e -= snprintf(end - e, e, "CLR,"); +#define FMT(f) ((f) == HAL_PIXEL_FORMAT_TI_NV12 ? "NV12" : \ + (f) == HAL_PIXEL_FORMAT_BGRX_8888 ? "xRGB32" : \ + (f) == HAL_PIXEL_FORMAT_RGBX_8888 ? "xBGR32" : \ + (f) == HAL_PIXEL_FORMAT_BGRA_8888 ? "ARGB32" : \ + (f) == HAL_PIXEL_FORMAT_RGBA_8888 ? "ABGR32" : \ + (f) == HAL_PIXEL_FORMAT_RGB_565 ? "RGB565" : "??") + e -= snprintf(end - e, e, "%d*%d(%s)", handle->iWidth, handle->iHeight, FMT(handle->iFormat)); + if (layer->transform) + e -= snprintf(end - e, e, "~%d", layer->transform); +#undef FMT + } + e -= snprintf(end - e, e, "} D{"); + for (i = 0; i < dsscomp->num_ovls; i++) { + if (i) + e -= snprintf(end - e, e, " "); + e -= snprintf(end - e, e, "%d=", dsscomp->ovls[i].cfg.ix); +#define FMT(f) ((f) == OMAP_DSS_COLOR_NV12 ? "NV12" : \ + (f) == OMAP_DSS_COLOR_RGB24U ? "xRGB32" : \ + (f) == OMAP_DSS_COLOR_ARGB32 ? "ARGB32" : \ + (f) == OMAP_DSS_COLOR_RGB16 ? "RGB565" : "??") + if (dsscomp->ovls[i].cfg.enabled) + e -= snprintf(end - e, e, "%08x:%d*%d,%s", + dsscomp->ovls[i].ba, + dsscomp->ovls[i].cfg.width, + dsscomp->ovls[i].cfg.height, + FMT(dsscomp->ovls[i].cfg.color_mode)); +#undef FMT + else + e -= snprintf(end - e, e, "-"); + } + e -= snprintf(end - e, e, "} L{"); + for (i = 0; i < dsscomp->num_ovls; i++) { + if (i) + e -= snprintf(end - e, e, " "); + e -= snprintf(end - e, e, "%p", hwc_dev->buffers[i]); + } + e -= snprintf(end - e, e, "}%s\n", hwc_dev->use_sgx ? " swap" : ""); + if (debug) { + LOGD("%s", big_log); + } + + // LOGD("set %d layers (sgx=%d)\n", dsscomp->num_ovls, hwc_dev->use_sgx); + + if (hwc_dev->use_sgx) { + if (!eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur)) { + LOGE("eglSwapBuffers error"); + err = HWC_EGL_ERROR; + goto err_out; + } + } + + //dump_dsscomp(dsscomp); + + err = hwc_dev->fb_dev->Post2((framebuffer_device_t *)hwc_dev->fb_dev, + hwc_dev->buffers, + dsscomp->num_ovls, + dsscomp, sizeof(*dsscomp)); + if (err) + LOGE("Post2 error"); + +err_out: + return err; +} + +static int dump_printf(char *buff, int buff_len, int len, const char *fmt, ...) +{ + va_list ap; + + int print_len; + + va_start(ap, fmt); + + print_len = vsnprintf(buff + len, buff_len - len, fmt, ap); + + va_end(ap); + + return len + print_len; +} + +static void omap4_hwc_dump(struct hwc_composer_device *dev, char *buff, int buff_len) +{ + omap4_hwc_device_t *hwc_dev = (omap4_hwc_device_t *)dev; + struct dsscomp_setup_dispc_data *dsscomp = &hwc_dev->dsscomp_data; + int len = 0; + int i; + + len = dump_printf(buff, buff_len, len, "omap4_hwc %d:\n", dsscomp->num_ovls); + + for (i = 0; i < dsscomp->num_ovls; i++) { + struct dss2_ovl_cfg *cfg = &dsscomp->ovls[i].cfg; + + len = dump_printf(buff, buff_len, len, " layer %d:\n", i); + len = dump_printf(buff, buff_len, len, " enabled: %s\n", + cfg->enabled ? "true" : "false"); + len = dump_printf(buff, buff_len, len, " buff: %dx%d stride: %d:\n", + cfg->width, cfg->height, cfg->stride); + len = dump_printf(buff, buff_len, len, " src: (%d,%d) %dx%d\n", + cfg->crop.x, cfg->crop.y, cfg->crop.w, cfg->crop.h); + len = dump_printf(buff, buff_len, len, " dst: (%d,%d) %dx%d\n", + cfg->win.x, cfg->win.y, cfg->win.w, cfg->win.h); + len = dump_printf(buff, buff_len, len, " ix: %d\n", cfg->ix); + len = dump_printf(buff, buff_len, len, " zorder: %d\n\n", cfg->zorder); + + } +} + + +static int omap4_hwc_device_close(hw_device_t* device) +{ + omap4_hwc_device_t *hwc_dev = (omap4_hwc_device_t *) device;; + + if (hwc_dev) + free(hwc_dev); + + return 0; +} + +static int omap4_hwc_open_fb_hal(IMG_framebuffer_device_public_t **fb_dev) +{ + IMG_gralloc_module_public_t *psGrallocModule; + int err; + + err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t**)&psGrallocModule); + if(err) + goto err_out; + + if(strcmp(psGrallocModule->base.common.author, + "Imagination Technologies")) + { + err = -EINVAL; + goto err_out; + } + + *fb_dev = psGrallocModule->psFrameBufferDevice; + + return 0; + +err_out: + LOGE("Composer HAL failed to load compatible Graphics HAL"); + return err; +} + +static int omap4_hwc_device_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + omap4_hwc_module_t *hwc_mod = (omap4_hwc_module_t *)module; + omap4_hwc_device_t *hwc_dev; + int err; + + if (strcmp(name, HWC_HARDWARE_COMPOSER)) { + return -EINVAL; + } + + if (!hwc_mod->fb_dev) { + err = omap4_hwc_open_fb_hal(&hwc_mod->fb_dev); + if (err) + return err; + + if (!hwc_mod->fb_dev) { + LOGE("Framebuffer HAL not opened before HWC"); + return -EFAULT; + } + hwc_mod->fb_dev->bBypassPost = 1; + } + + hwc_dev = (omap4_hwc_device_t *)malloc(sizeof(*hwc_dev)); + if (hwc_dev == NULL) + return -ENOMEM; + + memset(hwc_dev, 0, sizeof(*hwc_dev)); + + hwc_dev->base.common.tag = HARDWARE_DEVICE_TAG; + hwc_dev->base.common.version = HWC_API_VERSION; + hwc_dev->base.common.module = (hw_module_t *)module; + hwc_dev->base.common.close = omap4_hwc_device_close; + hwc_dev->base.prepare = omap4_hwc_prepare; + hwc_dev->base.set = omap4_hwc_set; + hwc_dev->base.dump = omap4_hwc_dump; + hwc_dev->fb_dev = hwc_mod->fb_dev; + *device = &hwc_dev->base.common; + + hwc_dev->buffers = malloc(sizeof(buffer_handle_t) * MAX_HW_OVERLAYS); + if (!hwc_dev->buffers) { + free(hwc_dev); + return -ENOMEM; + } + + /* get debug properties */ + + /* see if hwc is enabled at all */ + char value[PROPERTY_VALUE_MAX]; + property_get("debug.hwc.rgb_order", value, "1"); + hwc_dev->flags_rgb_order = atoi(value); + property_get("debug.hwc.nv12_only", value, "0"); + hwc_dev->flags_nv12_only = atoi(value); + LOGE("omap4_hwc_device_open(rgb_order=%d nv12_only=%d)", + hwc_dev->flags_rgb_order, hwc_dev->flags_nv12_only); + + return 0; +} + +static struct hw_module_methods_t omap4_hwc_module_methods = { + .open = omap4_hwc_device_open, +}; + +omap4_hwc_module_t HAL_MODULE_INFO_SYM = { + .base = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = HWC_HARDWARE_MODULE_ID, + .name = "OMAP 44xx Hardware Composer HAL", + .author = "Texas Instruments", + .methods = &omap4_hwc_module_methods, + }, + }, +}; diff --git a/ion/Android.mk b/ion/Android.mk new file mode 100644 index 0000000..c9bf668 --- /dev/null +++ b/ion/Android.mk @@ -0,0 +1,20 @@ +# only include if running on an omap4 platform +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := ion.c +LOCAL_MODULE := libion +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := liblog +include $(BUILD_HEAPTRACKED_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := ion.c ion_test.c +LOCAL_MODULE := iontest +LOCAL_MODULE_TAGS := optional tests +LOCAL_SHARED_LIBRARIES := liblog +include $(BUILD_HEAPTRACKED_EXECUTABLE) + +endif diff --git a/ion/ion.c b/ion/ion.c new file mode 100644 index 0000000..08e4570 --- /dev/null +++ b/ion/ion.c @@ -0,0 +1,156 @@ +/* + * ion.c + * + * Memory Allocator functions for ion + * + * Copyright 2011 Google, Inc + * + * 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. + */ +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> + +#define LOG_TAG "ion" +#include <cutils/log.h> + +#include <linux/ion.h> +#include <linux/omap_ion.h> +#include "ion.h" + +int ion_open() +{ + int fd = open("/dev/ion", O_RDWR); + if (fd < 0) + LOGE("open /dev/ion failed!\n"); + return fd; +} + +int ion_close(int fd) +{ + return close(fd); +} + +int ion_ioctl(int fd, int req, void *arg) +{ + int ret = ioctl(fd, req, arg); + if (ret < 0) { + LOGE("ioctl %d failed with code %d: %s\n", req, + ret, strerror(errno)); + return -errno; + } + return ret; +} + +int ion_alloc(int fd, size_t len, size_t align, unsigned int flags, + struct ion_handle **handle) +{ + int ret; + struct ion_allocation_data data = { + .len = len, + .align = align, + .flags = flags, + }; + + ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); + if (ret < 0) + return ret; + *handle = data.handle; + return ret; +} + +int ion_alloc_tiler(int fd, size_t w, size_t h, int fmt, unsigned int flags, + struct ion_handle **handle, size_t *stride) +{ + int ret; + struct omap_ion_tiler_alloc_data alloc_data = { + .w = w, + .h = h, + .fmt = fmt, + .flags = flags, + }; + + struct ion_custom_data custom_data = { + .cmd = OMAP_ION_TILER_ALLOC, + .arg = (unsigned long)(&alloc_data), + }; + + ret = ion_ioctl(fd, ION_IOC_CUSTOM, &custom_data); + if (ret < 0) + return ret; + *stride = alloc_data.stride; + *handle = alloc_data.handle; + return ret; +} + +int ion_free(int fd, struct ion_handle *handle) +{ + struct ion_handle_data data = { + .handle = handle, + }; + return ion_ioctl(fd, ION_IOC_FREE, &data); +} + +int ion_map(int fd, struct ion_handle *handle, size_t length, int prot, + int flags, off_t offset, unsigned char **ptr, int *map_fd) +{ + struct ion_fd_data data = { + .handle = handle, + }; + int ret = ion_ioctl(fd, ION_IOC_MAP, &data); + if (ret < 0) + return ret; + *map_fd = data.fd; + if (*map_fd < 0) { + LOGE("map ioctl returned negative fd\n"); + return -EINVAL; + } + *ptr = mmap(NULL, length, prot, flags, *map_fd, offset); + if (*ptr == MAP_FAILED) { + LOGE("mmap failed: %s\n", strerror(errno)); + return -errno; + } + return ret; +} + +int ion_share(int fd, struct ion_handle *handle, int *share_fd) +{ + int map_fd; + struct ion_fd_data data = { + .handle = handle, + }; + int ret = ion_ioctl(fd, ION_IOC_SHARE, &data); + if (ret < 0) + return ret; + *share_fd = data.fd; + if (*share_fd < 0) { + LOGE("map ioctl returned negative fd\n"); + return -EINVAL; + } + return ret; +} + +int ion_import(int fd, int share_fd, struct ion_handle **handle) +{ + struct ion_fd_data data = { + .fd = share_fd, + }; + int ret = ion_ioctl(fd, ION_IOC_IMPORT, &data); + if (ret < 0) + return ret; + *handle = data.handle; + return ret; +} diff --git a/ion/ion.h b/ion/ion.h new file mode 100644 index 0000000..871b9bc --- /dev/null +++ b/ion/ion.h @@ -0,0 +1,35 @@ +/* + * ion.c + * + * Memory Allocator functions for ion + * + * Copyright 2011 Google, Inc + * + * 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. + */ + +#include <linux/ion.h> +#include <linux/omap_ion.h> + +int ion_open(); +int ion_close(int fd); +int ion_alloc(int fd, size_t len, size_t align, unsigned int flags, + struct ion_handle **handle); +int ion_alloc_tiler(int fd, size_t w, size_t h, int fmt, unsigned int flags, + struct ion_handle **handle, size_t *stride); +int ion_free(int fd, struct ion_handle *handle); +int ion_map(int fd, struct ion_handle *handle, size_t length, int prot, + int flags, off_t offset, unsigned char **ptr, int *map_fd); +int ion_share(int fd, struct ion_handle *handle, int *share_fd); +int ion_import(int fd, int share_fd, struct ion_handle **handle); + diff --git a/ion/ion_test.c b/ion/ion_test.c new file mode 100644 index 0000000..734caca --- /dev/null +++ b/ion/ion_test.c @@ -0,0 +1,321 @@ +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "ion.h" +#include <linux/ion.h> +#include <linux/omap_ion.h> + +size_t len = 1024*1024, align = 0; +int prot = PROT_READ | PROT_WRITE; +int map_flags = MAP_SHARED; +int alloc_flags = 0; +int test = -1; +size_t width = 1024*1024, height = 1024*1024; +int fmt = TILER_PIXEL_FMT_32BIT; +int tiler_test = 0; +size_t stride; + +int _ion_alloc_test(int *fd, struct ion_handle **handle) +{ + int ret; + + *fd = ion_open(); + if (*fd < 0) + return *fd; + + if (tiler_test) + ret = ion_alloc_tiler(*fd, width, height, fmt, alloc_flags, + handle, &stride); + else + ret = ion_alloc(*fd, len, align, alloc_flags, handle); + + if (ret) + printf("%s failed: %s\n", __func__, strerror(ret)); + return ret; +} + +void ion_alloc_test() +{ + int fd, ret; + struct ion_handle *handle; + + if(_ion_alloc_test(&fd, &handle)) + return; + + ret = ion_free(fd, handle); + if (ret) { + printf("%s failed: %s %p\n", __func__, strerror(ret), handle); + return; + } + ion_close(fd); + printf("ion alloc test: passed\n"); +} + +void _ion_tiler_map_test(unsigned char *ptr) +{ + size_t row, col; + + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) { + int i = (row * stride) + col; + ptr[i] = (unsigned char)i; + } + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) { + int i = (row * stride) + col; + if (ptr[i] != (unsigned char)i) + printf("%s failed wrote %d read %d from mapped " + "memory\n", __func__, i, ptr[i]); + } +} + + +void ion_map_test() +{ + int fd, map_fd, ret; + size_t i; + struct ion_handle *handle; + unsigned char *ptr; + + if(_ion_alloc_test(&fd, &handle)) + return; + + if (tiler_test) + len = height * stride; + ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd); + if (ret) + return; + + if (tiler_test) + _ion_tiler_map_test(ptr); + else { + for (i = 0; i < len; i++) { + ptr[i] = (unsigned char)i; + } + for (i = 0; i < len; i++) + if (ptr[i] != (unsigned char)i) + printf("%s failed wrote %d read %d from mapped " + "memory\n", __func__, i, ptr[i]); + } + /* clean up properly */ + ret = ion_free(fd, handle); + ion_close(fd); + munmap(ptr, len); + close(map_fd); + + _ion_alloc_test(&fd, &handle); + close(fd); + +#if 0 + munmap(ptr, len); + close(map_fd); + ion_close(fd); + + _ion_alloc_test(len, align, flags, &fd, &handle); + close(map_fd); + ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd); + /* don't clean up */ +#endif +} + +void ion_share_test() + +{ + struct ion_handle *handle; + int sd[2]; + int num_fd = 1; + struct iovec count_vec = { + .iov_base = &num_fd, + .iov_len = sizeof num_fd, + }; + char buf[CMSG_SPACE(sizeof(int))]; + socketpair(AF_UNIX, SOCK_STREAM, 0, sd); + if (fork()) { + struct msghdr msg = { + .msg_control = buf, + .msg_controllen = sizeof buf, + .msg_iov = &count_vec, + .msg_iovlen = 1, + }; + + struct cmsghdr *cmsg; + int fd, share_fd, ret; + char *ptr; + /* parent */ + if(_ion_alloc_test(&fd, &handle)) + return; + ret = ion_share(fd, handle, &share_fd); + if (ret) + printf("share failed %s\n", strerror(errno)); + ptr = mmap(NULL, len, prot, map_flags, share_fd, 0); + if (ptr == MAP_FAILED) { + return; + } + strcpy(ptr, "master"); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + *(int *)CMSG_DATA(cmsg) = share_fd; + /* send the fd */ + printf("master? [%10s] should be [master]\n", ptr); + printf("master sending msg 1\n"); + sendmsg(sd[0], &msg, 0); + if (recvmsg(sd[0], &msg, 0) < 0) + perror("master recv msg 2"); + printf("master? [%10s] should be [child]\n", ptr); + + /* send ping */ + sendmsg(sd[0], &msg, 0); + printf("master->master? [%10s]\n", ptr); + if (recvmsg(sd[0], &msg, 0) < 0) + perror("master recv 1"); + } else { + struct msghdr msg; + struct cmsghdr *cmsg; + char* ptr; + int fd, recv_fd; + char* child_buf[100]; + /* child */ + struct iovec count_vec = { + .iov_base = child_buf, + .iov_len = sizeof child_buf, + }; + + struct msghdr child_msg = { + .msg_control = buf, + .msg_controllen = sizeof buf, + .msg_iov = &count_vec, + .msg_iovlen = 1, + }; + + if (recvmsg(sd[1], &child_msg, 0) < 0) + perror("child recv msg 1"); + cmsg = CMSG_FIRSTHDR(&child_msg); + if (cmsg == NULL) { + printf("no cmsg rcvd in child"); + return; + } + recv_fd = *(int*)CMSG_DATA(cmsg); + if (recv_fd < 0) { + printf("could not get recv_fd from socket"); + return; + } + printf("child %d\n", recv_fd); + fd = ion_open(); + ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0); + if (ptr == MAP_FAILED) { + return; + } + printf("child? [%10s] should be [master]\n", ptr); + strcpy(ptr, "child"); + printf("child sending msg 2\n"); + sendmsg(sd[1], &child_msg, 0); + } +} + +int main(int argc, char* argv[]) { + int c; + enum tests { + ALLOC_TEST = 0, MAP_TEST, SHARE_TEST, + }; + + while (1) { + static struct option opts[] = { + {"alloc", no_argument, 0, 'a'}, + {"alloc_flags", required_argument, 0, 'f'}, + {"map", no_argument, 0, 'm'}, + {"share", no_argument, 0, 's'}, + {"len", required_argument, 0, 'l'}, + {"align", required_argument, 0, 'g'}, + {"map_flags", required_argument, 0, 'z'}, + {"prot", required_argument, 0, 'p'}, + {"alloc_tiler", no_argument, 0, 't'}, + {"width", required_argument, 0, 'w'}, + {"height", required_argument, 0, 'h'}, + {"fmt", required_argument, 0, 'r'}, + }; + int i = 0; + c = getopt_long(argc, argv, "af:h:l:mr:stw:", opts, &i); + if (c == -1) + break; + + switch (c) { + case 'l': + len = atol(optarg); + break; + case 'g': + align = atol(optarg); + break; + case 'z': + map_flags = 0; + map_flags |= strstr(optarg, "PROT_EXEC") ? + PROT_EXEC : 0; + map_flags |= strstr(optarg, "PROT_READ") ? + PROT_READ: 0; + map_flags |= strstr(optarg, "PROT_WRITE") ? + PROT_WRITE: 0; + map_flags |= strstr(optarg, "PROT_NONE") ? + PROT_NONE: 0; + break; + case 'p': + prot = 0; + prot |= strstr(optarg, "MAP_PRIVATE") ? + MAP_PRIVATE : 0; + prot |= strstr(optarg, "MAP_SHARED") ? + MAP_PRIVATE : 0; + break; + case 'f': + alloc_flags = atol(optarg); + break; + case 'a': + test = ALLOC_TEST; + break; + case 'm': + test = MAP_TEST; + break; + case 'r': + fmt = atol(optarg); + break; + case 's': + test = SHARE_TEST; + break; + case 'w': + width = atol(optarg); + break; + case 'h': + height = atol(optarg); + break; + case 't': + tiler_test = 1; + break; + } + } + printf("test %d, len %u, width %u, height %u fmt %u align %u, " + "map_flags %d, prot %d, alloc_flags %d\n", test, len, width, + height, fmt, align, map_flags, prot, alloc_flags); + switch (test) { + case ALLOC_TEST: + ion_alloc_test(); + break; + case MAP_TEST: + ion_map_test(); + break; + case SHARE_TEST: + ion_share_test(); + break; + default: + printf("must specify a test (alloc, map, share)\n"); + } + return 0; +} diff --git a/libstagefrighthw/Android.mk b/libstagefrighthw/Android.mk new file mode 100644 index 0000000..c1757f2 --- /dev/null +++ b/libstagefrighthw/Android.mk @@ -0,0 +1,23 @@ +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + TIOMXPlugin.cpp + +LOCAL_C_INCLUDES:= \ + $(TOP)/frameworks/base/include/media/stagefright/openmax + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libutils \ + libcutils \ + libui \ + libdl \ + +LOCAL_MODULE := libstagefrighthw + +include $(BUILD_HEAPTRACKED_SHARED_LIBRARY) + +endif diff --git a/libstagefrighthw/TIOMXPlugin.cpp b/libstagefrighthw/TIOMXPlugin.cpp new file mode 100644 index 0000000..14c5e91 --- /dev/null +++ b/libstagefrighthw/TIOMXPlugin.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TIOMXPlugin.h" + +#include <dlfcn.h> + +#include <media/stagefright/HardwareAPI.h> +#include <media/stagefright/MediaDebug.h> + +namespace android { + +extern "C" OMXPluginBase *createOMXPlugin() { + return new TIOMXPlugin; +} + +extern "C" void destroyOMXPlugin(OMXPluginBase *plugin) { + delete plugin; +} + +#define LIBOMX "libOMX_Core.so" + +TIOMXPlugin::TIOMXPlugin() + : mLibHandle(dlopen(LIBOMX, RTLD_NOW)), + mInit(NULL), + mDeinit(NULL), + mComponentNameEnum(NULL), + mGetHandle(NULL), + mFreeHandle(NULL), + mGetRolesOfComponentHandle(NULL) { + if (mLibHandle != NULL) { + mInit = (InitFunc)dlsym(mLibHandle, "TIOMX_Init"); + mDeinit = (DeinitFunc)dlsym(mLibHandle, "TIOMX_DeInit"); + + mComponentNameEnum = + (ComponentNameEnumFunc)dlsym(mLibHandle, "TIOMX_ComponentNameEnum"); + + mGetHandle = (GetHandleFunc)dlsym(mLibHandle, "TIOMX_GetHandle"); + mFreeHandle = (FreeHandleFunc)dlsym(mLibHandle, "TIOMX_FreeHandle"); + + mGetRolesOfComponentHandle = + (GetRolesOfComponentFunc)dlsym( + mLibHandle, "TIOMX_GetRolesOfComponent"); + + (*mInit)(); + } + else + LOGE("%s: failed to load %s", __func__, LIBOMX); +} + +TIOMXPlugin::~TIOMXPlugin() { + if (mLibHandle != NULL) { + (*mDeinit)(); + + dlclose(mLibHandle); + mLibHandle = NULL; + } +} + +OMX_ERRORTYPE TIOMXPlugin::makeComponentInstance( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) { + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + return (*mGetHandle)( + reinterpret_cast<OMX_HANDLETYPE *>(component), + const_cast<char *>(name), + appData, const_cast<OMX_CALLBACKTYPE *>(callbacks)); +} + +OMX_ERRORTYPE TIOMXPlugin::destroyComponentInstance( + OMX_COMPONENTTYPE *component) { + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + return (*mFreeHandle)(reinterpret_cast<OMX_HANDLETYPE *>(component)); +} + +OMX_ERRORTYPE TIOMXPlugin::enumerateComponents( + OMX_STRING name, + size_t size, + OMX_U32 index) { + if (mLibHandle == NULL) { + LOGE("mLibHandle is NULL!"); + return OMX_ErrorUndefined; + } + + return (*mComponentNameEnum)(name, size, index); +} + +OMX_ERRORTYPE TIOMXPlugin::getRolesOfComponent( + const char *name, + Vector<String8> *roles) { + roles->clear(); + + if (mLibHandle == NULL) { + return OMX_ErrorUndefined; + } + + OMX_U32 numRoles; + OMX_ERRORTYPE err = (*mGetRolesOfComponentHandle)( + const_cast<OMX_STRING>(name), &numRoles, NULL); + + if (err != OMX_ErrorNone) { + return err; + } + + if (numRoles > 0) { + OMX_U8 **array = new OMX_U8 *[numRoles]; + for (OMX_U32 i = 0; i < numRoles; ++i) { + array[i] = new OMX_U8[OMX_MAX_STRINGNAME_SIZE]; + } + + err = (*mGetRolesOfComponentHandle)( + const_cast<OMX_STRING>(name), &numRoles, array); + + CHECK_EQ(err, OMX_ErrorNone); + + for (OMX_U32 i = 0; i < numRoles; ++i) { + String8 s((const char *)array[i]); + roles->push(s); + + delete[] array[i]; + array[i] = NULL; + } + + delete[] array; + array = NULL; + } + + return OMX_ErrorNone; +} + +} // namespace android diff --git a/libstagefrighthw/TIOMXPlugin.h b/libstagefrighthw/TIOMXPlugin.h new file mode 100644 index 0000000..668c5ef --- /dev/null +++ b/libstagefrighthw/TIOMXPlugin.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TI_OMX_PLUGIN_H_ + +#define TI_OMX_PLUGIN_H_ + +#include <media/stagefright/OMXPluginBase.h> + +namespace android { + +struct TIOMXPlugin : public OMXPluginBase { + TIOMXPlugin(); + virtual ~TIOMXPlugin(); + + virtual OMX_ERRORTYPE makeComponentInstance( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + + virtual OMX_ERRORTYPE destroyComponentInstance( + OMX_COMPONENTTYPE *component); + + virtual OMX_ERRORTYPE enumerateComponents( + OMX_STRING name, + size_t size, + OMX_U32 index); + + virtual OMX_ERRORTYPE getRolesOfComponent( + const char *name, + Vector<String8> *roles); + +private: + void *mLibHandle; + + typedef OMX_ERRORTYPE (*InitFunc)(); + typedef OMX_ERRORTYPE (*DeinitFunc)(); + typedef OMX_ERRORTYPE (*ComponentNameEnumFunc)( + OMX_STRING, OMX_U32, OMX_U32); + + typedef OMX_ERRORTYPE (*GetHandleFunc)( + OMX_HANDLETYPE *, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE *); + + typedef OMX_ERRORTYPE (*FreeHandleFunc)(OMX_HANDLETYPE *); + + typedef OMX_ERRORTYPE (*GetRolesOfComponentFunc)( + OMX_STRING, OMX_U32 *, OMX_U8 **); + + InitFunc mInit; + DeinitFunc mDeinit; + ComponentNameEnumFunc mComponentNameEnum; + GetHandleFunc mGetHandle; + FreeHandleFunc mFreeHandle; + GetRolesOfComponentFunc mGetRolesOfComponentHandle; + + TIOMXPlugin(const TIOMXPlugin &); + TIOMXPlugin &operator=(const TIOMXPlugin &); +}; + +} // namespace android + +#endif // TI_OMX_PLUGIN_H_ diff --git a/libtiutils/Android.mk b/libtiutils/Android.mk new file mode 100755 index 0000000..7312222 --- /dev/null +++ b/libtiutils/Android.mk @@ -0,0 +1,35 @@ +################################################ + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_PRELINK_MODULE := false + +LOCAL_SRC_FILES:= \ + MessageQueue.cpp \ + Semaphore.cpp \ + ErrorUtils.cpp + +LOCAL_SHARED_LIBRARIES:= \ + libdl \ + libui \ + libbinder \ + libutils \ + libcutils + +LOCAL_C_INCLUDES += \ + kernel/android-2.6.29/include \ + frameworks/base/include/utils \ + bionic/libc/include \ + hardware/ti/omap4xxx/domx/omx_core/inc \ + hardware/ti/omap4xxx/domx/mm_osal/inc + +LOCAL_CFLAGS += -fno-short-enums + +# LOCAL_CFLAGS += + +LOCAL_MODULE:= libtiutils +LOCAL_MODULE_TAGS:= optional + +include $(BUILD_HEAPTRACKED_SHARED_LIBRARY) diff --git a/libtiutils/DebugUtils.h b/libtiutils/DebugUtils.h new file mode 100644 index 0000000..54edfc7 --- /dev/null +++ b/libtiutils/DebugUtils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef DEBUG_UTILS_H +#define DEBUG_UTILS_H + +///Defines for debug statements - Macro LOG_TAG needs to be defined in the respective files +#define DBGUTILS_LOGVA(str) LOGV("%s:%d %s - " str,__FILE__, __LINE__,__FUNCTION__); +#define DBGUTILS_LOGVB(str,...) LOGV("%s:%d %s - " str,__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); +#define DBGUTILS_LOGDA(str) LOGD("%s:%d %s - " str,__FILE__, __LINE__,__FUNCTION__); +#define DBGUTILS_LOGDB(str, ...) LOGD("%s:%d %s - " str,__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); +#define DBGUTILS_LOGEA(str) LOGE("%s:%d %s - " str,__FILE__, __LINE__, __FUNCTION__); +#define DBGUTILS_LOGEB(str, ...) LOGE("%s:%d %s - " str,__FILE__, __LINE__,__FUNCTION__, __VA_ARGS__); +#define LOG_FUNCTION_NAME LOGV("%d: %s() ENTER", __LINE__, __FUNCTION__); +#define LOG_FUNCTION_NAME_EXIT LOGV("%d: %s() EXIT", __LINE__, __FUNCTION__); + + + + +#endif //DEBUG_UTILS_H + diff --git a/libtiutils/ErrorUtils.cpp b/libtiutils/ErrorUtils.cpp new file mode 100644 index 0000000..df0e51c --- /dev/null +++ b/libtiutils/ErrorUtils.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + +#include "ErrorUtils.h" + +namespace android { + +/** + @brief Method to convert from POSIX to Android errors + + @param error Any of the standard POSIX error codes (defined in bionic/libc/kernel/common/asm-generic/errno.h) + @return Any of the standard Android error code (defined in frameworks/base/include/utils/Errors.h) + */ +status_t ErrorUtils::posixToAndroidError(int error) +{ + switch(error) + { + case 0: + return NO_ERROR; + case EINVAL: + case EFBIG: + case EMSGSIZE: + case E2BIG: + case EFAULT: + case EILSEQ: + return BAD_VALUE; + case ENOSYS: + return INVALID_OPERATION; + case EACCES: + case EPERM: + return PERMISSION_DENIED; + case EADDRINUSE: + case EAGAIN: + case EALREADY: + case EBUSY: + case EEXIST: + case EINPROGRESS: + return ALREADY_EXISTS; + case ENOMEM: + return NO_MEMORY; + default: + return UNKNOWN_ERROR; + }; + + return NO_ERROR; +} + + +/** + @brief Method to convert from TI OSAL to Android errors + + @param error Any of the standard TI OSAL error codes (defined in + hardware/ti/omx/ducati/domx/system/mm_osal/inc/timm_osal_error.h) + @return Any of the standard Android error code (defined in frameworks/base/include/utils/Errors.h) + */ +status_t ErrorUtils::osalToAndroidError(TIMM_OSAL_ERRORTYPE error) +{ + switch(error) + { + case TIMM_OSAL_ERR_NONE: + return NO_ERROR; + case TIMM_OSAL_ERR_ALLOC: + return NO_MEMORY; + default: + return UNKNOWN_ERROR; + } + + return NO_ERROR; +} + +/** + @brief Method to convert from OMX to Android errors + + @param error Any of the standard OMX error codes (defined in hardware/ti/omx/ducati/domx/system/omx_core/inc/OMX_Core.h) + @return Any of the standard Android error code (defined in frameworks/base/include/utils/Errors.h) + */ +status_t ErrorUtils::omxToAndroidError(OMX_ERRORTYPE error) +{ + switch(error) + { + case OMX_ErrorNone: + return NO_ERROR; + case OMX_ErrorBadParameter: + case OMX_ErrorInvalidComponentName: + case OMX_ErrorUndefined: + case OMX_ErrorInvalidState: + case OMX_ErrorStreamCorrupt: + case OMX_ErrorPortsNotCompatible: + case OMX_ErrorVersionMismatch: + case OMX_ErrorMbErrorsInFrame: + return BAD_VALUE; + case OMX_ErrorInsufficientResources: + return NO_MEMORY; + case OMX_ErrorComponentNotFound: + case OMX_ErrorNotImplemented: + case OMX_ErrorFormatNotDetected: + case OMX_ErrorUnsupportedSetting: + return NAME_NOT_FOUND; + case OMX_ErrorUnderflow: + case OMX_ErrorOverflow: + case OMX_ErrorUnsupportedIndex: + case OMX_ErrorBadPortIndex: + return BAD_INDEX; + case OMX_ErrorHardware: + case OMX_ErrorContentPipeCreationFailed: + case OMX_ErrorContentPipeOpenFailed: + return FAILED_TRANSACTION; + case OMX_ErrorTimeout: + return TIMED_OUT; + case OMX_ErrorSameState: + case OMX_ErrorIncorrectStateTransition: + case OMX_ErrorIncorrectStateOperation: + return PERMISSION_DENIED; + case OMX_ErrorTunnelingUnsupported: + return INVALID_OPERATION; + default: + return UNKNOWN_ERROR; + } + + return NO_ERROR; +} + + +}; + + + diff --git a/libtiutils/ErrorUtils.h b/libtiutils/ErrorUtils.h new file mode 100644 index 0000000..24dd806 --- /dev/null +++ b/libtiutils/ErrorUtils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ERROR_UTILS_H +#define ERROR_UTILS_H + +///Header file where all the android error codes are defined +#include <Errors.h> + +///Header file where all the OMX error codes are defined +#include "OMX_Core.h" + + +extern "C" +{ +///Header file where all the TI OSAL error codes are defined +#include "timm_osal_error.h" +}; + +namespace android { + +///Generic class with static methods to convert any standard error type to Android error type +class ErrorUtils +{ +public: + ///Method to convert from POSIX to Android errors + static status_t posixToAndroidError(int error); + + ///Method to convert from TI OSAL to Android errors + static status_t osalToAndroidError(TIMM_OSAL_ERRORTYPE error); + + ///Method to convert from OMX to Android errors + static status_t omxToAndroidError(OMX_ERRORTYPE error); + +}; + +}; + +#endif /// ERROR_UTILS_H diff --git a/libtiutils/MessageQueue.cpp b/libtiutils/MessageQueue.cpp new file mode 100755 index 0000000..1a5942a --- /dev/null +++ b/libtiutils/MessageQueue.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/poll.h> +#include <unistd.h> +#include <Errors.h> + + + +#define LOG_TAG "MessageQueue" +#include <utils/Log.h> + +#include "MessageQueue.h" + +namespace TIUTILS { + +/** + @brief Constructor for the message queue class + + @param none + @return none + */ +MessageQueue::MessageQueue() +{ + LOG_FUNCTION_NAME; + + int fds[2] = {-1,-1}; + android::status_t stat; + + stat = pipe(fds); + + if ( 0 > stat ) + { + MSGQ_LOGEB("Error while openning pipe: %s", strerror(stat) ); + this->fd_read = 0; + this->fd_write = 0; + mHasMsg = false; + } + else + { + this->fd_read = fds[0]; + this->fd_write = fds[1]; + + mHasMsg = false; + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Destructor for the semaphore class + + @param none + @return none + */ +MessageQueue::~MessageQueue() +{ + LOG_FUNCTION_NAME; + + if(this->fd_read) + { + close(this->fd_read); + } + + if(this->fd_write) + { + close(this->fd_write); + } + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Get a message from the queue + + @param msg Message structure to hold the message to be retrieved + @return android::NO_ERROR On success + @return android::BAD_VALUE if the message pointer is NULL + @return android::NO_INIT If the file read descriptor is not set + @return android::UNKNOWN_ERROR if the read operation fromthe file read descriptor fails + */ +android::status_t MessageQueue::get(Message* msg) +{ + LOG_FUNCTION_NAME; + + if(!msg) + { + MSGQ_LOGEA("msg is NULL"); + LOG_FUNCTION_NAME_EXIT; + return android::BAD_VALUE; + } + + if(!this->fd_read) + { + MSGQ_LOGEA("read descriptor not initialized for message queue"); + LOG_FUNCTION_NAME_EXIT; + return android::NO_INIT; + } + + char* p = (char*) msg; + size_t read_bytes = 0; + + while( read_bytes < sizeof(*msg) ) + { + int err = read(this->fd_read, p, sizeof(*msg) - read_bytes); + + if( err < 0 ) + { + MSGQ_LOGEB("read() error: %s", strerror(errno)); + return android::UNKNOWN_ERROR; + } + else + { + read_bytes += err; + } + } + + MSGQ_LOGDB("MQ.get(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4); + + mHasMsg = false; + + LOG_FUNCTION_NAME_EXIT; + + return 0; +} + +/** + @brief Get the input file descriptor of the message queue + + @param none + @return file read descriptor + */ + +int MessageQueue::getInFd() +{ + return this->fd_read; +} + +/** + @brief Constructor for the message queue class + + @param fd file read descriptor + @return none + */ + +void MessageQueue::setInFd(int fd) +{ + LOG_FUNCTION_NAME; + + if ( -1 != this->fd_read ) + { + close(this->fd_read); + } + + this->fd_read = fd; + + LOG_FUNCTION_NAME_EXIT; +} + +/** + @brief Queue a message + + @param msg Message structure to hold the message to be retrieved + @return android::NO_ERROR On success + @return android::BAD_VALUE if the message pointer is NULL + @return android::NO_INIT If the file write descriptor is not set + @return android::UNKNOWN_ERROR if the write operation fromthe file write descriptor fails + */ + +android::status_t MessageQueue::put(Message* msg) +{ + LOG_FUNCTION_NAME; + + char* p = (char*) msg; + size_t bytes = 0; + + if(!msg) + { + MSGQ_LOGEA("msg is NULL"); + LOG_FUNCTION_NAME_EXIT; + return android::BAD_VALUE; + } + + if(!this->fd_write) + { + MSGQ_LOGEA("write descriptor not initialized for message queue"); + LOG_FUNCTION_NAME_EXIT; + return android::NO_INIT; + } + + + MSGQ_LOGDB("MQ.put(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4); + + while( bytes < sizeof(msg) ) + { + int err = write(this->fd_write, p, sizeof(*msg) - bytes); + + if( err < 0 ) + { + MSGQ_LOGEB("write() error: %s", strerror(errno)); + LOG_FUNCTION_NAME_EXIT; + return android::UNKNOWN_ERROR; + } + else + { + bytes += err; + } + } + + MSGQ_LOGDA("MessageQueue::put EXIT"); + + LOG_FUNCTION_NAME_EXIT; + return 0; +} + + +/** + @brief Returns if the message queue is empty or not + + @param none + @return true If the queue is empty + @return false If the queue has at least one message + */ +bool MessageQueue::isEmpty() +{ + LOG_FUNCTION_NAME; + + struct pollfd pfd; + + pfd.fd = this->fd_read; + pfd.events = POLLIN; + pfd.revents = 0; + + if(!this->fd_read) + { + MSGQ_LOGEA("read descriptor not initialized for message queue"); + LOG_FUNCTION_NAME_EXIT; + return android::NO_INIT; + } + + + if( -1 == poll(&pfd,1,0) ) + { + MSGQ_LOGEB("poll() error: %s", strerror(errno)); + LOG_FUNCTION_NAME_EXIT; + return false; + } + + if(pfd.revents & POLLIN) + { + mHasMsg = true; + } + else + { + mHasMsg = false; + } + + LOG_FUNCTION_NAME_EXIT; + return !mHasMsg; +} + +/** + @brief Force whether the message queue has message or not + + @param hasMsg Whether the queue has a message or not + @return none + */ +void MessageQueue::setMsg(bool hasMsg) + { + mHasMsg = hasMsg; + } + + +/** + @briefWait for message in maximum three different queues with a timeout + + @param queue1 First queue. At least this should be set to a valid queue pointer + @param queue2 Second queue. Optional. + @param queue3 Third queue. Optional. + @param timeout The timeout value (in micro secs) to wait for a message in any of the queues + @return android::NO_ERROR On success + @return android::BAD_VALUE If queue1 is NULL + @return android::NO_INIT If the file read descriptor of any of the provided queues is not set + */ +android::status_t MessageQueue::waitForMsg(MessageQueue *queue1, MessageQueue *queue2, MessageQueue *queue3, int timeout) + { + LOG_FUNCTION_NAME; + + int n =1; + struct pollfd pfd[3]; + + if(!queue1) + { + MSGQ_LOGEA("queue1 pointer is NULL"); + LOG_FUNCTION_NAME_EXIT; + return android::BAD_VALUE; + } + + pfd[0].fd = queue1->getInFd(); + if(!pfd[0].fd) + { + MSGQ_LOGEA("read descriptor not initialized for message queue1"); + LOG_FUNCTION_NAME_EXIT; + return android::NO_INIT; + } + pfd[0].events = POLLIN; + pfd[0].revents = 0; + if(queue2) + { + MSGQ_LOGDA("queue2 not-null"); + pfd[1].fd = queue2->getInFd(); + if(!pfd[1].fd) + { + MSGQ_LOGEA("read descriptor not initialized for message queue2"); + LOG_FUNCTION_NAME_EXIT; + return android::NO_INIT; + } + + pfd[1].events = POLLIN; + pfd[1].revents = 0; + n++; + } + + if(queue3) + { + MSGQ_LOGDA("queue3 not-null"); + pfd[2].fd = queue3->getInFd(); + if(!pfd[2].fd) + { + MSGQ_LOGEA("read descriptor not initialized for message queue3"); + LOG_FUNCTION_NAME_EXIT; + return android::NO_INIT; + } + + pfd[2].events = POLLIN; + pfd[2].revents = 0; + n++; + } + + + int ret = poll(pfd, n, timeout); + if(ret==0) + { + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + if(ret<android::NO_ERROR) + { + MSGQ_LOGEB("Message queue returned error %d", ret); + LOG_FUNCTION_NAME_EXIT; + return ret; + } + + if (pfd[0].revents & POLLIN) + { + queue1->setMsg(true); + } + + if(queue2) + { + if (pfd[1].revents & POLLIN) + { + queue2->setMsg(true); + } + } + + if(queue3) + { + if (pfd[2].revents & POLLIN) + { + queue3->setMsg(true); + } + } + + LOG_FUNCTION_NAME_EXIT; + return ret; + } + +}; diff --git a/libtiutils/MessageQueue.h b/libtiutils/MessageQueue.h new file mode 100755 index 0000000..97e11a7 --- /dev/null +++ b/libtiutils/MessageQueue.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#ifndef __MESSAGEQUEUE_H__ +#define __MESSAGEQUEUE_H__ + +#include "DebugUtils.h" +#include <stdint.h> + +///Uncomment this macro to debug the message queue implementation +//#define DEBUG_LOG + +///Camera HAL Logging Functions +#ifndef DEBUG_LOG + +#define MSGQ_LOGDA(str) +#define MSGQ_LOGDB(str, ...) + +#undef LOG_FUNCTION_NAME +#undef LOG_FUNCTION_NAME_EXIT +#define LOG_FUNCTION_NAME +#define LOG_FUNCTION_NAME_EXIT + +#else + +#define MSGQ_LOGDA DBGUTILS_LOGDA +#define MSGQ_LOGDB DBGUTILS_LOGDB + +#endif + +#define MSGQ_LOGEA DBGUTILS_LOGEA +#define MSGQ_LOGEB DBGUTILS_LOGEB + + +namespace TIUTILS { + +///Message type +struct Message +{ + unsigned int command; + void* arg1; + void* arg2; + void* arg3; + void* arg4; + int64_t id; +}; + +///Message queue implementation +class MessageQueue +{ +public: + + MessageQueue(); + ~MessageQueue(); + + ///Get a message from the queue + android::status_t get(Message*); + + ///Get the input file descriptor of the message queue + int getInFd(); + + ///Set the input file descriptor for the message queue + void setInFd(int fd); + + ///Queue a message + android::status_t put(Message*); + + ///Returns if the message queue is empty or not + bool isEmpty(); + + ///Force whether the message queue has message or not + void setMsg(bool hasMsg=false); + + ///Wait for message in maximum three different queues with a timeout + static int waitForMsg(MessageQueue *queue1, MessageQueue *queue2=0, MessageQueue *queue3=0, int timeout = 0); + + bool hasMsg() + { + return mHasMsg; + } + +private: + int fd_read; + int fd_write; + bool mHasMsg; +}; + +}; + +#endif diff --git a/libtiutils/Semaphore.cpp b/libtiutils/Semaphore.cpp new file mode 100644 index 0000000..1f46dca --- /dev/null +++ b/libtiutils/Semaphore.cpp @@ -0,0 +1,226 @@ +/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * 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.
+ */
+
+
+
+#include "Semaphore.h"
+#include "ErrorUtils.h"
+#include <utils/Log.h>
+#include <time.h>
+
+namespace android {
+
+/**
+ @brief Constructor for the semaphore class
+
+ @param none
+ @return none
+ */
+Semaphore::Semaphore()
+{
+ ///Initialize the semaphore to NULL
+ mSemaphore = NULL;
+}
+
+/**
+ @brief Destructor of the semaphore class
+
+ @param none
+ @return none
+
+ */
+Semaphore::~Semaphore()
+{
+ Release();
+}
+
+/**
+ @brief: Releases semaphore
+
+ @param count >=0
+ @return NO_ERROR On Success
+ @return One of the android error codes based on semaphore de-initialization
+ */
+
+status_t Semaphore::Release()
+{
+ int status = 0;
+
+ ///Destroy only if the semaphore has been created
+ if(mSemaphore)
+ {
+ status = sem_destroy(mSemaphore);
+
+ free(mSemaphore);
+
+ mSemaphore = NULL;
+ }
+
+ ///Initialize the semaphore and return the status
+ return ErrorUtils::posixToAndroidError(status);
+
+}
+
+/**
+ @brief Create the semaphore with initial count value
+
+ @param count >=0
+ @return NO_ERROR On Success
+ @return NO_MEMORY If unable to allocate memory for the semaphore
+ @return BAD_VALUE If an invalid count value is passed (<0)
+ @return One of the android error codes based on semaphore initialization
+ */
+
+status_t Semaphore::Create(int count)
+{
+ status_t ret = NO_ERROR;
+
+ ///count cannot be less than zero
+ if(count<0)
+ {
+ return BAD_VALUE;
+ }
+
+ ret = Release();
+ if ( NO_ERROR != ret )
+ {
+ return ret;
+ }
+
+ ///allocate memory for the semaphore
+ mSemaphore = (sem_t*)malloc(sizeof(sem_t)) ;
+
+ ///if memory is unavailable, return error
+ if(!mSemaphore)
+ {
+ return NO_MEMORY;
+ }
+
+ ///Initialize the semaphore and return the status
+ return ErrorUtils::posixToAndroidError(sem_init(mSemaphore, 0x00, count));
+
+}
+
+/**
+ @brief Wait operation
+
+ @param none
+ @return BAD_VALUE if the semaphore is not initialized
+ @return NO_ERROR On success
+ @return One of the android error codes based on semaphore wait operation
+ */
+status_t Semaphore::Wait()
+{
+ ///semaphore should have been created first
+ if(!mSemaphore)
+ {
+ return BAD_VALUE;
+ }
+
+ ///Wait and return the status after signalling
+ return ErrorUtils::posixToAndroidError(sem_wait(mSemaphore));
+
+
+}
+
+
+/**
+ @brief Signal operation
+
+ @param none
+ @return BAD_VALUE if the semaphore is not initialized
+ @return NO_ERROR On success
+ @return One of the android error codes based on semaphore signal operation
+ */
+
+status_t Semaphore::Signal()
+{
+ ///semaphore should have been created first
+ if(!mSemaphore)
+ {
+ return BAD_VALUE;
+ }
+
+ ///Post to the semaphore
+ return ErrorUtils::posixToAndroidError(sem_post(mSemaphore));
+
+}
+
+/**
+ @brief Current semaphore count
+
+ @param none
+ @return Current count value of the semaphore
+ */
+int Semaphore::Count()
+{
+ int val;
+
+ ///semaphore should have been created first
+ if(!mSemaphore)
+ {
+ return BAD_VALUE;
+ }
+
+ ///get the value of the semaphore
+ sem_getvalue(mSemaphore, &val);
+
+ return val;
+}
+
+/**
+ @brief Wait operation with a timeout
+
+ @param timeoutMicroSecs The timeout period in micro seconds
+ @return BAD_VALUE if the semaphore is not initialized
+ @return NO_ERROR On success
+ @return One of the android error codes based on semaphore wait operation
+ */
+
+status_t Semaphore::WaitTimeout(int timeoutMicroSecs)
+{
+ status_t ret = NO_ERROR;
+
+ struct timespec timeSpec;
+ struct timeval currentTime;
+
+ ///semaphore should have been created first
+ if( NULL == mSemaphore)
+ {
+ ret = BAD_VALUE;
+ }
+
+ if ( NO_ERROR == ret )
+ {
+
+ ///setup the timeout values - timeout is specified in seconds and nanoseconds
+ gettimeofday(¤tTime, NULL);
+ timeSpec.tv_sec = currentTime.tv_sec;
+ timeSpec.tv_nsec = currentTime.tv_usec * 1000;
+ timeSpec.tv_sec += ( timeoutMicroSecs / 1000000 );
+ timeSpec.tv_nsec += ( timeoutMicroSecs % 1000000) * 1000;
+
+ ///Wait for the timeout or signal and return the result based on whichever event occurred first
+ ret = sem_timedwait(mSemaphore, &timeSpec);
+ }
+
+ return ret;
+}
+
+
+};
+
+
diff --git a/libtiutils/Semaphore.h b/libtiutils/Semaphore.h new file mode 100644 index 0000000..466e709 --- /dev/null +++ b/libtiutils/Semaphore.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * 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. + */ + + + +#include <Errors.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +namespace android { + +class Semaphore +{ +public: + + Semaphore(); + ~Semaphore(); + + //Release semaphore + status_t Release(); + + ///Create the semaphore with initial count value + status_t Create(int count=0); + + ///Wait operation + status_t Wait(); + + ///Signal operation + status_t Signal(); + + ///Current semaphore count + int Count(); + + ///Wait operation with a timeout + status_t WaitTimeout(int timeoutMicroSecs); + +private: + sem_t *mSemaphore; + +}; + +}; diff --git a/libyv12colorconvert/Android.mk b/libyv12colorconvert/Android.mk new file mode 100644 index 0000000..6f781f4 --- /dev/null +++ b/libyv12colorconvert/Android.mk @@ -0,0 +1,21 @@ +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + ColorConvert.cpp + +LOCAL_C_INCLUDES:= \ + $(TOP)/frameworks/base/include/media/stagefright/openmax \ + $(TOP)/frameworks/media/libvideoeditor/include + +LOCAL_SHARED_LIBRARIES := \ + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := libyv12colorconvert + +include $(BUILD_HEAPTRACKED_SHARED_LIBRARY) + +endif diff --git a/libyv12colorconvert/ColorConvert.cpp b/libyv12colorconvert/ColorConvert.cpp new file mode 100644 index 0000000..41dcbad --- /dev/null +++ b/libyv12colorconvert/ColorConvert.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "IYV12ColorConverter.h" +#include <OMX_IVCommon.h> +#include <string.h> + +static int getDecoderOutputFormat() { + return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar; +} + +static int convertDecoderOutputToYV12( + void* srcBits, int srcWidth, int srcHeight, ARect srcRect, void* dstBits) { + + const uint8_t *pSrc_y = (const uint8_t *)srcBits + + srcWidth * srcRect.top + srcRect.left; + const uint8_t *pSrc_uv = (const uint8_t *)pSrc_y + + srcWidth * (srcHeight - srcRect.top / 2); + + int dstWidth = srcRect.right - srcRect.left + 1; + int dstHeight = srcRect.bottom - srcRect.top + 1; + size_t dst_y_size = dstWidth * dstHeight; + size_t dst_uv_stride = dstWidth / 2; + size_t dst_uv_size = dstWidth / 2 * dstHeight / 2; + uint8_t *pDst_y = (uint8_t *)dstBits; + uint8_t *pDst_u = pDst_y + dst_y_size; + uint8_t *pDst_v = pDst_u + dst_uv_size; + + for (int y = 0; y < dstHeight; ++y) { + memcpy(pDst_y, pSrc_y, dstWidth); + pSrc_y += srcWidth; + pDst_y += dstWidth; + } + + size_t tmp = (dstWidth + 1) / 2; + for (int y = 0; y < (dstHeight + 1) / 2; ++y) { + for (size_t x = 0; x < tmp; ++x) { + pDst_u[x] = pSrc_uv[2 * x]; + pDst_v[x] = pSrc_uv[2 * x + 1]; + } + pSrc_uv += srcWidth; + pDst_u += dst_uv_stride; + pDst_v += dst_uv_stride; + } + return 0; +} + +static int getEncoderInputFormat() { + return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar; +} + +static int convertYV12ToEncoderInput( + void* srcBits, int srcWidth, int srcHeight, + int dstWidth, int dstHeight, ARect dstRect, + void* dstBits) { + uint8_t *pSrc_y = (uint8_t*) srcBits; + uint8_t *pDst_y = (uint8_t*) dstBits; + for(int i=0; i < srcHeight; i++) { + memcpy(pDst_y, pSrc_y, srcWidth); + pSrc_y += srcWidth; + pDst_y += dstWidth; + } + uint8_t* pSrc_u = (uint8_t*)srcBits + (srcWidth * srcHeight); + uint8_t* pSrc_v = (uint8_t*)pSrc_u + (srcWidth / 2) * (srcHeight / 2); + uint8_t* pDst_uv = (uint8_t*)dstBits + dstWidth * dstHeight; + + for(int i=0; i < srcHeight / 2; i++) { + for(int j=0, k=0; j < srcWidth / 2; j++, k+=2) { + pDst_uv[k] = pSrc_u[j]; + pDst_uv[k+1] = pSrc_v[j]; + } + pDst_uv += dstWidth; + pSrc_u += srcWidth / 2; + pSrc_v += srcWidth / 2; + } + return 0; +} + +static int getEncoderInputBufferInfo( + int actualWidth, int actualHeight, + int* encoderWidth, int* encoderHeight, + ARect* encoderRect, int* encoderBufferSize) { + + *encoderWidth = actualWidth; + *encoderHeight = actualHeight; + encoderRect->left = 0; + encoderRect->top = 0; + encoderRect->right = actualWidth - 1; + encoderRect->bottom = actualHeight - 1; + *encoderBufferSize = (actualWidth * actualHeight * 3 / 2); + + return 0; +} + +extern "C" void getYV12ColorConverter(IYV12ColorConverter *converter) { + converter->getDecoderOutputFormat = getDecoderOutputFormat; + converter->convertDecoderOutputToYV12 = convertDecoderOutputToYV12; + converter->getEncoderInputFormat = getEncoderInputFormat; + converter->convertYV12ToEncoderInput = convertYV12ToEncoderInput; + converter->getEncoderInputBufferInfo = getEncoderInputBufferInfo; +} diff --git a/mapinfo.c b/mapinfo.c new file mode 100644 index 0000000..7f4250f --- /dev/null +++ b/mapinfo.c @@ -0,0 +1,106 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "mapinfo.h" + +extern void *__real_malloc(size_t size); +extern void __real_free(void *ptr); + +#if 0 + while (p <= end) { + data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); + _LOG(tfd, (sp_depth > 2) || only_in_tombstone, + " %08x %08x %s\n", p, data, + map_to_name(map, data, "")); + p += 4; + } +#endif + +// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 + +static mapinfo *parse_maps_line(char *line) +{ + mapinfo *mi; + int len = strlen(line); + + if(len < 1) return 0; + line[--len] = 0; + + if(len < 50) return 0; + if(line[20] != 'x') return 0; + + mi = __real_malloc(sizeof(mapinfo) + (len - 47)); + if(mi == 0) return 0; + + mi->start = strtoul(line, 0, 16); + mi->end = strtoul(line + 9, 0, 16); + /* To be filled in parse_elf_info if the mapped section starts with + * elf_header + */ + mi->next = 0; + strcpy(mi->name, line + 49); + + return mi; +} + +mapinfo *init_mapinfo(int pid) +{ + struct mapinfo *milist = NULL; + char data[1024]; + sprintf(data, "/proc/%d/maps", pid); + FILE *fp = fopen(data, "r"); + if(fp) { + while(fgets(data, sizeof(data), fp)) { + mapinfo *mi = parse_maps_line(data); + if(mi) { + mi->next = milist; + milist = mi; + } + } + fclose(fp); + } + + return milist; +} + +void deinit_mapinfo(mapinfo *mi) +{ + mapinfo *del; + while(mi) { + del = mi; + mi = mi->next; + __real_free(del); + } +} + +/* Map a pc address to the name of the containing ELF file */ +const char *map_to_name(mapinfo *mi, unsigned pc, const char* def) +{ + while(mi) { + if((pc >= mi->start) && (pc < mi->end)){ + return mi->name; + } + mi = mi->next; + } + return def; +} + +/* Find the containing map info for the pc */ +const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc) +{ + *rel_pc = pc; + while(mi) { + if((pc >= mi->start) && (pc < mi->end)){ + // Only calculate the relative offset for shared libraries + if (strstr(mi->name, ".so")) { + *rel_pc -= mi->start; + } + return mi; + } + mi = mi->next; + } + return NULL; +} diff --git a/mapinfo.h b/mapinfo.h new file mode 100644 index 0000000..25adeb4 --- /dev/null +++ b/mapinfo.h @@ -0,0 +1,16 @@ +#ifndef MAPINFO_H +#define MAPINFO_H + +typedef struct mapinfo { + struct mapinfo *next; + unsigned start; + unsigned end; + char name[]; +} mapinfo; + +mapinfo *init_mapinfo(int pid); +void deinit_mapinfo(mapinfo *mi); +const char *map_to_name(mapinfo *mi, unsigned pc, const char* def); +const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc); + +#endif diff --git a/omap4.mk b/omap4.mk new file mode 100644 index 0000000..1d1a877 --- /dev/null +++ b/omap4.mk @@ -0,0 +1,33 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file lists the modules that are specific to OMAP4 but are used by +# all OMAP4 devices. + +PRODUCT_PACKAGES := \ + libdomx \ + libOMX_Core \ + libOMX.TI.DUCATI1.VIDEO.H264E \ + libOMX.TI.DUCATI1.VIDEO.DECODER \ + libOMX.TI.DUCATI1.VIDEO.CAMERA \ + libOMX.TI.DUCATI1.MISC.SAMPLE \ + libstagefrighthw \ + libyv12colorconvert \ + libtimemmgr \ + libtiutils \ + libcamera \ + libion \ + camera.omap4 \ + libomxcameraadapter \ + hwcomposer.omap4 diff --git a/stacktrace.c b/stacktrace.c new file mode 100644 index 0000000..1e79bfa --- /dev/null +++ b/stacktrace.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <unwind.h> +#include <sys/types.h> + +// ============================================================================= +// stack trace functions +// ============================================================================= + +typedef struct +{ + size_t count; + intptr_t* addrs; +} stack_crawl_state_t; + + +/* depends how the system includes define this */ +#ifdef HAVE_UNWIND_CONTEXT_STRUCT +typedef struct _Unwind_Context __unwind_context; +#else +typedef _Unwind_Context __unwind_context; +#endif + +static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg) +{ + stack_crawl_state_t* state = (stack_crawl_state_t*)arg; + if (state->count) { + intptr_t ip = (intptr_t)_Unwind_GetIP(context); + if (ip) { + state->addrs[0] = ip; + state->addrs++; + state->count--; + return _URC_NO_REASON; + } + } + /* + * If we run out of space to record the address or 0 has been seen, stop + * unwinding the stack. + */ + return _URC_END_OF_STACK; +} + +int heaptracker_stacktrace(intptr_t* addrs, size_t max_entries) +{ + stack_crawl_state_t state; + state.count = max_entries; + state.addrs = (intptr_t*)addrs; + _Unwind_Backtrace(trace_function, (void*)&state); + return max_entries - state.count; +} diff --git a/test/CameraHal/Android.mk b/test/CameraHal/Android.mk new file mode 100644 index 0000000..c7da48a --- /dev/null +++ b/test/CameraHal/Android.mk @@ -0,0 +1,38 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + camera_test_menu.cpp \ + camera_test_script.cpp + +LOCAL_SHARED_LIBRARIES:= \ + libdl \ + libui \ + libutils \ + libcutils \ + libbinder \ + libmedia \ + libui \ + libgui \ + libcamera_client + +LOCAL_C_INCLUDES += \ + frameworks/base/include/ui \ + frameworks/base/include/surfaceflinger \ + frameworks/base/include/camera \ + frameworks/base/include/media \ + $(PV_INCLUDES) + +LOCAL_MODULE:= camera_test +LOCAL_MODULE_TAGS:= tests + +LOCAL_CFLAGS += -Wall -fno-short-enums -O0 -g -D___ANDROID___ + +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + LOCAL_CFLAGS += -DTARGET_OMAP4 +endif + +include $(BUILD_HEAPTRACKED_EXECUTABLE) + + diff --git a/test/CameraHal/camera_test.h b/test/CameraHal/camera_test.h new file mode 100644 index 0000000..6ff8eb3 --- /dev/null +++ b/test/CameraHal/camera_test.h @@ -0,0 +1,165 @@ +#ifndef CAMERA_TEST_H +#define CAMERA_TEST_H + +#define PRINTOVER(arg...) LOGD(#arg) +#define LOG_FUNCTION_NAME LOGD("%d: %s() ENTER", __LINE__, __FUNCTION__); +#define LOG_FUNCTION_NAME_EXIT LOGD("%d: %s() EXIT", __LINE__, __FUNCTION__); +#define KEY_GBCE "gbce" +#define KEY_CAMERA "camera-index" +#define KEY_SATURATION "saturation" +#define KEY_BRIGHTNESS "brightness" +#define KEY_BURST "burst-capture" +#define KEY_EXPOSURE "exposure" +#define KEY_CONTRAST "contrast" +#define KEY_SHARPNESS "sharpness" +#define KEY_ISO "iso" +#define KEY_CAF "caf" +#define KEY_MODE "mode" +#define KEY_VNF "vnf" +#define KEY_VSTAB "vstab" +#define KEY_COMPENSATION "exposure-compensation" + +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) +#define KEY_IPP "ippMode" +#else +#define KEY_IPP "ipp" +#endif + +#define KEY_BUFF_STARV "buff-starvation" +#define KEY_METERING_MODE "meter-mode" +#define KEY_AUTOCONVERGENCE "auto-convergence" +#define KEY_MANUALCONVERGENCE_VALUES "manual-convergence-values" +#define AUTOCONVERGENCE_MODE_MANUAL "mode-manual" +#define KEY_EXP_BRACKETING_RANGE "exp-bracketing-range" +#define KEY_TEMP_BRACKETING "temporal-bracketing" +#define KEY_TEMP_BRACKETING_POS "temporal-bracketing-range-positive" +#define KEY_TEMP_BRACKETING_NEG "temporal-bracketing-range-negative" +#define KEY_MEASUREMENT "measurement" +#define KEY_S3D2D_PREVIEW_MODE "s3d2d-preview" +#define KEY_STEREO_CAMERA "s3d-supported" +#define KEY_EXIF_MODEL "exif-model" +#define KEY_EXIF_MAKE "exif-make" + +#define KEY_AUTO_EXPOSURE_LOCK "auto-exposure-lock" +#define KEY_AUTO_WHITEBALANCE_LOCK "auto-whitebalance-lock" + +#define SDCARD_PATH "/sdcard/" + +#define MAX_BURST 15 +#define BURST_INC 5 +#define TEMP_BRACKETING_MAX_RANGE 4 + +#define MEDIASERVER_DUMP "procmem -w $(ps | grep mediaserver | grep -Eo '[0-9]+' | head -n 1) | grep \"\\(Name\\|libcamera.so\\|libOMX\\|libomxcameraadapter.so\\|librcm.so\\|libnotify.so\\|libipcutils.so\\|libipc.so\\|libsysmgr.so\\|TOTAL\\)\"" +#define MEMORY_DUMP "procrank -u" +#define KEY_METERING_MODE "meter-mode" + +#define TEST_FOCUS_AREA "(0,0,1000,1000,300),(-1000,-1000,1000,1000,300),(0,0,0,0,0)" + +#define COMPENSATION_OFFSET 20 +#define DELIMITER "|" + +#define MAX_PREVIEW_SURFACE_WIDTH 800 +#define MAX_PREVIEW_SURFACE_HEIGHT 480 + +#define MODEL "camera_test" +#define MAKE "camera_test" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +namespace android { + class CameraHandler: public CameraListener { + public: + virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); + virtual void postData(int32_t msgType, + const sp<IMemory>& dataPtr, + camera_frame_metadata_t *metadata); + + virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); + }; + +}; + +using namespace android; + +char * get_cycle_cmd(const char *aSrc); +int execute_functional_script(char *script); +status_t dump_mem_status(); +int openCamera(); +int closeCamera(); +void initDefaults(); +int startPreview(); +void stopPreview(); +int startRecording(); +int stopRecording(); +int closeRecorder(); +int openRecorder(); +int configureRecorder(); +void printSupportedParams(); +char *load_script(char *config); +int start_logging(char *config, int &pid); +int stop_logging(int &pid); +int execute_error_script(char *script); + +typedef struct pixel_format_t { + int32_t pixelFormatDesc; + const char *pixformat; +}pixel_format; + +typedef struct output_format_t { + output_format type; + const char *desc; +} outformat; + +typedef struct preview_size_t { + int width, height; + const char *desc; +} preview_size; + +typedef struct Vcapture_size_t { + int width, height; + const char *desc; +} Vcapture_size; + +typedef struct capture_Size_t { + int width, height; + const char *name; +} capture_Size; + +typedef struct video_Codecs_t { + video_encoder type; + const char *desc; +} video_Codecs; + +typedef struct audio_Codecs_t { + audio_encoder type; + const char *desc; +} audio_Codecs; + +typedef struct V_bitRate_t { + uint32_t bit_rate; + const char *desc; +} V_bitRate; + +typedef struct zoom_t { + int idx; + const char *zoom_description; +} Zoom; + +typedef struct fps_ranges_t { + const char *range; + const char *rangeDescription; +} fps_ranges; + +typedef struct fpsConst_Ranges_t { + const char *range; + const char *rangeDescription; + int constFramerate; +} fpsConst_Ranges; + +typedef struct fpsConst_RangesSec_t { + const char *range; + const char *rangeDescription; + int constFramerate; +} fpsConst_RangesSec; + +#endif diff --git a/test/CameraHal/camera_test_menu.cpp b/test/CameraHal/camera_test_menu.cpp new file mode 100644 index 0000000..9bbf16a --- /dev/null +++ b/test/CameraHal/camera_test_menu.cpp @@ -0,0 +1,2522 @@ +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <semaphore.h> +#include <pthread.h> + +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/ISurfaceComposerClient.h> +#include <surfaceflinger/SurfaceComposerClient.h> + +#include <camera/Camera.h> +#include <camera/ICamera.h> +#include <media/mediarecorder.h> + +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> +#include <cutils/properties.h> +#include <camera/CameraParameters.h> +#include <system/audio.h> +#include <system/camera.h> + +#include <cutils/memory.h> +#include <utils/Log.h> + +#include <sys/wait.h> + +#include "camera_test.h" + +using namespace android; + +int camera_index = 0; +int print_menu; +sp<Camera> camera; +sp<MediaRecorder> recorder; +sp<SurfaceComposerClient> client; +sp<SurfaceControl> surfaceControl; +sp<Surface> previewSurface; +CameraParameters params; +float compensation = 0.0; +double latitude = 0.0; +double longitude = 0.0; +double degree_by_step = 17.5609756;//..0975609756097; +double altitude = 0.0; +int awb_mode = 0; +int effects_mode = 0; +int scene_mode = 0; +int caf_mode = 0; +int vnf_mode = 0; +int vstab_mode = 0; + +int tempBracketRange = 1; +int tempBracketIdx = 0; +int measurementIdx = 0; +int expBracketIdx = 0; +int AutoConvergenceModeIDX = 0; +int ManualConvergenceValuesIDX = 0; +int ManualConvergenceDefaultValueIDX = 2; +int gbceIDX = 0; +int rotation = 0; +bool reSizePreview = true; +bool hardwareActive = false; +bool recordingMode = false; +bool previewRunning = false; +int saturation = 0; +int zoomIDX = 0; +int videoCodecIDX = 0; +int audioCodecIDX = 0; +int outputFormatIDX = 0; +int contrast = 0; +int brightness = 0; +unsigned int burst = 0; +int sharpness = 0; +int iso_mode = 0; +int capture_mode = 0; +int exposure_mode = 0; +int ippIDX = 0; +int ippIDX_old = 0; +int previewFormat = 0; +int jpegQuality = 85; +int thumbQuality = 85; +int flashIdx = 0; +int fpsRangeIdx = 0; +timeval autofocus_start, picture_start; +char script_name[80]; +int prevcnt = 0; +int videoFd = -1; +int elockidx = 0; +int wblockidx = 0; + + +char dir_path[80] = SDCARD_PATH; + +const char *cameras[] = {"Primary Camera", "Secondary Camera 1", "Stereo Camera", "USB Camera", "Fake Camera"}; +const char *measurement[] = {"disable", "enable"}; +const char *expBracketing[] = {"disable", "enable"}; +const char *expBracketingRange[] = {"", "-30,0,30,0,-30"}; +const char *tempBracketing[] = {"disable", "enable"}; +const char *faceDetection[] = {"disable", "enable"}; +const char *lock[] = {"false", "true"}; + +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) +const char *ipp_mode[] = { "off", "Chroma Suppression", "Edge Enhancement" }; +#else +const char *ipp_mode[] = { "off", "ldc", "nsf", "ldc-nsf" }; +#endif + +const char *iso [] = { "auto", "100", "200", "400", "800", "1200", "1600"}; + +const char *effects [] = { +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + "none", + "mono", + "negative", + "solarize", + "sepia", + "whiteboard", + "blackboard", + "cool", + "emboss" +#else + "none", + "mono", + "negative", + "solarize", + "sepia", + "vivid", + "whiteboard", + "blackboard", + "cool", + "emboss", + "blackwhite", + "aqua", + "posterize" +#endif +}; + +const char CameraParameters::FLASH_MODE_OFF[] = "off"; +const char CameraParameters::FLASH_MODE_AUTO[] = "auto"; +const char CameraParameters::FLASH_MODE_ON[] = "on"; +const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye"; +const char CameraParameters::FLASH_MODE_TORCH[] = "torch"; + +const char *flashModes[] = { + "off", + "auto", + "on", + "red-eye", + "torch", + "fill-in", +}; + +const char *caf [] = { "Off", "On" }; +const char *vnf [] = { "Off", "On" }; +const char *vstab [] = { "Off", "On" }; + + +const char *scene [] = { +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + "auto", + "portrait", + "landscape", + "night", + "night-portrait", + "fireworks", + "snow", + "action", +#else + "auto", + "portrait", + "landscape", + "night", + "night-portrait", + "night-indoor", + "fireworks", + "sport", + "cine", + "beach", + "snow", + "mood", + "closeup", + "underwater", + "document", + "barcode", + "oldfilm", + "candlelight", + "party", + "steadyphoto", + "sunset", + "action", + "theatre" +#endif +}; +const char *strawb_mode[] = { + "auto", + "incandescent", + "fluorescent", + "daylight", + "horizon", + "shadow", + "tungsten", + "shade", + "twilight", + "warm-fluorescent", + "facepriority", + "sunset" +}; + +size_t length_cam = ARRAY_SIZE(cameras); + + +preview_size previewSize [] = { + { 0, 0, "NULL"}, + { 128, 96, "SQCIF" }, + { 176, 144, "QCIF" }, + { 352, 288, "CIF" }, + { 320, 240, "QVGA" }, + { 352, 288, "CIF" }, + { 640, 480, "VGA" }, + { 720, 480, "NTSC" }, + { 720, 576, "PAL" }, + { 800, 480, "WVGA" }, + { 848, 480, "WVGA2"}, + { 864, 480, "WVGA3"}, + { 992, 560, "WVGA4"}, + { 1280, 720, "HD" }, + { 1920, 1080, "FULLHD"}, +}; + +size_t length_previewSize = ARRAY_SIZE(previewSize); + +Vcapture_size VcaptureSize [] = { + { 128, 96, "SQCIF" }, + { 176, 144, "QCIF" }, + { 352, 288, "CIF" }, + { 320, 240, "QVGA" }, + { 640, 480, "VGA" }, + { 704, 480, "TVNTSC" }, + { 704, 576, "TVPAL" }, + { 720, 480, "D1NTSC" }, + { 720, 576, "D1PAL" }, + { 800, 480, "WVGA" }, + #if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + { 848, 480, "WVGA2"}, + { 864, 480, "WVGA3"}, + { 992, 560, "WVGA4"}, + #endif + { 1280, 720, "HD" }, + { 1920, 1080, "FULLHD"}, +}; + +size_t lenght_Vcapture_size = ARRAY_SIZE(VcaptureSize); + +capture_Size captureSize[] = { + { 320, 240, "QVGA" }, + { 640, 480, "VGA" }, + { 800, 600, "SVGA" }, + { 1152, 864, "1MP" }, + { 1280, 1024, "1.3MP" }, + { 1600, 1200, "2MP" }, + { 2048, 1536, "3MP" }, + { 2592, 1944, "5MP" }, + { 2608, 1960, "5MP" }, + { 3264, 2448, "8MP" }, + { 3648, 2736, "10MP"}, + { 4032, 3024, "12MP"}, +}; + +size_t length_capture_Size = ARRAY_SIZE(captureSize); + + +outformat outputFormat[] = { + { OUTPUT_FORMAT_THREE_GPP, "3gp" }, + { OUTPUT_FORMAT_MPEG_4, "mp4" }, + }; + +size_t length_outformat = ARRAY_SIZE(outputFormat); + +video_Codecs videoCodecs[] = { + { VIDEO_ENCODER_H263, "H263" }, + { VIDEO_ENCODER_H264, "H264" }, + { VIDEO_ENCODER_MPEG_4_SP, "MPEG4"} +}; + +size_t length_video_Codecs = ARRAY_SIZE(videoCodecs); + +audio_Codecs audioCodecs[] = { + { AUDIO_ENCODER_AMR_NB, "AMR_NB" }, + { AUDIO_ENCODER_AMR_WB, "AMR_WB" }, + { AUDIO_ENCODER_AAC, "AAC" }, + { AUDIO_ENCODER_AAC_PLUS, "AAC+" }, + { AUDIO_ENCODER_EAAC_PLUS, "EAAC+" } +}; + +size_t length_audio_Codecs = ARRAY_SIZE(audioCodecs); + +V_bitRate VbitRate[] = { + { 64000, "64K" }, + { 128000, "128K" }, + { 192000, "192K" }, + { 240000, "240K" }, + { 320000, "320K" }, + { 360000, "360K" }, + { 384000, "384K" }, + { 420000, "420K" }, + { 768000, "768K" }, + { 1000000, "1M" }, + { 1500000, "1.5M" }, + { 2000000, "2M" }, + { 4000000, "4M" }, + { 6000000, "6M" }, + { 8000000, "8M" }, + { 10000000, "10M" }, +}; + +size_t length_V_bitRate = ARRAY_SIZE(VbitRate); + +Zoom zoom[] = { + { 0, "1x" }, + { 12, "1.5x"}, + { 20, "2x" }, + { 27, "2.5x"}, + { 32, "3x" }, + { 36, "3.5x"}, + { 40, "4x" }, + { 60, "8x" }, +}; + +size_t length_Zoom = ARRAY_SIZE(zoom); + +fps_ranges fpsRanges[] = { + { "5000,30000", "[5:30]" }, + { "5000,10000", "[5:10]" }, + { "5000,15000", "[5:15]" }, + { "5000,20000", "[5:20]" }, +}; + +size_t length_fps_ranges = ARRAY_SIZE(fpsRanges); + +fpsConst_Ranges fpsConstRanges[] = { + { "5000,5000", "[5:5]", 5 }, + { "10000,10000", "[10:10]", 10 }, + { "15000,15000", "[15:15]", 15 }, + { "20000,20000", "[20:20]", 20 }, + { "25000,25000", "[25:25]", 25 }, + { "30000,30000", "[30:30]", 30 }, +}; + +size_t length_fpsConst_Ranges = ARRAY_SIZE(fpsConstRanges); + +fpsConst_RangesSec fpsConstRangesSec[] = { + { "5000,5000", "[5:5]", 5 }, + { "10000,10000", "[10:10]", 10 }, + { "15000,15000", "[15:15]", 15 }, + { "20000,20000", "[20:20]", 20 }, + { "25000,25000", "[25:25]", 25 }, + { "27000,27000", "[27:27]", 27 }, +}; + +size_t length_fpsConst_RangesSec = ARRAY_SIZE(fpsConstRangesSec); + +const char *antibanding[] = { + "off", + "auto", + "50hz", + "60hz", +}; +int antibanding_mode = 0; +const char *focus[] = { + "auto", + "infinity", + "macro", + "continuous-video", + "extended", + "portrait", +}; +int focus_mode = 0; +pixel_format pixelformat[] = { + { HAL_PIXEL_FORMAT_YCbCr_422_I, CameraParameters::PIXEL_FORMAT_YUV422I }, + { HAL_PIXEL_FORMAT_YCrCb_420_SP, CameraParameters::PIXEL_FORMAT_YUV420SP }, + { HAL_PIXEL_FORMAT_RGB_565, CameraParameters::PIXEL_FORMAT_RGB565 }, + { -1, CameraParameters::PIXEL_FORMAT_JPEG }, + { -1, "raw" }, + }; + +const char *codingformat[] = {"yuv422i-yuyv", "yuv420sp", "rgb565", "jpeg", "raw", "jps", "mpo", "raw+jpeg", "raw+mpo"}; +const char *gbce[] = {"disable", "enable"}; +int pictureFormat = 3; // jpeg +const char *exposure[] = {"auto", "macro", "portrait", "landscape", "sports", "night", "night-portrait", "backlighting", "manual"}; +const char *capture[] = { "high-performance", "high-quality", "video-mode" }; +const char *autoconvergencemode[] = { "mode-disable", "mode-frame", "mode-center", "mode-fft", "mode-manual" }; +const char *manualconvergencevalues[] = { "-100", "-50", "-30", "-25", "0", "25", "50", "100" }; + +const struct { + int fps; +} frameRate[] = { + {0}, + {5}, + {10}, + {15}, + {20}, + {25}, + {30} +}; + +int thumbSizeIDX = 3; +int previewSizeIDX = ARRAY_SIZE(previewSize) - 1; +int captureSizeIDX = ARRAY_SIZE(captureSize) - 1; +int frameRateIDX = ARRAY_SIZE(fpsConstRanges) - 1; +int frameRateIDXSec = ARRAY_SIZE(fpsConstRangesSec) - 1; +int VcaptureSizeIDX = ARRAY_SIZE(VcaptureSize) - 1; +int VbitRateIDX = ARRAY_SIZE(VbitRate) - 1; + +static unsigned int recording_counter = 1; + +int dump_preview = 0; +int bufferStarvationTest = 0; +bool showfps = false; + +const char *metering[] = { + "center", + "average", +}; +int meter_mode = 0; +bool bLogSysLinkTrace = true; +bool stressTest = false; +bool stopScript = false; +int restartCount = 0; + +/** Calculate delay from a reference time */ +unsigned long long timeval_delay(const timeval *ref) { + unsigned long long st, end, delay; + timeval current_time; + + gettimeofday(¤t_time, 0); + + st = ref->tv_sec * 1000000 + ref->tv_usec; + end = current_time.tv_sec * 1000000 + current_time.tv_usec; + delay = end - st; + + return delay; +} + +/** Callback for takePicture() */ +void my_raw_callback(const sp<IMemory>& mem) { + + static int counter = 1; + unsigned char *buff = NULL; + int size; + int fd = -1; + char fn[256]; + + LOG_FUNCTION_NAME; + + if (mem == NULL) + goto out; + + //Start preview after capture. + camera->startPreview(); + + fn[0] = 0; + sprintf(fn, "/sdcard/img%03d.raw", counter); + fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + + if (fd < 0) + goto out; + + size = mem->size(); + + if (size <= 0) + goto out; + + buff = (unsigned char *)mem->pointer(); + + if (!buff) + goto out; + + if (size != write(fd, buff, size)) + printf("Bad Write int a %s error (%d)%s\n", fn, errno, strerror(errno)); + + counter++; + printf("%s: buffer=%08X, size=%d stored at %s\n", + __FUNCTION__, (int)buff, size, fn); + +out: + + if (fd >= 0) + close(fd); + + LOG_FUNCTION_NAME_EXIT; +} + +void saveFile(const sp<IMemory>& mem) { + static int counter = 1; + unsigned char *buff = NULL; + int size; + int fd = -1; + char fn[256]; + + LOG_FUNCTION_NAME; + + if (mem == NULL) + goto out; + + fn[0] = 0; + sprintf(fn, "/sdcard/preview%03d.yuv", counter); + fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + if(fd < 0) { + LOGE("Unable to open file %s: %s", fn, strerror(fd)); + goto out; + } + + size = mem->size(); + if (size <= 0) { + LOGE("IMemory object is of zero size"); + goto out; + } + + buff = (unsigned char *)mem->pointer(); + if (!buff) { + LOGE("Buffer pointer is invalid"); + goto out; + } + + if (size != write(fd, buff, size)) + printf("Bad Write int a %s error (%d)%s\n", fn, errno, strerror(errno)); + + counter++; + printf("%s: buffer=%08X, size=%d\n", + __FUNCTION__, (int)buff, size); + +out: + + if (fd >= 0) + close(fd); + + LOG_FUNCTION_NAME_EXIT; +} + + +void debugShowFPS() +{ + static int mFrameCount = 0; + static int mLastFrameCount = 0; + static nsecs_t mLastFpsTime = 0; + static float mFps = 0; + mFrameCount++; + if ( ( mFrameCount % 30 ) == 0 ) { + nsecs_t now = systemTime(); + nsecs_t diff = now - mLastFpsTime; + mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; + mLastFpsTime = now; + mLastFrameCount = mFrameCount; + printf("####### [%d] Frames, %f FPS", mFrameCount, mFps); + } +} + +/** Callback for startPreview() */ +void my_preview_callback(const sp<IMemory>& mem) { + + printf("PREVIEW Callback 0x%x", ( unsigned int ) mem->pointer()); + if (dump_preview) { + + if(prevcnt==50) + saveFile(mem); + + prevcnt++; + + uint8_t *ptr = (uint8_t*) mem->pointer(); + + printf("PRV_CB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9]); + + } + + debugShowFPS(); +} + +/** Callback for takePicture() */ +void my_jpeg_callback(const sp<IMemory>& mem) { + static int counter = 1; + unsigned char *buff = NULL; + int size; + int fd = -1; + char fn[256]; + + LOG_FUNCTION_NAME; + + //Start preview after capture. + camera->startPreview(); + + if (mem == NULL) + goto out; + + fn[0] = 0; + sprintf(fn, "%s/img%03d.jpg", dir_path,counter); + fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); + + if(fd < 0) { + LOGE("Unable to open file %s: %s", fn, strerror(fd)); + goto out; + } + + size = mem->size(); + if (size <= 0) { + LOGE("IMemory object is of zero size"); + goto out; + } + + buff = (unsigned char *)mem->pointer(); + if (!buff) { + LOGE("Buffer pointer is invalid"); + goto out; + } + + if (size != write(fd, buff, size)) + printf("Bad Write int a %s error (%d)%s\n", fn, errno, strerror(errno)); + + counter++; + printf("%s: buffer=%08X, size=%d stored at %s\n", + __FUNCTION__, (int)buff, size, fn); + +out: + + if (fd >= 0) + close(fd); + + LOG_FUNCTION_NAME_EXIT; +} + +void my_face_callback(camera_frame_metadata_t *metadata) { + int idx; + + if ( NULL == metadata ) { + return; + } + + for ( idx = 0 ; idx < metadata->number_of_faces ; idx++ ) { + printf("Face %d at %d,%d %d,%d \n", + idx, + metadata->faces[idx].rect[0], + metadata->faces[idx].rect[1], + metadata->faces[idx].rect[2], + metadata->faces[idx].rect[3]); + } + +} + +void CameraHandler::notify(int32_t msgType, int32_t ext1, int32_t ext2) { + + printf("Notify cb: %d %d %d\n", msgType, ext1, ext2); + + if ( msgType & CAMERA_MSG_FOCUS ) + printf("AutoFocus %s in %llu us\n", (ext1) ? "OK" : "FAIL", timeval_delay(&autofocus_start)); + + if ( msgType & CAMERA_MSG_SHUTTER ) + printf("Shutter done in %llu us\n", timeval_delay(&picture_start)); + + if ( msgType & CAMERA_MSG_ERROR && (ext1 == 1)) + { + printf("Camera Test CAMERA_MSG_ERROR.....\n"); + if (stressTest) + { + printf("Camera Test Notified of Error Restarting.....\n"); + stopScript = true; + } + else + { + printf("Camera Test Notified of Error Stopping.....\n"); + stopScript =false; + stopPreview(); + + if (recordingMode) + { + stopRecording(); + closeRecorder(); + recordingMode = false; + } + } + } +} + +void CameraHandler::postData(int32_t msgType, + const sp<IMemory>& dataPtr, + camera_frame_metadata_t *metadata) { + printf("Data cb: %d\n", msgType); + + if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) + my_preview_callback(dataPtr); + + if ( msgType & CAMERA_MSG_RAW_IMAGE ) { + printf("RAW done in %llu us\n", timeval_delay(&picture_start)); + my_raw_callback(dataPtr); + } + + if (msgType & CAMERA_MSG_POSTVIEW_FRAME) { + printf("Postview frame %llu us\n", timeval_delay(&picture_start)); + } + + if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) { + printf("JPEG done in %llu us\n", timeval_delay(&picture_start)); + my_jpeg_callback(dataPtr); + } + + if ( ( msgType & CAMERA_MSG_PREVIEW_METADATA ) && + ( NULL != metadata ) ) { + printf("Face detected %d \n", metadata->number_of_faces); + my_face_callback(metadata); + } +} + +void CameraHandler::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) + +{ + printf("Recording cb: %d %lld %p\n", msgType, timestamp, dataPtr.get()); + + static uint32_t count = 0; + + //if(count==100) + //saveFile(dataPtr); + + count++; + + uint8_t *ptr = (uint8_t*) dataPtr->pointer(); + + printf("VID_CB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9]); + + camera->releaseRecordingFrame(dataPtr); +} + +int createPreviewSurface(unsigned int width, unsigned int height, int32_t pixFormat) { + unsigned int previewWidth, previewHeight; + + if ( MAX_PREVIEW_SURFACE_WIDTH < width ) { + previewWidth = MAX_PREVIEW_SURFACE_WIDTH; + } else { + previewWidth = width; + } + + if ( MAX_PREVIEW_SURFACE_HEIGHT < height ) { + previewHeight = MAX_PREVIEW_SURFACE_HEIGHT; + } else { + previewHeight = height; + } + + client = new SurfaceComposerClient(); + + if ( NULL == client.get() ) { + printf("Unable to establish connection to Surface Composer \n"); + + return -1; + } + + surfaceControl = client->createSurface(0, + previewWidth, + previewHeight, + pixFormat); + + previewSurface = surfaceControl->getSurface(); + + client->openGlobalTransaction(); + surfaceControl->setLayer(100000); + surfaceControl->setPosition(0, 0); + surfaceControl->setSize(previewWidth, previewHeight); + surfaceControl->show(); + client->closeGlobalTransaction(); + + return 0; +} + +void printSupportedParams() +{ + printf("\n\r\tSupported Cameras: %s", params.get("camera-indexes")); + printf("\n\r\tSupported Picture Sizes: %s", params.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES)); + printf("\n\r\tSupported Picture Formats: %s", params.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); + printf("\n\r\tSupported Preview Sizes: %s", params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)); + printf("\n\r\tSupported Preview Formats: %s", params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS)); + printf("\n\r\tSupported Preview Frame Rates: %s", params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); + printf("\n\r\tSupported Thumbnail Sizes: %s", params.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES)); + printf("\n\r\tSupported Whitebalance Modes: %s", params.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE)); + printf("\n\r\tSupported Effects: %s", params.get(CameraParameters::KEY_SUPPORTED_EFFECTS)); + printf("\n\r\tSupported Scene Modes: %s", params.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES)); + printf("\n\r\tSupported Focus Modes: %s", params.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); + printf("\n\r\tSupported Antibanding Options: %s", params.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING)); + printf("\n\r\tSupported Flash Modes: %s", params.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES)); + printf("\n\r\tSupported Focus Areas: %d", params.getInt(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS)); + + if ( NULL != params.get(CameraParameters::KEY_FOCUS_DISTANCES) ) { + printf("\n\r\tFocus Distances: %s \n", params.get(CameraParameters::KEY_FOCUS_DISTANCES)); + } + + return; +} + + +int destroyPreviewSurface() { + + if ( NULL != previewSurface.get() ) { + previewSurface.clear(); + } + + if ( NULL != surfaceControl.get() ) { + surfaceControl->clear(); + surfaceControl.clear(); + } + + if ( NULL != client.get() ) { + client->dispose(); + client.clear(); + } + + return 0; +} + +int openRecorder() { + recorder = new MediaRecorder(); + + if ( NULL == recorder.get() ) { + printf("Error while creating MediaRecorder\n"); + + return -1; + } + + return 0; +} + +int closeRecorder() { + if ( NULL == recorder.get() ) { + printf("invalid recorder reference\n"); + + return -1; + } + + if ( recorder->init() < 0 ) { + printf("recorder failed to initialize\n"); + + return -1; + } + + if ( recorder->close() < 0 ) { + printf("recorder failed to close\n"); + + return -1; + } + + if ( recorder->release() < 0 ) { + printf("error while releasing recorder\n"); + + return -1; + } + + recorder.clear(); + + return 0; +} + +int configureRecorder() { + + char videoFile[256],vbit_string[50]; + videoFd = -1; + + if ( ( NULL == recorder.get() ) || ( NULL == camera.get() ) ) { + printf("invalid recorder and/or camera references\n"); + + return -1; + } + + camera->unlock(); + + sprintf(vbit_string,"video-param-encoding-bitrate=%u", VbitRate[VbitRateIDX].bit_rate); + String8 bit_rate(vbit_string); + if ( recorder->setParameters(bit_rate) < 0 ) { + printf("error while configuring bit rate\n"); + + return -1; + } + + if ( recorder->setCamera(camera->remote(), camera->getRecordingProxy()) < 0 ) { + printf("error while setting the camera\n"); + + return -1; + } + + if ( recorder->setVideoSource(VIDEO_SOURCE_CAMERA) < 0 ) { + printf("error while configuring camera video source\n"); + + return -1; + } + + + if ( recorder->setAudioSource(AUDIO_SOURCE_MIC) < 0 ) { + printf("error while configuring camera audio source\n"); + + return -1; + } + + if ( recorder->setOutputFormat(outputFormat[outputFormatIDX].type) < 0 ) { + printf("error while configuring output format\n"); + + return -1; + } + + if(mkdir("/mnt/sdcard/videos",0777) == -1) + printf("\n Directory --videos-- was not created \n"); + sprintf(videoFile, "/mnt/sdcard/videos/video%d.%s", recording_counter,outputFormat[outputFormatIDX].desc); + + videoFd = open(videoFile, O_CREAT | O_RDWR); + + if(videoFd < 0){ + printf("Error while creating video filename\n"); + + return -1; + } + + if ( recorder->setOutputFile(videoFd, 0, 0) < 0 ) { + printf("error while configuring video filename\n"); + + return -1; + } + + recording_counter++; + + if (camera_index == 0) { + if ( recorder->setVideoFrameRate(fpsConstRanges[frameRateIDX].constFramerate) < 0 ) { + printf("error while configuring video framerate\n"); + return -1; + } + } + else { + if ( recorder->setVideoFrameRate(fpsConstRangesSec[frameRateIDXSec].constFramerate) < 0 ) { + printf("error while configuring video framerate\n"); + return -1; + } + } + + if ( recorder->setVideoSize(VcaptureSize[VcaptureSizeIDX].width, VcaptureSize[VcaptureSizeIDX].height) < 0 ) { + printf("error while configuring video size\n"); + + return -1; + } + + if ( recorder->setVideoEncoder(videoCodecs[videoCodecIDX].type) < 0 ) { + printf("error while configuring video codec\n"); + + return -1; + } + + if ( recorder->setAudioEncoder(audioCodecs[audioCodecIDX].type) < 0 ) { + printf("error while configuring audio codec\n"); + + return -1; + } + + if ( recorder->setPreviewSurface( surfaceControl->getSurface() ) < 0 ) { + printf("error while configuring preview surface\n"); + + return -1; + } + + return 0; +} + +int startRecording() { + if ( ( NULL == recorder.get() ) || ( NULL == camera.get() ) ) { + printf("invalid recorder and/or camera references\n"); + + return -1; + } + + camera->unlock(); + + if ( recorder->prepare() < 0 ) { + printf("recorder prepare failed\n"); + + return -1; + } + + if ( recorder->start() < 0 ) { + printf("recorder start failed\n"); + + return -1; + } + + return 0; +} + +int stopRecording() { + if ( NULL == recorder.get() ) { + printf("invalid recorder reference\n"); + + return -1; + } + + if ( recorder->stop() < 0 ) { + printf("recorder failed to stop\n"); + + return -1; + } + + if ( 0 < videoFd ) { + close(videoFd); + } + + return 0; +} + +int openCamera() { + printf("openCamera(camera_index=%d)\n", camera_index); + camera = Camera::connect(camera_index); + + if ( NULL == camera.get() ) { + printf("Unable to connect to CameraService\n"); + printf("Retrying... \n"); + sleep(1); + camera = Camera::connect(camera_index); + + if ( NULL == camera.get() ) { + printf("Giving up!! \n"); + return -1; + } + } + + params = camera->getParameters(); + camera->setParameters(params.flatten()); + + camera->setListener(new CameraHandler()); + + hardwareActive = true; + + return 0; +} + +int closeCamera() { + if ( NULL == camera.get() ) { + printf("invalid camera reference\n"); + + return -1; + } + + camera->disconnect(); + camera.clear(); + + hardwareActive = false; + + return 0; +} + +//Workaround for an issue seen with ICS SurfaceFlinger. +//The last surface created is not getting rendered on screen, +//in our case this is the preview surface. Here we artificially wait +//for the preview to start and create a new temporary surface, which +//gets destroyed immediately. +int surfaceWorkaround(unsigned int width, unsigned int height, int32_t pixFormat) { + sleep(1); + + if ( NULL == client.get() ) { + return NO_INIT; + } + + sp<SurfaceControl> tmpSurface = client->createSurface(0, + width, + height, + pixFormat); + + if ( NULL != tmpSurface.get() ) { + tmpSurface->clear(); + tmpSurface.clear(); + } else { + return -ENOMEM; + } + + return NO_ERROR; +} + +int startPreview() { + int previewWidth, previewHeight; + if (reSizePreview) { + + if(recordingMode) + { + previewWidth = VcaptureSize[VcaptureSizeIDX].width; + previewHeight = VcaptureSize[VcaptureSizeIDX].height; + }else + { + previewWidth = previewSize[previewSizeIDX].width; + previewHeight = previewSize[previewSizeIDX].height; + } + + if ( createPreviewSurface(previewWidth, + previewHeight, + pixelformat[previewFormat].pixelFormatDesc) < 0 ) { + printf("Error while creating preview surface\n"); + return -1; + } + + if ( !hardwareActive ) { + openCamera(); + } + + params.setPreviewSize(previewWidth, previewHeight); + params.setPictureSize(captureSize[captureSizeIDX].width, captureSize[captureSizeIDX].height); + + camera->setParameters(params.flatten()); + camera->setPreviewDisplay(previewSurface); + + if(!hardwareActive) prevcnt = 0; + + camera->startPreview(); + + previewRunning = true; + reSizePreview = false; + + surfaceWorkaround( previewWidth, previewHeight, pixelformat[previewFormat].pixelFormatDesc); + } + + return 0; +} + +void stopPreview() { + if ( hardwareActive ) { + camera->stopPreview(); + + destroyPreviewSurface(); + + previewRunning = false; + reSizePreview = true; + closeCamera(); + } +} + +void initDefaults() { + camera_index = 0; + antibanding_mode = 0; + focus_mode = 0; + fpsRangeIdx = 0; + previewSizeIDX = 1; /* Default resolution set to WVGA */ + captureSizeIDX = 3; /* Default capture resolution is 8MP */ + frameRateIDX = ARRAY_SIZE(fpsConstRanges) - 1; /* Default frame rate is 30 FPS */ +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + VcaptureSizeIDX = ARRAY_SIZE(VcaptureSize) - 6;/* Default video record is WVGA */ +#else + VcaptureSizeIDX = ARRAY_SIZE(VcaptureSize) - 2;/* Default video record is WVGA */ +#endif + VbitRateIDX = ARRAY_SIZE(VbitRate) - 4; /*Default video bit rate is 4M */ + thumbSizeIDX = 0; + compensation = 0.0; + awb_mode = 0; + effects_mode = 0; + scene_mode = 0; + caf_mode = 0; + vnf_mode = 0; + vstab_mode = 0; + expBracketIdx = 0; + flashIdx = 0; + rotation = 0; + zoomIDX = 0; + videoCodecIDX = 0; + gbceIDX = 0; +#ifdef TARGET_OMAP4 + ///Temporary fix until OMAP3 and OMAP4 3A values are synced + contrast = 90; + brightness = 50; + sharpness = 0; + saturation = 50; +#else + contrast = 100; + brightness = 100; + sharpness = 0; + saturation = 100; +#endif + iso_mode = 0; + capture_mode = 0; + exposure_mode = 0; + ippIDX = 0;//set the ipp to ldc-nsf as the capture mode is set to HQ by default + ippIDX_old = ippIDX; + jpegQuality = 85; + bufferStarvationTest = 0; + meter_mode = 0; + previewFormat = 1; + pictureFormat = 3; // jpeg + params.setPreviewSize(previewSize[previewSizeIDX].width, previewSize[previewSizeIDX].height); + params.setPictureSize(captureSize[captureSizeIDX].width, captureSize[captureSizeIDX].height); + params.set(CameraParameters::KEY_ROTATION, rotation); + params.set(KEY_COMPENSATION, (int) (compensation * 10)); + params.set(params.KEY_WHITE_BALANCE, strawb_mode[awb_mode]); + params.set(KEY_MODE, (capture[capture_mode])); + params.set(params.KEY_SCENE_MODE, scene[scene_mode]); + params.set(KEY_CAF, caf_mode); + params.set(KEY_ISO, iso_mode); + params.set(KEY_GBCE, gbce[gbceIDX]); + params.set(KEY_SHARPNESS, sharpness); + params.set(KEY_CONTRAST, contrast); + params.set(CameraParameters::KEY_ZOOM, zoom[zoomIDX].idx); + params.set(KEY_EXPOSURE, exposure[exposure_mode]); + params.set(KEY_BRIGHTNESS, brightness); + params.set(KEY_SATURATION, saturation); + params.set(params.KEY_EFFECT, effects[effects_mode]); + params.setPreviewFrameRate(frameRate[ARRAY_SIZE(frameRate) - 1].fps); + params.set(params.KEY_ANTIBANDING, antibanding[antibanding_mode]); + params.set(params.KEY_FOCUS_MODE, focus[focus_mode]); + params.set(KEY_IPP, ippIDX); + params.set(CameraParameters::KEY_JPEG_QUALITY, jpegQuality); + params.setPreviewFormat(pixelformat[previewFormat].pixformat); + params.setPictureFormat(codingformat[pictureFormat]); + params.set(KEY_BUFF_STARV, bufferStarvationTest); //enable buffer starvation + params.set(KEY_METERING_MODE, metering[meter_mode]); + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, previewSize[thumbSizeIDX].width); + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, previewSize[thumbSizeIDX].height); + ManualConvergenceValuesIDX = ManualConvergenceDefaultValueIDX; + params.set(KEY_MANUALCONVERGENCE_VALUES, manualconvergencevalues[ManualConvergenceValuesIDX]); + params.set(KEY_S3D2D_PREVIEW_MODE, "off"); + params.set(KEY_STEREO_CAMERA, "false"); + params.set(KEY_EXIF_MODEL, MODEL); + params.set(KEY_EXIF_MAKE, MAKE); +} + +int menu_gps() { + char ch; + char coord_str[100]; + + if (print_menu) { + printf("\n\n== GPS MENU ============================\n\n"); + printf(" e. Latitude: %.7lf\n", latitude); + printf(" d. Longitude: %.7lf\n", longitude); + printf(" c. Altitude: %.7lf\n", altitude); + printf("\n"); + printf(" q. Return to main menu\n"); + printf("\n"); + printf(" Choice: "); + } + + ch = getchar(); + printf("%c", ch); + + print_menu = 1; + + switch (ch) { + + case 'e': + latitude += degree_by_step; + + if (latitude > 90.0) { + latitude -= 180.0; + } + + snprintf(coord_str, 7, "%.7lf", latitude); + params.set(params.KEY_GPS_LATITUDE, coord_str); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'd': + longitude += degree_by_step; + + if (longitude > 180.0) { + longitude -= 360.0; + } + + snprintf(coord_str, 7, "%.7lf", longitude); + params.set(params.KEY_GPS_LONGITUDE, coord_str); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'c': + altitude += 12345.67890123456789; + + if (altitude > 100000.0) { + altitude -= 200000.0; + } + + snprintf(coord_str, 100, "%.20lf", altitude); + params.set(params.KEY_GPS_ALTITUDE, coord_str); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'Q': + case 'q': + return -1; + + default: + print_menu = 0; + break; + } + + return 0; +} + +int functional_menu() { + char ch; + + if (print_menu) { + + printf("\n\n=========== FUNCTIONAL TEST MENU ===================\n\n"); + + printf(" \n\nSTART / STOP / GENERAL SERVICES \n"); + printf(" -----------------------------\n"); + printf(" A Select Camera %s\n", cameras[camera_index]); + printf(" [. Resume Preview after capture\n"); + printf(" 0. Reset to defaults\n"); + printf(" q. Quit\n"); + printf(" @. Disconnect and Reconnect to CameraService \n"); + printf(" /. Enable/Disable showfps: %s\n", ((showfps)? "Enabled":"Disabled")); + printf(" a. GEO tagging settings menu\n"); + printf(" E. Camera Capability Dump"); + + + printf(" \n\n PREVIEW SUB MENU \n"); + printf(" -----------------------------\n"); + printf(" 1. Start Preview\n"); + printf(" 2. Stop Preview\n"); + printf(" ~. Preview format %s\n", pixelformat[previewFormat].pixformat); +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + printf(" 4. Preview size: %4d x %4d - %s\n",previewSize[previewSizeIDX].width, previewSize[previewSizeIDX].height, previewSize[previewSizeIDX].desc); +#else + printf(" 4. Preview size: %4d x %4d - %s\n",previewSize[previewSizeIDX].width, camera_index == 2 ? previewSize[previewSizeIDX].height*2 : previewSize[previewSizeIDX].height, previewSize[previewSizeIDX].desc); +#endif + printf(" R. Preview framerate range: %s\n", fpsRanges[fpsRangeIdx].rangeDescription); + printf(" &. Dump a preview frame\n"); + printf(" _. Auto Convergence mode: %s\n", autoconvergencemode[AutoConvergenceModeIDX]); + printf(" ^. Manual Convergence Value: %s\n", manualconvergencevalues[ManualConvergenceValuesIDX]); + printf(" {. 2D Preview in 3D Stereo Mode: %s\n", params.get(KEY_S3D2D_PREVIEW_MODE)); + + printf(" \n\n IMAGE CAPTURE SUB MENU \n"); + printf(" -----------------------------\n"); + printf(" p. Take picture/Full Press\n"); + printf(" H. Exposure Bracketing: %s\n", expBracketing[expBracketIdx]); + printf(" U. Temporal Bracketing: %s\n", tempBracketing[tempBracketIdx]); + printf(" W. Temporal Bracketing Range: [-%d;+%d]\n", tempBracketRange, tempBracketRange); + printf(" $. Picture Format: %s\n", codingformat[pictureFormat]); + printf(" 3. Picture Rotation: %3d degree\n", rotation ); + printf(" 5. Picture size: %4d x %4d - %s\n",captureSize[captureSizeIDX].width, captureSize[captureSizeIDX].height, captureSize[captureSizeIDX].name); + printf(" i. ISO mode: %s\n", iso[iso_mode]); + printf(" u. Capture Mode: %s\n", capture[capture_mode]); + printf(" k. IPP Mode: %s\n", ipp_mode[ippIDX]); + printf(" K. GBCE: %s\n", gbce[gbceIDX]); + printf(" o. Jpeg Quality: %d\n", jpegQuality); + printf(" #. Burst Images: %3d\n", burst); + printf(" :. Thumbnail Size: %4d x %4d - %s\n",previewSize[thumbSizeIDX].width, previewSize[thumbSizeIDX].height, previewSize[thumbSizeIDX].desc); + printf(" ': Thumbnail Quality %d\n", thumbQuality); + + printf(" \n\n VIDEO CAPTURE SUB MENU \n"); + printf(" -----------------------------\n"); + + printf(" 6. Start Video Recording\n"); + printf(" 2. Stop Recording\n"); + printf(" l. Video Capture resolution: %4d x %4d - %s\n",VcaptureSize[VcaptureSizeIDX].width,VcaptureSize[VcaptureSizeIDX].height, VcaptureSize[VcaptureSizeIDX].desc); + printf(" ]. Video Bit rate : %s\n", VbitRate[VbitRateIDX].desc); + printf(" 9. Video Codec: %s\n", videoCodecs[videoCodecIDX].desc); + printf(" D. Audio Codec: %s\n", audioCodecs[audioCodecIDX].desc); + printf(" v. Output Format: %s\n", outputFormat[outputFormatIDX].desc); + + if (camera_index == 1) { + printf(" r. Framerate: %d\n", fpsConstRangesSec[frameRateIDXSec].constFramerate); + } + else { + printf(" r. Framerate: %d\n", fpsConstRanges[frameRateIDX].constFramerate); + } + printf(" *. Start Video Recording dump ( 1 raw frame ) \n"); + printf(" B VNF %s \n", vnf[vnf_mode]); + printf(" C VSTAB %s", vstab[vstab_mode]); + + printf(" \n\n 3A SETTING SUB MENU \n"); + printf(" -----------------------------\n"); + + printf(" M. Measurement Data: %s\n", measurement[measurementIdx]); + printf(" F. Start face detection \n"); + printf(" T. Stop face detection \n"); + printf(" G. Touch/Focus area AF\n"); + printf(" f. Auto Focus/Half Press\n"); + printf(" J.Flash: %s\n", flashModes[flashIdx]); + printf(" 7. EV offset: %4.1f\n", compensation); + printf(" 8. AWB mode: %s\n", strawb_mode[awb_mode]); + printf(" z. Zoom %s\n", zoom[zoomIDX].zoom_description); + printf(" j. Exposure %s\n", exposure[exposure_mode]); + printf(" e. Effect: %s\n", effects[effects_mode]); + printf(" w. Scene: %s\n", scene[scene_mode]); + printf(" s. Saturation: %d\n", saturation); + printf(" c. Contrast: %d\n", contrast); + printf(" h. Sharpness: %d\n", sharpness); + printf(" b. Brightness: %d\n", brightness); + printf(" x. Antibanding: %s\n", antibanding[antibanding_mode]); + printf(" g. Focus mode: %s\n", focus[focus_mode]); + printf(" m. Metering mode: %s\n" , metering[meter_mode]); + printf(" <. Exposure Lock: %s\n", lock[elockidx]); + printf(" >. WhiteBalance Lock: %s\n",lock[wblockidx]); + printf("\n"); + printf(" Choice: "); + } + + ch = getchar(); + printf("%c", ch); + + print_menu = 1; + + switch (ch) { + + case '_': + AutoConvergenceModeIDX++; + AutoConvergenceModeIDX %= ARRAY_SIZE(autoconvergencemode); + params.set(KEY_AUTOCONVERGENCE, autoconvergencemode[AutoConvergenceModeIDX]); + if ( strcmp (autoconvergencemode[AutoConvergenceModeIDX], AUTOCONVERGENCE_MODE_MANUAL) == 0) { + params.set(KEY_MANUALCONVERGENCE_VALUES, manualconvergencevalues[ManualConvergenceValuesIDX]); + } + else { + params.set(KEY_MANUALCONVERGENCE_VALUES, manualconvergencevalues[ManualConvergenceDefaultValueIDX]); + ManualConvergenceValuesIDX = ManualConvergenceDefaultValueIDX; + } + camera->setParameters(params.flatten()); + + break; + case '^': + if ( strcmp (autoconvergencemode[AutoConvergenceModeIDX], AUTOCONVERGENCE_MODE_MANUAL) == 0) { + ManualConvergenceValuesIDX++; + ManualConvergenceValuesIDX %= ARRAY_SIZE(manualconvergencevalues); + params.set(KEY_MANUALCONVERGENCE_VALUES, manualconvergencevalues[ManualConvergenceValuesIDX]); + camera->setParameters(params.flatten()); + } + break; + case 'A': + camera_index++; + camera_index %= ARRAY_SIZE(cameras); + if ( camera_index == 2) { + params.set(KEY_STEREO_CAMERA, "true"); + } else { + params.set(KEY_STEREO_CAMERA, "false"); + } + closeCamera(); + + openCamera(); + + if (camera_index == 0) { + params.setPreviewFrameRate(30); + } else { + params.setPreviewFrameRate(27); + } + + + break; + case '[': + if ( hardwareActive ) { + camera->setParameters(params.flatten()); + camera->startPreview(); + } + break; + + case '0': + initDefaults(); + break; + + case '1': + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + + return -1; + } + + break; + + case '2': + stopPreview(); + + if ( recordingMode ) { + camera->disconnect(); + camera.clear(); + stopRecording(); + closeRecorder(); + + camera = Camera::connect(camera_index); + if ( NULL == camera.get() ) { + sleep(1); + camera = Camera::connect(camera_index); + if ( NULL == camera.get() ) { + return -1; + } + } + camera->setListener(new CameraHandler()); + camera->setParameters(params.flatten()); + recordingMode = false; + } + + break; + + case '3': + rotation += 90; + rotation %= 360; + params.set(CameraParameters::KEY_ROTATION, rotation); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '4': + previewSizeIDX += 1; + previewSizeIDX %= ARRAY_SIZE(previewSize); + if ( strcmp(params.get(KEY_STEREO_CAMERA), "false") == 0 ) { + params.setPreviewSize(previewSize[previewSizeIDX].width, previewSize[previewSizeIDX].height); + } else { + params.setPreviewSize(previewSize[previewSizeIDX].width, previewSize[previewSizeIDX].height*2); + } + reSizePreview = true; + + if ( hardwareActive && previewRunning ) { + camera->stopPreview(); + camera->setParameters(params.flatten()); + camera->startPreview(); + } else if ( hardwareActive ) { + camera->setParameters(params.flatten()); + } + + break; + + case '5': + captureSizeIDX += 1; + captureSizeIDX %= ARRAY_SIZE(captureSize); + params.setPictureSize(captureSize[captureSizeIDX].width, captureSize[captureSizeIDX].height); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'l': + case 'L': + VcaptureSizeIDX++; + VcaptureSizeIDX %= ARRAY_SIZE(VcaptureSize); + break; + + case ']': + VbitRateIDX++; + VbitRateIDX %= ARRAY_SIZE(VbitRate); + break; + + + case '6': + + if ( !recordingMode ) { + + recordingMode = true; + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + + return -1; + } + + if ( openRecorder() < 0 ) { + printf("Error while openning video recorder\n"); + + return -1; + } + + if ( configureRecorder() < 0 ) { + printf("Error while configuring video recorder\n"); + + return -1; + } + + if ( startRecording() < 0 ) { + printf("Error while starting video recording\n"); + + return -1; + } + } + + break; + + case '7': + + if ( compensation > 2.0) { + compensation = -2.0; + } else { + compensation += 0.1; + } + + params.set(KEY_COMPENSATION, (int) (compensation * 10)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '8': + awb_mode++; + awb_mode %= ARRAY_SIZE(strawb_mode); + params.set(params.KEY_WHITE_BALANCE, strawb_mode[awb_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '9': + videoCodecIDX++; + videoCodecIDX %= ARRAY_SIZE(videoCodecs); + break; + case '~': + previewFormat += 1; + previewFormat %= ARRAY_SIZE(pixelformat) - 1; + params.setPreviewFormat(pixelformat[previewFormat].pixformat); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + case '$': + pictureFormat += 1; + if ( strcmp(params.get(KEY_STEREO_CAMERA), "false") == 0 && pictureFormat > 4 ) + pictureFormat = 0; + pictureFormat %= ARRAY_SIZE(codingformat); + params.setPictureFormat(codingformat[pictureFormat]); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '?' : + ///Set mode=3 to select video mode + params.set(KEY_MODE, 3); + params.set(KEY_VNF, 1); + params.set(KEY_VSTAB, 1); + break; + + case ':': + thumbSizeIDX += 1; + thumbSizeIDX %= ARRAY_SIZE(previewSize); + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, previewSize[thumbSizeIDX].width); + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, previewSize[thumbSizeIDX].height); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '\'': + if ( thumbQuality >= 100) { + thumbQuality = 0; + } else { + thumbQuality += 5; + } + + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, thumbQuality); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'B' : + vnf_mode++; + vnf_mode %= ARRAY_SIZE(vnf); + params.set(KEY_VNF, vnf_mode); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'C' : + vstab_mode++; + vstab_mode %= ARRAY_SIZE(vstab); + params.set(KEY_VSTAB, vstab_mode); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'E': + if(hardwareActive) + params.unflatten(camera->getParameters()); + printSupportedParams(); + break; + + case '*': + if ( hardwareActive ) + camera->startRecording(); + break; + + case 'o': + if ( jpegQuality >= 100) { + jpegQuality = 0; + } else { + jpegQuality += 5; + } + + params.set(CameraParameters::KEY_JPEG_QUALITY, jpegQuality); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'M': + measurementIdx = (measurementIdx + 1)%ARRAY_SIZE(measurement); + params.set(KEY_MEASUREMENT, measurement[measurementIdx]); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + case 'm': + { + meter_mode = (meter_mode + 1)%ARRAY_SIZE(metering); + params.set(KEY_METERING_MODE, metering[meter_mode]); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + } + + case 'k': + ippIDX += 1; + ippIDX %= ARRAY_SIZE(ipp_mode); + ippIDX_old = ippIDX; + +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + params.set(KEY_IPP, ipp_mode[ippIDX]); +#else + params.set(KEY_IPP, ippIDX); +#endif + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'K': + gbceIDX+= 1; + gbceIDX %= ARRAY_SIZE(gbce); + params.set(KEY_GBCE, gbce[gbceIDX]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'F': + if ( hardwareActive ) + camera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, 0, 0); + + break; + + case 'T': + + if ( hardwareActive ) + camera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0); + + break; + + case '@': + if ( hardwareActive ) { + + closeCamera(); + + if ( 0 >= openCamera() ) { + printf( "Reconnected to CameraService \n"); + } + } + + break; + + case '#': + + if ( burst >= MAX_BURST ) { + burst = 0; + } else { + burst += BURST_INC; + } + params.set(KEY_BURST, burst); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'J': + flashIdx++; + flashIdx %= ARRAY_SIZE(flashModes); + params.set(CameraParameters::KEY_FLASH_MODE, (flashModes[flashIdx])); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'u': + capture_mode++; + capture_mode %= ARRAY_SIZE(capture); + + // HQ should always be in ldc-nsf + // if not HQ, then return the ipp to its previous state + if( !strcmp(capture[capture_mode], "high-quality") ) { + ippIDX_old = ippIDX; + ippIDX = 3; + params.set(KEY_IPP, ipp_mode[ippIDX]); + } else { + ippIDX = ippIDX_old; + } + + params.set(KEY_MODE, (capture[capture_mode])); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'U': + tempBracketIdx++; + tempBracketIdx %= ARRAY_SIZE(tempBracketing); + params.set(KEY_TEMP_BRACKETING, tempBracketing[tempBracketIdx]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'H': + expBracketIdx++; + expBracketIdx %= ARRAY_SIZE(expBracketing); + + params.set(KEY_EXP_BRACKETING_RANGE, expBracketingRange[expBracketIdx]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'W': + tempBracketRange++; + tempBracketRange %= TEMP_BRACKETING_MAX_RANGE; + if ( 0 == tempBracketRange ) { + tempBracketRange = 1; + } + + params.set(KEY_TEMP_BRACKETING_NEG, tempBracketRange); + params.set(KEY_TEMP_BRACKETING_POS, tempBracketRange); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'w': + scene_mode++; + scene_mode %= ARRAY_SIZE(scene); + params.set(params.KEY_SCENE_MODE, scene[scene_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'i': + iso_mode++; + iso_mode %= ARRAY_SIZE(iso); + params.set(KEY_ISO, iso[iso_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'h': + if ( sharpness >= 100) { + sharpness = 0; + } else { + sharpness += 10; + } + params.set(KEY_SHARPNESS, sharpness); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'D': + { + audioCodecIDX++; + audioCodecIDX %= ARRAY_SIZE(audioCodecs); + break; + } + + case 'v': + { + outputFormatIDX++; + outputFormatIDX %= ARRAY_SIZE(outputFormat); + break; + } + + case 'z': + zoomIDX++; + zoomIDX %= ARRAY_SIZE(zoom); + params.set(CameraParameters::KEY_ZOOM, zoom[zoomIDX].idx); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'j': + exposure_mode++; + exposure_mode %= ARRAY_SIZE(exposure); + params.set(KEY_EXPOSURE, exposure[exposure_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'c': + if( contrast >= 200){ + contrast = 0; + } else { + contrast += 10; + } + params.set(KEY_CONTRAST, contrast); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + case 'b': + if ( brightness >= 200) { + brightness = 0; + } else { + brightness += 10; + } + + params.set(KEY_BRIGHTNESS, brightness); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 's': + case 'S': + if ( saturation >= 100) { + saturation = 0; + } else { + saturation += 10; + } + + params.set(KEY_SATURATION, saturation); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'e': + effects_mode++; + effects_mode %= ARRAY_SIZE(effects); + params.set(params.KEY_EFFECT, effects[effects_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'r': + + + if (camera_index == 0) { + frameRateIDX += 1; + frameRateIDX %= ARRAY_SIZE(fpsConstRanges); + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, fpsConstRanges[frameRateIDX].range); + } else + { + frameRateIDXSec += 1; + frameRateIDXSec %= ARRAY_SIZE(fpsConstRangesSec); + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, fpsConstRangesSec[frameRateIDXSec].range); + + + } + + if ( hardwareActive ) { + camera->setParameters(params.flatten()); + } + + break; + + case 'R': + fpsRangeIdx += 1; + fpsRangeIdx %= ARRAY_SIZE(fpsRanges); + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, fpsRanges[fpsRangeIdx].range); + + if ( hardwareActive ) { + camera->setParameters(params.flatten()); + } + + break; + + case 'x': + antibanding_mode++; + antibanding_mode %= ARRAY_SIZE(antibanding); + params.set(params.KEY_ANTIBANDING, antibanding[antibanding_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'g': + focus_mode++; + focus_mode %= ARRAY_SIZE(focus); + params.set(params.KEY_FOCUS_MODE, focus[focus_mode]); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'G': + + params.set(CameraParameters::KEY_FOCUS_AREAS, TEST_FOCUS_AREA); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + params.remove(CameraParameters::KEY_FOCUS_AREAS); + + case 'f': + + gettimeofday(&autofocus_start, 0); + + if ( hardwareActive ) + camera->autoFocus(); + + break; + + case 'p': + + gettimeofday(&picture_start, 0); + + if ( hardwareActive ) + camera->takePicture(CAMERA_MSG_COMPRESSED_IMAGE|CAMERA_MSG_RAW_IMAGE); + + break; + + case '&': + printf("Enabling Preview Callback"); + dump_preview = 1; + if ( hardwareActive ) + camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK); + break; + + case '{': + if ( strcmp(params.get(KEY_S3D2D_PREVIEW_MODE), "off") == 0 ) + { + params.set(KEY_S3D2D_PREVIEW_MODE, "on"); + } + else + { + params.set(KEY_S3D2D_PREVIEW_MODE, "off"); + } + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'a': + + while (1) { + if ( menu_gps() < 0) + break; + }; + + break; + + case 'q': + + stopPreview(); + + return -1; + + case '/': + { + if (showfps) + { + property_set("debug.image.showfps", "0"); + showfps = false; + } + else + { + property_set("debug.image.showfps", "1"); + showfps = true; + } + break; + } + + case '<': + elockidx += 1; + elockidx %= ARRAY_SIZE(lock); + params.set(KEY_AUTO_EXPOSURE_LOCK, lock[elockidx]); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case '>': + wblockidx += 1; + wblockidx %= ARRAY_SIZE(lock); + params.set(KEY_AUTO_WHITEBALANCE_LOCK, lock[wblockidx]); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + default: + print_menu = 0; + + break; + } + + return 0; +} + +void print_usage() { + printf(" USAGE: camera_test <param> <script>\n"); + printf(" <param>\n-----------\n\n"); + printf(" F or f -> Functional tests \n"); + printf(" A or a -> API tests \n"); + printf(" E or e -> Error scenario tests \n"); + printf(" S or s -> Stress tests; with syslink trace \n"); + printf(" SN or sn -> Stress tests; No syslink trace \n\n"); + printf(" <script>\n----------\n"); + printf("Script name (Only for stress tests)\n\n"); + return; +} + +int error_scenario() { + char ch; + status_t stat = NO_ERROR; + + if (print_menu) { + printf(" 0. Buffer need\n"); + printf(" 1. Not enough memory\n"); + printf(" 2. Media server crash\n"); + printf(" 3. Overlay object request\n"); + printf(" 4. Pass unsupported preview&picture format\n"); + printf(" 5. Pass unsupported preview&picture resolution\n"); + printf(" 6. Pass unsupported preview framerate\n"); + + printf(" q. Quit\n"); + printf(" Choice: "); + } + + print_menu = 1; + ch = getchar(); + printf("%c\n", ch); + + switch (ch) { + case '0': { + printf("Case0:Buffer need\n"); + bufferStarvationTest = 1; + params.set(KEY_BUFF_STARV, bufferStarvationTest); //enable buffer starvation + + if ( !recordingMode ) { + recordingMode = true; + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + + return -1; + } + + if ( openRecorder() < 0 ) { + printf("Error while openning video recorder\n"); + + return -1; + } + + if ( configureRecorder() < 0 ) { + printf("Error while configuring video recorder\n"); + + return -1; + } + + if ( startRecording() < 0 ) { + printf("Error while starting video recording\n"); + + return -1; + } + + } + + usleep(1000000);//1s + + stopPreview(); + + if ( recordingMode ) { + stopRecording(); + closeRecorder(); + + recordingMode = false; + } + + break; + } + + case '1': { + printf("Case1:Not enough memory\n"); + int* tMemoryEater = new int[999999999]; + + if (!tMemoryEater) { + printf("Not enough memory\n"); + return -1; + } else { + delete tMemoryEater; + } + + break; + } + + case '2': { + printf("Case2:Media server crash\n"); + //camera = Camera::connect(); + + if ( NULL == camera.get() ) { + printf("Unable to connect to CameraService\n"); + return -1; + } + + break; + } + + case '3': { + printf("Case3:Overlay object request\n"); + int err = 0; + + err = open("/dev/video5", O_RDWR); + + if (err < 0) { + printf("Could not open the camera device5: %d\n", err ); + return err; + } + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + return -1; + } + + usleep(1000000);//1s + + stopPreview(); + + close(err); + break; + } + + case '4': { + + if ( hardwareActive ) { + + params.setPictureFormat("invalid-format"); + params.setPreviewFormat("invalid-format"); + + stat = camera->setParameters(params.flatten()); + + if ( NO_ERROR != stat ) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + } + + initDefaults(); + } + + break; + } + + case '5': { + + if ( hardwareActive ) { + + params.setPictureSize(-1, -1); + params.setPreviewSize(-1, -1); + + stat = camera->setParameters(params.flatten()); + + if ( NO_ERROR != stat ) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + } + + initDefaults(); + } + + break; + } + + case '6': { + + if ( hardwareActive ) { + + params.setPreviewFrameRate(-1); + + stat = camera->setParameters(params.flatten()); + + if ( NO_ERROR != stat ) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + } + + initDefaults(); + } + + + break; + } + + case 'q': { + return -1; + } + + default: { + print_menu = 0; + break; + } + } + + return 0; +} + +int restartCamera() { + + const char dir_path_name[80] = SDCARD_PATH; + + printf("+++Restarting Camera After Error+++\n"); + stopPreview(); + + if (recordingMode) { + stopRecording(); + closeRecorder(); + + recordingMode = false; + } + + sleep(3); //Wait a bit before restarting + + restartCount++; + + if (strcpy(dir_path, dir_path_name) == NULL) + { + printf("Error reseting dir name"); + return -1; + } + + if ( openCamera() < 0 ) + { + printf("+++Camera Restarted Failed+++\n"); + system("echo camerahal_test > /sys/power/wake_unlock"); + return -1; + } + + initDefaults(); + + stopScript = false; + + printf("+++Camera Restarted Successfully+++\n"); + return 0; +} + +int main(int argc, char *argv[]) { + char *cmd; + int pid; + sp<ProcessState> proc(ProcessState::self()); + + unsigned long long st, end, delay; + timeval current_time; + + gettimeofday(¤t_time, 0); + + st = current_time.tv_sec * 1000000 + current_time.tv_usec; + + cmd = NULL; + + if ( argc < 2 ) { + printf(" Please enter atleast 1 argument\n"); + print_usage(); + + return 0; + } + system("echo camerahal_test > /sys/power/wake_lock"); + if ( argc < 3 ) { + switch (*argv[1]) { + case 'S': + case 's': + printf("This is stress / regression tests \n"); + printf("Provide script file as 2nd argument\n"); + + break; + + case 'F': + case 'f': + ProcessState::self()->startThreadPool(); + + if ( openCamera() < 0 ) { + printf("Camera initialization failed\n"); + system("echo camerahal_test > /sys/power/wake_unlock"); + return -1; + } + + initDefaults(); + print_menu = 1; + + while ( 1 ) { + if ( functional_menu() < 0 ) + break; + }; + + break; + + case 'A': + case 'a': + printf("API level test cases coming soon ... \n"); + + break; + + case 'E': + case 'e': { + ProcessState::self()->startThreadPool(); + + if ( openCamera() < 0 ) { + printf("Camera initialization failed\n"); + system("echo camerahal_test > /sys/power/wake_unlock"); + return -1; + } + + initDefaults(); + print_menu = 1; + + while (1) { + if (error_scenario() < 0) { + break; + } + } + + break; + } + + default: + printf("INVALID OPTION USED\n"); + print_usage(); + + break; + } + } else if ( ( argc == 3) && ( ( *argv[1] == 'S' ) || ( *argv[1] == 's') ) ) { + + if((argv[1][1] == 'N') || (argv[1][1] == 'n')) { + bLogSysLinkTrace = false; + } + + ProcessState::self()->startThreadPool(); + + if ( openCamera() < 0 ) { + printf("Camera initialization failed\n"); + system("echo camerahal_test > /sys/power/wake_unlock"); + return -1; + } + + initDefaults(); + + cmd = load_script(argv[2]); + + if ( cmd != NULL) { + start_logging(argv[2], pid); + stressTest = true; + + while (1) + { + if ( execute_functional_script(cmd) == 0 ) + { + break; + } + else + { + printf("CameraTest Restarting Camera...\n"); + + free(cmd); + cmd = NULL; + + if ( (restartCamera() != 0) || ((cmd = load_script(argv[2])) == NULL) ) + { + printf("ERROR::CameraTest Restarting Camera...\n"); + break; + } + } + } + free(cmd); + stop_logging(pid); + } + } else if ( ( argc == 3) && ( ( *argv[1] == 'E' ) || ( *argv[1] == 'e') ) ) { + + ProcessState::self()->startThreadPool(); + + if ( openCamera() < 0 ) { + printf("Camera initialization failed\n"); + system("echo camerahal_test > /sys/power/wake_unlock"); + return -1; + } + + initDefaults(); + + cmd = load_script(argv[2]); + + if ( cmd != NULL) { + start_logging(argv[2], pid); + execute_error_script(cmd); + free(cmd); + stop_logging(pid); + } + + } else { + printf("INVALID OPTION USED\n"); + print_usage(); + } + + gettimeofday(¤t_time, 0); + end = current_time.tv_sec * 1000000 + current_time.tv_usec; + delay = end - st; + printf("Application clossed after: %llu ms\n", delay); + system("echo camerahal_test > /sys/power/wake_unlock"); + return 0; +} + diff --git a/test/CameraHal/camera_test_script.cpp b/test/CameraHal/camera_test_script.cpp new file mode 100644 index 0000000..15a403c --- /dev/null +++ b/test/CameraHal/camera_test_script.cpp @@ -0,0 +1,1373 @@ +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <semaphore.h> +#include <pthread.h> + +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/ISurface.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/ISurfaceComposerClient.h> +#include <surfaceflinger/SurfaceComposerClient.h> + +#include <camera/Camera.h> +#include <camera/ICamera.h> +#include <media/mediarecorder.h> + +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> +#include <cutils/properties.h> +#include <camera/CameraParameters.h> + +#include <sys/wait.h> + +#include "camera_test.h" + +using namespace android; + +extern bool stopScript; +extern bool hardwareActive; +extern sp<Camera> camera; +extern CameraParameters params; +extern bool recordingMode; +extern int camera_index; +extern int rotation; +extern const preview_size previewSize []; +extern const Vcapture_size VcaptureSize []; +extern const capture_Size captureSize[]; +extern const outformat outputFormat[]; +extern const video_Codecs videoCodecs[]; +extern const audio_Codecs audioCodecs[]; +extern const V_bitRate VbitRate[]; +extern const fps_ranges fpsRanges[]; +extern const fpsConst_Ranges fpsConstRanges[]; +extern const fpsConst_RangesSec fpsConstRangesSec[]; +extern const Zoom zoom []; +extern int previewSizeIDX; +extern bool reSizePreview; +extern bool previewRunning; +extern int captureSizeIDX; +extern float compensation; +extern int videoCodecIDX; +extern int outputFormatIDX; +extern int audioCodecIDX; +extern int VcaptureSizeIDX; +extern int VbitRateIDX; +extern int thumbSizeIDX; +extern int thumbQuality; +extern int jpegQuality; +extern int dump_preview; +extern int ippIDX_old; +extern const char *capture[]; +extern int capture_mode; +extern int ippIDX; +extern const char *ipp_mode[]; +extern int tempBracketRange; +extern int iso_mode; +extern int sharpness; +extern int contrast; +extern int zoomIDX; +extern int brightness; +extern int saturation; +extern int fpsRangeIdx; +extern timeval autofocus_start, picture_start; +extern const char *cameras[]; +extern double latitude; +extern double degree_by_step; +extern double longitude; +extern double altitude; +extern char dir_path[80]; +extern int AutoConvergenceModeIDX; +extern const char *autoconvergencemode[]; +extern const char *manualconvergencevalues[]; +extern const int ManualConvergenceDefaultValueIDX; +extern size_t length_cam; +extern char script_name[]; +extern int restartCount; +extern bool bLogSysLinkTrace; +extern int bufferStarvationTest; +extern size_t length_previewSize; +extern size_t lenght_Vcapture_size; +extern size_t length_outformat; +extern size_t length_capture_Size; +extern size_t length_video_Codecs; +extern size_t length_audio_Codecs; +extern size_t length_V_bitRate; +extern size_t length_Zoom; +extern size_t length_fps_ranges; +extern size_t length_fpsConst_Ranges; +extern size_t length_fpsConst_RangesSec; + + +int execute_functional_script(char *script) { + char *cmd, *ctx, *cycle_cmd, *temp_cmd; + char id; + unsigned int i; + int dly; + int cycleCounter = 1; + int tLen = 0; + unsigned int iteration = 0; + status_t ret = NO_ERROR; + int frameR = 20; + int frameRateIndex = 0; + + LOG_FUNCTION_NAME; + + dump_mem_status(); + + cmd = strtok_r((char *) script, DELIMITER, &ctx); + + while ( NULL != cmd && (stopScript == false)) { + id = cmd[0]; + printf("Full Command: %s \n", cmd); + printf("Command: %c \n", cmd[0]); + + switch (id) { + + // Case for Suspend-Resume Feature + case '!': { + // STEP 1: Mount Debugfs + system("mkdir /debug"); + system("mount -t debugfs debugfs /debug"); + + // STEP 2: Set up wake up Timer - wake up happens after 5 seconds + system("echo 10 > /debug/pm_debug/wakeup_timer_seconds"); + + // STEP 3: Make system ready for Suspend + system("echo camerahal_test > /sys/power/wake_unlock"); + // Release wake lock held by test app + printf(" Wake lock released "); + system("cat /sys/power/wake_lock"); + system("sendevent /dev/input/event0 1 60 1"); + system("sendevent /dev/input/event0 1 60 0"); + // Simulate F2 key press to make display OFF + printf(" F2 event simulation complete "); + + //STEP 4: Wait for system Resume and then simuate F1 key + sleep(50);//50s // This delay is not related to suspend resume timer + printf(" After 30 seconds of sleep"); + system("sendevent /dev/input/event0 1 59 0"); + system("sendevent /dev/input/event0 1 59 1"); + // Simulate F1 key press to make display ON + system("echo camerahal_test > /sys/power/wake_lock"); + // Acquire wake lock for test app + + break; + } + + case '[': + if ( hardwareActive ) + { + + camera->setParameters(params.flatten()); + + printf("starting camera preview.."); + status_t ret = camera->startPreview(); + if(ret !=NO_ERROR) + { + printf("startPreview failed %d..", ret); + } + } + break; + case '+': { + cycleCounter = atoi(cmd + 1); + cycle_cmd = get_cycle_cmd(ctx); + tLen = strlen(cycle_cmd); + temp_cmd = new char[tLen+1]; + + for (int ind = 0; ind < cycleCounter; ind++) { + strcpy(temp_cmd, cycle_cmd); + if ( execute_functional_script(temp_cmd) != 0 ) + return -1; + temp_cmd[0] = '\0'; + + //patch for image capture + //[ + if (ind < cycleCounter - 1) { + if (hardwareActive == false) { + if ( openCamera() < 0 ) { + printf("Camera initialization failed\n"); + + return -1; + } + + initDefaults(); + } + } + + //] + } + + ctx += tLen + 1; + + if (temp_cmd) { + delete temp_cmd; + temp_cmd = NULL; + } + + if (cycle_cmd) { + delete cycle_cmd; + cycle_cmd = NULL; + } + + break; + } + + case '0': + { + initDefaults(); + break; + } + + case '1': + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + + return -1; + } + + break; + + case '2': + stopPreview(); + + if ( recordingMode ) { + + camera->disconnect(); + camera.clear(); + stopRecording(); + closeRecorder(); + + camera = Camera::connect(camera_index); + if ( NULL == camera.get() ) { + sleep(1); + camera = Camera::connect(camera_index); + + if ( NULL == camera.get() ) { + return -1; + } + } + camera->setListener(new CameraHandler()); + camera->setParameters(params.flatten()); + + recordingMode = false; + } + + break; + + case '3': + rotation = atoi(cmd + 1); + params.set(CameraParameters::KEY_ROTATION, rotation); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '4': + { + printf("Setting resolution..."); + int width, height; + for(i = 0; i < length_previewSize ; i++) + { + if( strcmp((cmd + 1), previewSize[i].desc) == 0) + { + width = previewSize[i].width; + height = previewSize[i].height; + previewSizeIDX = i; + break; + } + } + + if (i == length_previewSize ) //if the resolution is not in the supported ones + { + char *res = NULL; + res = strtok(cmd + 1, "x"); + width = atoi(res); + res = strtok(NULL, "x"); + height = atoi(res); + } + + if ( strcmp(params.get(KEY_STEREO_CAMERA), "true") == 0 ) { + height *=2; + } + printf("Resolution: %d x %d\n", width, height); + params.setPreviewSize(width, height); + reSizePreview = true; + + if ( hardwareActive && previewRunning ) { + camera->stopPreview(); + camera->setParameters(params.flatten()); + camera->startPreview(); + } else if ( hardwareActive ) { + camera->setParameters(params.flatten()); + } + + break; + } + case '5': + + for (i = 0; i < length_capture_Size; i++) { + if ( strcmp((cmd + 1), captureSize[i].name) == 0) + break; + } + + if ( i < length_capture_Size ) { + params.setPictureSize(captureSize[i].width, captureSize[i].height); + captureSizeIDX = i; + } + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '6': + + if ( !recordingMode ) { + + recordingMode = true; + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + + return -1; + } + + if ( openRecorder() < 0 ) { + printf("Error while openning video recorder\n"); + + return -1; + } + + if ( configureRecorder() < 0 ) { + printf("Error while configuring video recorder\n"); + + return -1; + } + + if ( startRecording() < 0 ) { + printf("Error while starting video recording\n"); + + return -1; + } + + } + + break; + + case '7': + compensation = atof(cmd + 1); + params.set(KEY_COMPENSATION, (int) (compensation * 10)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '8': + params.set(params.KEY_WHITE_BALANCE, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '9': + for(i = 0; i < length_video_Codecs; i++) + { + if( strcmp((cmd + 1), videoCodecs[i].desc) == 0) + { + videoCodecIDX = i; + printf("Video Codec Selected: %s\n", + videoCodecs[i].desc); + break; + } + } + break; + + case 'v': + for(i = 0; i < length_outformat; i++) + + { + if( strcmp((cmd + 1), outputFormat[i].desc) == 0) + { + outputFormatIDX = i; + printf("Video Codec Selected: %s\n", + videoCodecs[i].desc); + break; + } + } + break; + + case '~': + params.setPreviewFormat(cmd + 1); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '$': + params.setPictureFormat(cmd + 1); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + case '-': + for(i = 0; i < length_audio_Codecs; i++) + { + if( strcmp((cmd + 1), audioCodecs[i].desc) == 0) + { + audioCodecIDX = i; + printf("Selected Audio: %s\n", audioCodecs[i].desc); + break; + } + } + break; + + case 'A': + camera_index=atoi(cmd+1); + // camera_index %= ARRAY_SIZE(cameras); + camera_index %= length_cam; + if ( camera_index == 2) + params.set(KEY_STEREO_CAMERA, "true"); + else + params.set(KEY_STEREO_CAMERA, "false"); + + printf("%s selected.\n", cameras[camera_index]); + + if ( hardwareActive ) { + stopPreview(); + closeCamera(); + openCamera(); + } else { + closeCamera(); + openCamera(); + } + + if (camera_index == 0) params.setPreviewFrameRate(30); + else params.setPreviewFrameRate(27); + + + break; + + case 'a': + char * temp_str; + + temp_str = strtok(cmd+1,"!"); + printf("Latitude %s \n",temp_str); + params.set(params.KEY_GPS_LATITUDE, temp_str); + temp_str=strtok(NULL,"!"); + printf("Longitude %s \n",temp_str); + params.set(params.KEY_GPS_LONGITUDE, temp_str); + temp_str=strtok(NULL,"!"); + printf("Altitude %s \n",temp_str); + params.set(params.KEY_GPS_ALTITUDE, temp_str); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'l': + case 'L': + for(i = 0; i < lenght_Vcapture_size; i++) + { + if( strcmp((cmd + 1), VcaptureSize[i].desc) == 0) + { + VcaptureSizeIDX = i; + printf("Video Capture Size: %s\n", VcaptureSize[i].desc); + break; + } + } + break; + case ']': + for(i = 0; i < length_V_bitRate; i++) + { + if( strcmp((cmd + 1), VbitRate[i].desc) == 0) + { + VbitRateIDX = i; + printf("Video Bit Rate: %s\n", VbitRate[i].desc); + break; + } + } + break; + case ':': + int width, height; + for(i = 0; i < length_previewSize ; i++) + { + if( strcmp((cmd + 1), previewSize[i].desc) == 0) + { + width = previewSize[i].width; + height = previewSize[i].height; + thumbSizeIDX = i; + break; + } + } + + if (i == length_previewSize ) //if the resolution is not in the supported ones + { + char *res = NULL; + res = strtok(cmd + 1, "x"); + width = atoi(res); + res = strtok(NULL, "x"); + height = atoi(res); + } + + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, width); + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, height); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '\'': + thumbQuality = atoi(cmd + 1); + + params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY, thumbQuality); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case '*': + if ( hardwareActive ) + camera->startRecording(); + break; + + case 't': + params.setPreviewFormat((cmd + 1)); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'o': + jpegQuality = atoi(cmd + 1); + params.set(CameraParameters::KEY_JPEG_QUALITY, jpegQuality); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + + case '&': + printf("Enabling Preview Callback"); + dump_preview = 1; + camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK); + break; + + + case 'k': + ippIDX_old = atoi(cmd + 1); + params.set(KEY_IPP, atoi(cmd + 1)); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'K': + params.set(KEY_GBCE, (cmd+1)); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'u': + // HQ should always be in ldc-nsf + // if not HQ, then return the ipp to its previous state + if( !strcmp(capture[capture_mode], "high-quality") ) { + ippIDX_old = ippIDX; + ippIDX = 3; + params.set(KEY_IPP, ipp_mode[ippIDX]); + } else { + ippIDX = ippIDX_old; + } + + params.set(KEY_MODE, (cmd + 1)); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'U': + + params.set(KEY_TEMP_BRACKETING, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'W': + + tempBracketRange = atoi(cmd + 1); + tempBracketRange %= TEMP_BRACKETING_MAX_RANGE; + if ( 0 == tempBracketRange ) { + tempBracketRange = 1; + } + + params.set(KEY_TEMP_BRACKETING_NEG, tempBracketRange); + params.set(KEY_TEMP_BRACKETING_POS, tempBracketRange); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '#': + + params.set(KEY_BURST, atoi(cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'J': + params.set(CameraParameters::KEY_FLASH_MODE, (cmd+1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'w': + params.set(params.KEY_SCENE_MODE, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'B' : + params.set(KEY_VNF, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + + case 'C' : + params.set(KEY_VSTAB, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'D': + if ( hardwareActive ) + camera->stopRecording(); + break; + + case 'E': + if(hardwareActive) + params.unflatten(camera->getParameters()); + printSupportedParams(); + break; + + case 'i': + iso_mode = atoi(cmd + 1); + params.set(KEY_ISO, iso_mode); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'h': + sharpness = atoi(cmd + 1); + params.set(KEY_SHARPNESS, sharpness); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case '@': + if ( hardwareActive ) { + + closeCamera(); + + if ( 0 >= openCamera() ) { + printf( "Reconnected to CameraService \n"); + } + } + + break; + + case 'c': + contrast = atoi(cmd + 1); + params.set(KEY_CONTRAST, contrast); + + if ( hardwareActive ) { + camera->setParameters(params.flatten()); + } + + break; + + case 'z': + case 'Z': + +#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3) + params.set(CameraParameters::KEY_ZOOM, atoi(cmd + 1)); +#else + + for(i = 0; i < length_Zoom; i++) + { + if( strcmp((cmd + 1), zoom[i].zoom_description) == 0) + { + zoomIDX = i; + break; + } + } + + params.set(CameraParameters::KEY_ZOOM, zoom[zoomIDX].idx); +#endif + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'j': + params.set(KEY_EXPOSURE, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'b': + brightness = atoi(cmd + 1); + params.set(KEY_BRIGHTNESS, brightness); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 's': + saturation = atoi(cmd + 1); + params.set(KEY_SATURATION, saturation); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'e': + params.set(params.KEY_EFFECT, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'r': + + frameR = atoi(cmd + 1); + + + if (camera_index == 0) { + for (i = 0; i < length_fpsConst_Ranges; i++) { + if (frameR == fpsConstRanges[i].constFramerate) + frameRateIndex = i; + + } + } else { + for (i = 0; i < length_fpsConst_RangesSec; i++) { + if (frameR == fpsConstRangesSec[i].constFramerate) + frameRateIndex = i; + } + } + + + if (camera_index == 0) + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, fpsConstRanges[frameRateIndex].range); + else + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, fpsConstRangesSec[frameRateIndex].range); + + + if ( hardwareActive && previewRunning ) { + camera->stopPreview(); + camera->setParameters(params.flatten()); + camera->startPreview(); + } else if ( hardwareActive ) { + camera->setParameters(params.flatten()); + } + + break; + + case 'R': + for(i = 0; i < length_fps_ranges; i++) + { + if( strcmp((cmd + 1), fpsRanges[i].rangeDescription) == 0) + { + fpsRangeIdx = i; + printf("Selected Framerate range: %s\n", fpsRanges[i].rangeDescription); + if ( hardwareActive ) { + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, fpsRanges[i].range); + params.remove(CameraParameters::KEY_PREVIEW_FRAME_RATE); + camera->setParameters(params.flatten()); + } + break; + } + } + break; + + case 'x': + params.set(params.KEY_ANTIBANDING, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'g': + params.set(params.KEY_FOCUS_MODE, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + break; + + case 'G': + + params.set(CameraParameters::KEY_FOCUS_AREAS, (cmd + 1)); + + if ( hardwareActive ) + camera->setParameters(params.flatten()); + + params.remove(CameraParameters::KEY_FOCUS_AREAS); + + case 'f': + gettimeofday(&autofocus_start, 0); + + if ( hardwareActive ) + camera->autoFocus(); + + break; + + case 'p': + gettimeofday(&picture_start, 0); + + if ( hardwareActive ) + ret = camera->takePicture(CAMERA_MSG_COMPRESSED_IMAGE|CAMERA_MSG_RAW_IMAGE); + + if ( ret != NO_ERROR ) + printf("Error returned while taking a picture"); + break; + + case 'd': + dly = atoi(cmd + 1); + sleep(dly); + break; + + case 'q': + dump_mem_status(); + stopPreview(); + + if ( recordingMode ) { + stopRecording(); + closeRecorder(); + + recordingMode = false; + } + goto exit; + + case '\n': + printf("Iteration: %d \n", iteration); + iteration++; + break; + + case '{': + if ( atoi(cmd + 1) > 0 ) + params.set(KEY_S3D2D_PREVIEW_MODE, "on"); + else + params.set(KEY_S3D2D_PREVIEW_MODE, "off"); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + + case 'M': + params.set(KEY_MEASUREMENT, (cmd + 1)); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + case 'm': + { + params.set(KEY_METERING_MODE, (cmd + 1)); + if ( hardwareActive ) + { + camera->setParameters(params.flatten()); + } + break; + } + case '<': + { + char coord_str[8]; + latitude += degree_by_step; + if (latitude > 90.0) + { + latitude -= 180.0; + } + snprintf(coord_str, 7, "%.7lf", latitude); + params.set(params.KEY_GPS_LATITUDE, coord_str); + if ( hardwareActive ) + { + camera->setParameters(params.flatten()); + } + break; + } + + case '=': + { + char coord_str[8]; + longitude += degree_by_step; + if (longitude > 180.0) + { + longitude -= 360.0; + } + snprintf(coord_str, 7, "%.7lf", longitude); + params.set(params.KEY_GPS_LONGITUDE, coord_str); + if ( hardwareActive ) + { + camera->setParameters(params.flatten()); + } + break; + } + + case '>': + { + char coord_str[8]; + altitude += 12345.67890123456789; + if (altitude > 100000.0) + { + altitude -= 200000.0; + } + snprintf(coord_str, 7, "%.7lf", altitude); + params.set(params.KEY_GPS_ALTITUDE, coord_str); + if ( hardwareActive ) + { + camera->setParameters(params.flatten()); + } + break; + } + + case 'X': + { + char rem_str[50]; + printf("Deleting images from %s \n", dir_path); + if(!sprintf(rem_str,"rm %s/*.jpg",dir_path)) + printf("Sprintf Error"); + if(system(rem_str)) + printf("Images were not deleted\n"); + break; + } + + case '_': + { + AutoConvergenceModeIDX = atoi(cmd + 1); + if ( AutoConvergenceModeIDX < 0 || AutoConvergenceModeIDX > 4 ) + AutoConvergenceModeIDX = 0; + params.set(KEY_AUTOCONVERGENCE, autoconvergencemode[AutoConvergenceModeIDX]); + if ( AutoConvergenceModeIDX != 4 ) + params.set(KEY_MANUALCONVERGENCE_VALUES, manualconvergencevalues[ManualConvergenceDefaultValueIDX]); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + break; + } + + case '^': + { + char strtmpval[7]; + if ( strcmp (autoconvergencemode[AutoConvergenceModeIDX], AUTOCONVERGENCE_MODE_MANUAL) == 0) { + sprintf(strtmpval,"%d", atoi(cmd + 1)); + params.set(KEY_MANUALCONVERGENCE_VALUES, strtmpval); + if ( hardwareActive ) + camera->setParameters(params.flatten()); + } + break; + } + + default: + printf("Unrecognized command!\n"); + break; + } + + cmd = strtok_r(NULL, DELIMITER, &ctx); + } + +exit: + if (stopScript == true) + { + return -1; + } + else + { + return 0; + } +} + + +char * get_cycle_cmd(const char *aSrc) { + unsigned ind = 0; + char *cycle_cmd = new char[256]; + + while ((*aSrc != '+') && (*aSrc != '\0')) { + cycle_cmd[ind++] = *aSrc++; + } + cycle_cmd[ind] = '\0'; + + return cycle_cmd; +} + +status_t dump_mem_status() { + system(MEDIASERVER_DUMP); + return system(MEMORY_DUMP); +} + +char *load_script(char *config) { + FILE *infile; + size_t fileSize; + char *script; + size_t nRead = 0; + char dir_name[40]; + size_t count; + char rCount [5]; + + count = 0; + + infile = fopen(config, "r"); + + strcpy(script_name,config); + + // remove just the '.txt' part of the config + while((config[count] != '.') && (count < sizeof(dir_name)/sizeof(dir_name[0]))) + count++; + + printf("\n SCRIPT : <%s> is currently being executed \n",script_name); + if(strncpy(dir_name,config,count) == NULL) + printf("Strcpy error"); + + dir_name[count]=NULL; + + if(strcat(dir_path,dir_name) == NULL) + printf("Strcat error"); + + if(restartCount) + { + sprintf(rCount,"_%d",restartCount); + if(strcat(dir_path, rCount) == NULL) + printf("Strcat error RestartCount"); + } + + printf("\n COMPLETE FOLDER PATH : %s \n",dir_path); + if(mkdir(dir_path,0777) == -1) { + printf("\n Directory %s was not created \n",dir_path); + } else { + printf("\n Directory %s was created \n",dir_path); + } + printf("\n DIRECTORY CREATED FOR TEST RESULT IMAGES IN MMC CARD : %s \n",dir_name); + + if( (NULL == infile)){ + printf("Error while opening script file %s!\n", config); + return NULL; + } + + fseek(infile, 0, SEEK_END); + fileSize = ftell(infile); + fseek(infile, 0, SEEK_SET); + + script = (char *) malloc(fileSize); + + if ( NULL == script ) { + printf("Unable to allocate buffer for the script\n"); + + return NULL; + } + + if ((nRead = fread(script, 1, fileSize, infile)) != fileSize) { + printf("Error while reading script file!\n"); + + free(script); + fclose(infile); + return NULL; + } + + fclose(infile); + + return script; +} + +int start_logging(char *config, int &pid) { + char dir_name[40]; + size_t count = 0; + int status = 0; + + // remove just the '.txt' part of the config + while((config[count] != '.') && (count < sizeof(dir_name)/sizeof(dir_name[0]))) + count++; + + if(strncpy(dir_name,config,count) == NULL) + printf("Strcpy error"); + + dir_name[count]=NULL; + + pid = fork(); + if (pid == 0) + { + char *command_list[] = {"sh", "-c", NULL, NULL}; + char log_cmd[120]; + // child process to run logging + + // set group id of this process to itself + // we will use this group id to kill the + // application logging + setpgid(getpid(), getpid()); + + /* Start logcat */ + if(!sprintf(log_cmd,"logcat > /sdcard/%s/log.txt &",dir_name)) + printf(" Sprintf Error"); + + /* Start Syslink Trace */ + if(bLogSysLinkTrace) { + if(!sprintf(log_cmd,"%s /system/bin/syslink_trace_daemon.out -l /sdcard/%s/syslink_trace.txt -f &",log_cmd, dir_name)) + printf(" Sprintf Error"); + } + + command_list[2] = (char *)log_cmd; + execvp("/system/bin/sh", command_list); + } if(pid < 0) + { + printf("failed to fork logcat\n"); + return -1; + } + + //wait for logging to start + if(waitpid(pid, &status, 0) != pid) + { + printf("waitpid failed in log fork\n"); + return -1; + }else + printf("logging started... status=%d\n", status); + + return 0; +} + +int stop_logging(int &pid) +{ + if(pid > 0) + { + if(killpg(pid, SIGKILL)) + { + printf("Exit command failed"); + return -1; + } else { + printf("\nlogging for script %s is complete\n logcat saved @ location: %s\n",script_name,dir_path); + if (bLogSysLinkTrace) + printf(" syslink_trace is saved @ location: %s\n\n",dir_path); + } + } + return 0; +} + +int execute_error_script(char *script) { + char *cmd, *ctx; + char id; + status_t stat = NO_ERROR; + + LOG_FUNCTION_NAME; + + cmd = strtok_r((char *) script, DELIMITER, &ctx); + + while ( NULL != cmd ) { + id = cmd[0]; + + switch (id) { + + case '0': { + bufferStarvationTest = 1; + params.set(KEY_BUFF_STARV, bufferStarvationTest); //enable buffer starvation + + if ( !recordingMode ) { + + recordingMode = true; + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + + return -1; + } + + if ( openRecorder() < 0 ) { + printf("Error while openning video recorder\n"); + + return -1; + } + + if ( configureRecorder() < 0 ) { + printf("Error while configuring video recorder\n"); + + return -1; + } + + if ( startRecording() < 0 ) { + printf("Error while starting video recording\n"); + + return -1; + } + + } + + usleep(1000000);//1s + + stopPreview(); + + if ( recordingMode ) { + stopRecording(); + closeRecorder(); + + recordingMode = false; + } + + break; + } + + case '1': { + int* tMemoryEater = new int[999999999]; + + if (!tMemoryEater) { + printf("Not enough memory\n"); + return -1; + } else { + delete tMemoryEater; + } + + break; + } + + case '2': { + //camera = Camera::connect(); + + if ( NULL == camera.get() ) { + printf("Unable to connect to CameraService\n"); + return -1; + } + + break; + } + + case '3': { + int err = 0; + + err = open("/dev/video5", O_RDWR); + + if (err < 0) { + printf("Could not open the camera device5: %d\n", err ); + return err; + } + + if ( startPreview() < 0 ) { + printf("Error while starting preview\n"); + return -1; + } + + usleep(1000000);//1s + + stopPreview(); + + close(err); + break; + } + + case '4': { + + if ( hardwareActive ) { + + params.setPictureFormat("invalid-format"); + params.setPreviewFormat("invalid-format"); + + stat = camera->setParameters(params.flatten()); + + if ( NO_ERROR != stat ) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + } + + initDefaults(); + } + + break; + } + + case '5': { + + if ( hardwareActive ) { + + params.setPictureSize(-1, -1); + params.setPreviewSize(-1, -1); + + stat = camera->setParameters(params.flatten()); + + if ( NO_ERROR != stat ) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + } + + initDefaults(); + } + + break; + } + + case '6': { + + if ( hardwareActive ) { + + params.setPreviewFrameRate(-1); + + stat = camera->setParameters(params.flatten()); + + if ( NO_ERROR != stat ) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + } + + initDefaults(); + } + + + break; + } + + case 'q': { + goto exit; + + break; + } + + default: { + printf("Unrecognized command!\n"); + + break; + } + } + + cmd = strtok_r(NULL, DELIMITER, &ctx); + } + +exit: + + return 0; +} + + + diff --git a/tiler/.gitignore b/tiler/.gitignore new file mode 100644 index 0000000..c23ec1a --- /dev/null +++ b/tiler/.gitignore @@ -0,0 +1,27 @@ +aclocal.m4 +autom4te.cache +Makefile.in +Makefile +ltmain.sh +stamp-h1 +.deps +.libs +*.o +*.lo +*.la +libtool +*.pc +config.log +config.status +config.guess +config.h +config.h.in +config.sub +config +configure +m4 +build +*~ +tests/testlib.c +*_test +*_ptest
\ No newline at end of file diff --git a/tiler/Android.mk b/tiler/Android.mk new file mode 100644 index 0000000..60c8699 --- /dev/null +++ b/tiler/Android.mk @@ -0,0 +1,33 @@ +# only include if running on an omap4 platform +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := memmgr.c tilermgr.c +LOCAL_MODULE := libtimemmgr +LOCAL_MODULE_TAGS := optional tests +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := memmgr_test.c testlib.c +LOCAL_SHARED_LIBRARIES := libtimemmgr +LOCAL_MODULE := memmgr_test +LOCAL_MODULE_TAGS := tests +include $(BUILD_HEAPTRACKED_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := utils_test.c testlib.c +LOCAL_SHARED_LIBRARIES := libtimemmgr +LOCAL_MODULE := utils_test +LOCAL_MODULE_TAGS := tests +include $(BUILD_HEAPTRCKED_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := tiler_ptest.c +LOCAL_SHARED_LIBRARIES := libtimemmgr +LOCAL_MODULE := tiler_ptest +LOCAL_MODULE_TAGS:= tests +include $(BUILD_HEAPTRACKED_EXECUTABLE) + +endif diff --git a/tiler/Makefile.am b/tiler/Makefile.am new file mode 100644 index 0000000..9f9e70b --- /dev/null +++ b/tiler/Makefile.am @@ -0,0 +1,80 @@ +# +# Makefile.am +# +# TI OMAP Processor Memory Allocator Interface functions makefile. +# +# Copyright (C) 2009-2011 Texas Instruments, Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Texas Instruments Incorporated nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +AUTOMAKE_OPTIONS = foreign + +## sources + +h_sources = memmgr.h tilermem.h mem_types.h tiler.h tilermem_utils.h +if STUB_TILER +c_sources = memmgr.c +else +c_sources = memmgr.c tilermgr.c +endif + +if TILERMGR +library_include_HEADERS = $(h_sources) tilermgr.h +else +library_include_HEADERS = $(h_sources) +noinst_HEADERS = tilermgr.h +endif + +#Install the headers in library directory - e.g. examplelib-1.0: +library_includedir=$(includedir)/timemmgr + +# library sources +lib_LTLIBRARIES= libtimemmgr.la +libtimemmgr_la_SOURCES = $(h_sources) $(c_sources) +libtimemmgr_la_CFLAGS = $(MEMMGR_CFLAGS) -fpic -ansi +libtimemmgr_la_LIBTOOLFLAGS = --tag=disable-static +libtimemmgr_la_LDFLAGS = -version-info 2:0:0 + +if UNIT_TESTS +bin_PROGRAMS = utils_test memmgr_test tiler_ptest + +utils_testdir = . +utils_test_SOURCES = utils_test.c testlib.c + +memmgr_testdir = . +memmgr_test_SOURCES = memmgr_test.c testlib.c +memmgr_test_LDADD = libtimemmgr.la + +tiler_ptest_SOURCES = tiler_ptest.c +tiler_ptest_LDADD = libtimemmgr.la +endif + +pkgconfig_DATA = libtimemmgr.pc +pkgconfigdir = $(libdir)/pkgconfig + diff --git a/tiler/README b/tiler/README new file mode 100644 index 0000000..e531b09 --- /dev/null +++ b/tiler/README @@ -0,0 +1,136 @@ +Validating MemMgr + + MemMgr tests are not persistently enumerated, so the test # in + memmgr test may vary from release to release. + + You need to run the test with the "list" argument to list all the test + descriptions and the corresponding test numbers. + + E.g. "memmgr_test list" + + If you have access to the official test report, the details column lists + the test description (in the last line). Match the test case description + to the last line of the cells in the Details column. + + Negative MemMgr tests run multiple test cases, so they map to multiple rows + in the official test report. Some of the test cases may not be available, + or may succeed even if the whole test failed/succeeded. + + To ease the generation of the test report, a python script is provided that + will populate most of the test report: + + run memmgr_test and pipe the output of the tests into a + file, e.g.: + + memmgr_test > test.log + + open UTR and select Tiler User Space worksheet + run this script by piping the test logs into the script, e.g. (you may + have to copy the log file from the target to a location that you can + access from the machine that has the UTR open.) + + python fill_utr.py < test.log + +Latest List of test cases + +memmgr_test + +TEST # 1 - alloc_1D_test(4096, 0) +TEST # 2 - alloc_2D_test(64, 64, PIXEL_FMT_8BIT) +TEST # 3 - alloc_2D_test(64, 64, PIXEL_FMT_16BIT) +TEST # 4 - alloc_2D_test(64, 64, PIXEL_FMT_32BIT) +TEST # 5 - alloc_NV12_test(64, 64) +TEST # 6 - map_1D_test(4096, 0) +TEST # 7 - alloc_1D_test(176 * 144 * 2, 512) +TEST # 8 - alloc_2D_test(176, 144, PIXEL_FMT_8BIT) +TEST # 9 - alloc_2D_test(176, 144, PIXEL_FMT_16BIT) +TEST # 10 - alloc_2D_test(176, 144, PIXEL_FMT_32BIT) +TEST # 11 - alloc_NV12_test(176, 144) +TEST # 12 - map_1D_test(176 * 144 * 2, 2048) +TEST # 13 - alloc_1D_test(640 * 480 * 2, 0) +TEST # 14 - alloc_2D_test(640, 480, PIXEL_FMT_8BIT) +TEST # 15 - alloc_2D_test(640, 480, PIXEL_FMT_16BIT) +TEST # 16 - alloc_2D_test(640, 480, PIXEL_FMT_32BIT) +TEST # 17 - alloc_NV12_test(640, 480) +TEST # 18 - map_1D_test(640 * 480 * 2, 0) +TEST # 19 - alloc_1D_test(848 * 480 * 2, 0) +TEST # 20 - alloc_2D_test(848, 480, PIXEL_FMT_8BIT) +TEST # 21 - alloc_2D_test(848, 480, PIXEL_FMT_16BIT) +TEST # 22 - alloc_2D_test(848, 480, PIXEL_FMT_32BIT) +TEST # 23 - alloc_NV12_test(848, 480) +TEST # 24 - map_1D_test(848 * 480 * 2, 0) +TEST # 25 - alloc_1D_test(1280 * 720 * 2, 0) +TEST # 26 - alloc_2D_test(1280, 720, PIXEL_FMT_8BIT) +TEST # 27 - alloc_2D_test(1280, 720, PIXEL_FMT_16BIT) +TEST # 28 - alloc_2D_test(1280, 720, PIXEL_FMT_32BIT) +TEST # 29 - alloc_NV12_test(1280, 720) +TEST # 30 - map_1D_test(1280 * 720 * 2, 0) +TEST # 31 - alloc_1D_test(1920 * 1080 * 2, 0) +TEST # 32 - alloc_2D_test(1920, 1080, PIXEL_FMT_8BIT) +TEST # 33 - alloc_2D_test(1920, 1080, PIXEL_FMT_16BIT) +TEST # 34 - alloc_2D_test(1920, 1080, PIXEL_FMT_32BIT) +TEST # 35 - alloc_NV12_test(1920, 1080) +TEST # 36 - map_1D_test(1920 * 1080 * 2, 0) +TEST # 37 - neg_alloc_tests() +TEST # 38 - neg_free_tests() +TEST # 39 - neg_map_tests() +TEST # 40 - neg_unmap_tests() +TEST # 41 - neg_check_tests() +TEST # 42 - page_size_test() +TEST # 43 - maxalloc_2D_test(2500, 32, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 44 - maxalloc_2D_test(2500, 16, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 45 - maxalloc_2D_test(1250, 16, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 46 - maxalloc_2D_test(5000, 32, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 47 - maxalloc_2D_test(5000, 16, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 48 - maxalloc_2D_test(2500, 16, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 49 - alloc_2D_test(8193, 16, PIXEL_FMT_8BIT) +TEST # 50 - alloc_2D_test(8193, 16, PIXEL_FMT_16BIT) +TEST # 51 - alloc_2D_test(4097, 16, PIXEL_FMT_32BIT) +TEST # 52 - alloc_2D_test(16384, 16, PIXEL_FMT_8BIT) +TEST # 53 - alloc_2D_test(16384, 16, PIXEL_FMT_16BIT) +TEST # 54 - alloc_2D_test(8192, 16, PIXEL_FMT_32BIT) +TEST # 55 - !alloc_2D_test(16385, 16, PIXEL_FMT_8BIT) +TEST # 56 - !alloc_2D_test(16385, 16, PIXEL_FMT_16BIT) +TEST # 57 - !alloc_2D_test(8193, 16, PIXEL_FMT_32BIT) +TEST # 58 - maxalloc_1D_test(4096, MAX_ALLOCS) +TEST # 59 - maxalloc_2D_test(64, 64, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 60 - maxalloc_2D_test(64, 64, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 61 - maxalloc_2D_test(64, 64, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 62 - maxalloc_NV12_test(64, 64, MAX_ALLOCS) +TEST # 63 - maxmap_1D_test(4096, MAX_ALLOCS) +TEST # 64 - maxalloc_1D_test(176 * 144 * 2, MAX_ALLOCS) +TEST # 65 - maxalloc_2D_test(176, 144, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 66 - maxalloc_2D_test(176, 144, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 67 - maxalloc_2D_test(176, 144, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 68 - maxalloc_NV12_test(176, 144, MAX_ALLOCS) +TEST # 69 - maxmap_1D_test(176 * 144 * 2, MAX_ALLOCS) +TEST # 70 - maxalloc_1D_test(640 * 480 * 2, MAX_ALLOCS) +TEST # 71 - maxalloc_2D_test(640, 480, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 72 - maxalloc_2D_test(640, 480, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 73 - maxalloc_2D_test(640, 480, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 74 - maxalloc_NV12_test(640, 480, MAX_ALLOCS) +TEST # 75 - maxmap_1D_test(640 * 480 * 2, MAX_ALLOCS) +TEST # 76 - maxalloc_1D_test(848 * 480 * 2, MAX_ALLOCS) +TEST # 77 - maxalloc_2D_test(848, 480, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 78 - maxalloc_2D_test(848, 480, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 79 - maxalloc_2D_test(848, 480, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 80 - maxalloc_NV12_test(848, 480, MAX_ALLOCS) +TEST # 81 - maxmap_1D_test(848 * 480 * 2, MAX_ALLOCS) +TEST # 82 - maxalloc_1D_test(1280 * 720 * 2, MAX_ALLOCS) +TEST # 83 - maxalloc_2D_test(1280, 720, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 84 - maxalloc_2D_test(1280, 720, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 85 - maxalloc_2D_test(1280, 720, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 86 - maxalloc_NV12_test(1280, 720, MAX_ALLOCS) +TEST # 87 - maxmap_1D_test(1280 * 720 * 2, MAX_ALLOCS) +TEST # 88 - maxalloc_1D_test(1920 * 1080 * 2, MAX_ALLOCS) +TEST # 89 - maxalloc_2D_test(1920, 1080, PIXEL_FMT_8BIT, MAX_ALLOCS) +TEST # 90 - maxalloc_2D_test(1920, 1080, PIXEL_FMT_16BIT, MAX_ALLOCS) +TEST # 91 - maxalloc_2D_test(1920, 1080, PIXEL_FMT_32BIT, MAX_ALLOCS) +TEST # 92 - maxalloc_NV12_test(1920, 1080, 2) +TEST # 93 - maxalloc_NV12_test(1920, 1080, MAX_ALLOCS) +TEST # 94 - maxmap_1D_test(1920 * 1080 * 2, MAX_ALLOCS) +TEST # 95 - star_tiler_test(1000, 10) +TEST # 96 - star_tiler_test(1000, 30) +TEST # 97 - star_test(100, 10) +TEST # 98 - star_test(1000, 10) + diff --git a/tiler/bootstrap.sh b/tiler/bootstrap.sh new file mode 100755 index 0000000..6170918 --- /dev/null +++ b/tiler/bootstrap.sh @@ -0,0 +1,18 @@ +#! /bin/sh + +cd `dirname $0` + +# on some platforms, you have "g" versions of some of these tools instead, +# ie glibtoolize instead of libtoolize.. +find_tool() { + which $1 2> /dev/null || which g$1 2> /dev/null +} + +aclocal=`find_tool aclocal` +libtoolize=`find_tool libtoolize` +automake=`find_tool automake` +autoconf=`find_tool autoconf` +autoheader=`find_tool autoheader` + +mkdir -p config && $autoheader && $aclocal && $libtoolize --copy --force && $automake --copy --add-missing --foreign && $autoconf + diff --git a/tiler/configure.ac b/tiler/configure.ac new file mode 100755 index 0000000..30d131c --- /dev/null +++ b/tiler/configure.ac @@ -0,0 +1,75 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.61) +AC_INIT(timemmgr, 2.00, http://www.ti.com) +AC_CONFIG_SRCDIR([memmgr.c]) +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([config]) +AC_CANONICAL_SYSTEM +AM_INIT_AUTOMAKE([timemmgr], [2.00]) +LT_INIT + +# Checks for programs. +AC_PROG_CC +AM_PROG_LIBTOOL + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T + +# Checks for library functions. +AC_PROG_GCC_TRADITIONAL +#AC_FUNC_MALLOC +#AC_FUNC_MMAP +AC_CHECK_FUNCS([munmap strerror]) + +AC_ARG_ENABLE(tilermgr, +[ --enable-tilermgr Include TilerMgr headers], +[case "${enableval}" in + yes) tilermgr=true ;; + no) tilermgr=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-tilermgr) ;; +esac],[tilermgr=true]) + +AC_ARG_ENABLE(tests, +[ --enable-tests Build unit tests], +[case "${enableval}" in + yes) tests=true ;; + no) tests=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-tests) ;; +esac],[tests=false]) + +AM_CONDITIONAL(UNIT_TESTS, test x$tests = xtrue) + +AM_CONDITIONAL(TILERMGR, test x$tilermgr != xfalse) + +AC_ARG_ENABLE(stub, +[ --enable-stub Stubbing tiler and syslink on none-arm system], +[case "${enableval}" in + yes) stub_tiler=true ;; + no) stub_tiler=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-stub) ;; +esac],[stub_tiler=false]) + +AM_CONDITIONAL(STUB_TILER, test x$stub_tiler = xtrue) + +if test x$stub_tiler = xtrue; then +AC_DEFINE([STUB_TILER],[1],[Use tiler stub]) +fi + +# Project build flags +MEMMGR_CFLAGS="-Werror -Wall -pipe -ansi" +AC_SUBST(MEMMGR_CFLAGS) + +AC_CONFIG_FILES([libtimemmgr.pc Makefile]) +AC_OUTPUT + diff --git a/tiler/debug_utils.h b/tiler/debug_utils.h new file mode 100644 index 0000000..316e80e --- /dev/null +++ b/tiler/debug_utils.h @@ -0,0 +1,211 @@ +/* + * debug_utils.h + * + * Debug Utility definitions. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEBUG_UTILS_H_ +#define _DEBUG_UTILS_H_ + +#include <stdio.h> + +/*#define __DEBUG__*/ +/*#define __DEBUG_ENTRY__*/ +/*#define __DEBUG_ASSERT__*/ + +/* ---------- Generic Debug Print Macros ---------- */ + +/** + * Use as: + * P("val is %d", 5); + * ==> val is 5 + * DP("val is %d", 15); + * ==> val is 5 at test.c:56:main() + */ +/* debug print (fmt must be a literal); adds new-line. */ +#define __DEBUG_PRINT(fmt, ...) do { fprintf(stdout, fmt "\n", ##__VA_ARGS__); fflush(stdout); } while(0) + +/* debug print with context information (fmt must be a literal) */ +#define __DEBUG_DPRINT(fmt, ...) __DEBUG_PRINT(fmt " at %s(" __FILE__ ":%d)", ##__VA_ARGS__, __FUNCTION__, __LINE__) + +#ifdef __DEBUG__ +#define P(fmt, ...) __DEBUG_PRINT(fmt, ##__VA_ARGS__) +#define DP(fmt, ...) __DEBUG_DPRINT(fmt, ##__VA_ARGS__) +#else +#define P(fmt, ...) +#define DP(fmt, ...) +#endif + +/* ---------- Program Flow Debug Macros ---------- */ + +/** + * Use as: + * int get5() { + * IN; + * return R_I(5); + * } + * void check(int i) { + * IN; + * if (i == 5) { RET; return; } + * OUT; + * } + * void main() { + * IN; + * check(get5()); + * check(2); + * OUT; + * } + * ==> + * in main(test.c:11) + * in get5(test.c:2) + * out(5) at get5(test.c:3) + * in check(test.c:6) + * out() at check(test.c:7) + * in check(test.c:6) + * out check(test.c:8) + * out main(test.c:14) + */ + +#ifdef __DEBUG_ENTRY__ +/* function entry */ +#define IN __DEBUG_PRINT("in %s(" __FILE__ ":%d)", __FUNCTION__, __LINE__) +/* function exit */ +#define OUT __DEBUG_PRINT("out %s(" __FILE__ ":%d)", __FUNCTION__, __LINE__) +/* function abort (return;) Use as { RET; return; } */ +#define RET __DEBUG_DPRINT("out() ") +/* generic function return */ +#define R(val,type,fmt) ({ type __val__ = (type) val; __DEBUG_DPRINT("out(" fmt ")", __val__); __val__; }) +#else +#define IN +#define OUT +#define RET +#define R(val,type,fmt) (val) +#endif + +/* integer return */ +#define R_I(val) R(val,int,"%d") +/* pointer return */ +#define R_P(val) R(val,void *,"%p") +/* long return */ +#define R_UP(val) R(val,long,"0x%lx") + +/* ---------- Assertion Debug Macros ---------- */ + +/** + * Use as: + * int i = 5; + * // int j = i * 5; + * int j = A_I(i,==,3) * 5; + * // if (i > 3) P("bad") + * if (NOT_I(i,<=,3)) P("bad") + * P("j is %d", j); + * ==> assert: i (=5) !== 3 at test.c:56:main() + * assert: i (=5) !<= 3 at test.c:58:main() + * j is 25 + * + */ +/* generic assertion check, A returns the value of exp, CHK return void */ +#ifdef __DEBUG_ASSERT__ +#define A(exp,cmp,val,type,fmt) ({ \ + type __exp__ = (type) (exp); type __val__ = (type) (val); \ + if (!(__exp__ cmp __val__)) __DEBUG_DPRINT("assert: %s (=" fmt ") !" #cmp " " fmt, #exp, __exp__, __val__); \ + __exp__; \ +}) +#define CHK(exp,cmp,val,type,fmt) do { \ + type __exp__ = (type) (exp); type __val__ = (type) (val); \ + if (!(__exp__ cmp __val__)) __DEBUG_DPRINT("assert: %s (=" fmt ") !" #cmp " " fmt, #exp, __exp__, __val__); \ +} while(0) +#else +#define A(exp,cmp,val,type,fmt) (exp) +#define CHK(exp,cmp,val,type,fmt) +#endif + +/* typed assertions */ +#define A_I(exp,cmp,val) A(exp,cmp,val,int,"%d") +#define A_L(exp,cmp,val) A(exp,cmp,val,long,"%ld") +#define A_P(exp,cmp,val) A(exp,cmp,val,void *,"%p") +#define CHK_I(exp,cmp,val) CHK(exp,cmp,val,int,"%d") +#define CHK_L(exp,cmp,val) CHK(exp,cmp,val,long,"%ld") +#define CHK_P(exp,cmp,val) CHK(exp,cmp,val,void *,"%p") + +/* generic assertion check, returns true iff assertion fails */ +#ifdef __DEBUG_ASSERT__ +#define NOT(exp,cmp,val,type,fmt) ({ \ + type __exp__ = (type) (exp); type __val__ = (type) (val); \ + if (!(__exp__ cmp __val__)) __DEBUG_DPRINT("assert: %s (=" fmt ") !" #cmp " " fmt, #exp, __exp__, __val__); \ + !(__exp__ cmp __val__); \ +}) +#else +#define NOT(exp,cmp,val,type,fmt) (!((exp) cmp (val))) +#endif + +/* typed assertion checks */ +#define NOT_I(exp,cmp,val) NOT(exp,cmp,val,int,"%d") +#define NOT_L(exp,cmp,val) NOT(exp,cmp,val,long,"%ld") +#define NOT_P(exp,cmp,val) NOT(exp,cmp,val,void *,"%p") + + +/* system assertions - will use perror to give external error information */ +#ifdef __DEBUG_ASSERT__ +#define ERR_S(fmt, ...) do { fprintf(stderr, fmt " at %s(" __FILE__ ":%d", ##__VA_ARGS__, __FUNCTION__, __LINE__); perror(")"); fflush(stderr); } while(0) +#define A_S(exp,cmp,val) ({ \ + int __exp__ = (int) (exp); int __val__ = (int) (val); \ + if (!(__exp__ cmp __val__)) ERR_S("assert: %s (=%d) !" #cmp " %d", #exp, __exp__, __val__); \ + __exp__; \ +}) +#define CHK_S(exp,cmp,val) do { \ + int __exp__ = (int) (exp); int __val__ = (int) (val); \ + if (!(__exp__ cmp __val__)) ERR_S("assert: %s (=%d) !" #cmp " %d", #exp, __exp__, __val__); \ +} while(0) +#define NOT_S(exp,cmp,val) ({ \ + int __exp__ = (int) (exp); int __val__ = (int) (val); \ + if (!(__exp__ cmp __val__)) ERR_S("assert: %s (=%d) !" #cmp " %d", #exp, __exp__, __val__); \ + !(__exp__ cmp __val__); \ +}) +#else +#define A_S(exp,cmp,val) (exp) +#define CHK_S(exp,cmp,val) +#define NOT_S(exp,cmp,val) (!((exp) cmp (val))) +#endif + +/* error propagation macros - these macros ensure evaluation of the expression + even if there was a prior error */ + +/* new error is accumulated into error */ +#define ERR_ADD(err, exp) do { int __error__ = A_I(exp,==,0); err = err ? err : __error__; } while(0) +#define ERR_ADD_S(err, exp) do { int __error__ = A_S(exp,==,0); err = err ? err : __error__; } while(0) +/* new error overwrites old error */ +#define ERR_OVW(err, exp) do { int __error__ = A_I(exp,==,0); err = __error__ ? __error__ : err; } while(0) +#define ERR_OVW_S(err, exp) do { int __error__ = A_S(exp,==,0); err = __error__ ? __error__ : err; } while(0) + +#endif + diff --git a/tiler/fill_utr.py b/tiler/fill_utr.py new file mode 100755 index 0000000..d006298 --- /dev/null +++ b/tiler/fill_utr.py @@ -0,0 +1,92 @@ +# Use this script to fill out the UTR for MemMgr/D2C tests. You can use
+# either Python 2.6 or 3.1
+#
+# Limitations:
+# - only basic tests run by memmgr_test and d2c_test are filled out
+# - negative memmgr_tests are performed in one step and this script will
+# not separate which part of the test failed. If your negative memmgr
+# tests fail, you want to manually check which test case failed.
+
+# Usage:
+# 1. run memmgr_test and d2c_test, and pipe the output of the tests into a
+# file.
+#
+# memmgr_test > test.log
+# d2c_test >> test.log
+#
+# 2. open UTR and select Tiler/D2C User Space worksheet
+# 3. run this script by piping the test logs into the script, e.g.
+# python fill_utr.py < test.log
+
+import sys, re, win32com.client
+
+TCs, results = [], {}
+
+# gather test results from the log
+for line in sys.stdin:
+ # check for test description
+ desc = re.search("TEST #... - (.*)", line.strip())
+ if desc:
+ TCs.append(desc.group(1))
+
+ # check for any test result
+ result = re.search("==> TEST (.*)", line.strip())
+ if result:
+ result = result.group(1)
+ if result == 'OK':
+ result = 'P', ''
+ elif result == 'NOT AVAILABLE':
+ result = 'D', ''
+ else:
+ result = 'F', 'failed with error #' + result[5:-1]
+
+ results[TCs.pop(0)] = result
+
+assert "test_d2c(1920, 1080, 2)" in results
+
+# populate test results
+excel = win32com.client.Dispatch('Excel.Application')
+if not excel:
+ print('Could not find Excel application. The UTR is probably not open in Excel.')
+ sys.exit(1)
+
+sheet = excel.ActiveSheet
+if sheet.Name != 'Tiler' or sheet.Cells(1,1).Text != 'Test Metrics':
+ print('Active worksheet does not seem to be the Tiler UTR')
+ sys.exit(1)
+
+# find Header
+for r in range(1, 100):
+ if sheet.Cells(r, 1).Text == 'Test Case\nID':
+ break
+else:
+ print('Could not find header row starting with "Test Case\\nID"')
+ sys.exit(1)
+
+# find Status, Details and Comments columns
+heads = t_status, t_details, t_comments, t_desc = 'Status', 'Details', 'Comments', 'Test Case\nDescription'
+heads = set(heads)
+cols = {}
+for c in range(1, 100):
+ if sheet.Cells(r, c).Text in heads:
+ cols[sheet.Cells(r, c).Text] = c
+ heads.remove(sheet.Cells(r, c).Text)
+if heads:
+ print('Could not find columns', heads)
+ sys.exit(1)
+
+# populate sheet, quit after 20 empty Details/Description cells
+empties = 0
+while empties < 20:
+ r += 1
+ details = sheet.Cells(r, cols[t_details]).Text
+ if details:
+ empties = 0
+ # get test case description
+ desc = details.split('\n')[-1]
+ if not desc in results:
+ results[desc] = 'U', ''
+ sheet.Cells(r, cols[t_status]).Value, sheet.Cells(r, cols[t_comments]).Value = results[desc]
+ elif not sheet.Cells(r, cols[t_desc]).Text:
+ empties += 1
+
diff --git a/tiler/libtimemmgr.pc.in b/tiler/libtimemmgr.pc.in new file mode 100644 index 0000000..7ecd886 --- /dev/null +++ b/tiler/libtimemmgr.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: timemmgr +Description: TI memory manager +Version: @VERSION@ +Requires: +Libs: -L${libdir} -ltimemmgr +Cflags: -I${includedir}/timemmgr + + diff --git a/tiler/list_utils.h b/tiler/list_utils.h new file mode 100644 index 0000000..1643cf0 --- /dev/null +++ b/tiler/list_utils.h @@ -0,0 +1,511 @@ +/* + * list_utils.h + * + * Utility definitions for the Memory Interface for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LIST_UTILS_H_ +#define _LIST_UTILS_H_ + +/* + + DLIST macros facilitate double-linked lists in a generic fashion. + + - Double-linked lists simplify list manipulations, so they are preferred to + single-linked lists. + + - Having a double-linked list with a separate header allow accessing the + last element of the list easily, so this is also preferred to a double + linked list that uses NULL pointers at its ends. + + Therefore, the following is required: a list info structure (separate from + the element structure, although the info structure can be a member of the + element structure). The info structure must contain (at least) the + following 3 members: + + *next, *last: as pointers to the info structure. These are the next and + previous elements in the list. + *me: as a pointer to the element structure. This is how we get to the + element itself, as next and last points to another info structure. + + The list element structure __MAY__ contain the info structure as a member, + or a pointer to the info structure if it is desired to be kept separately. + In such cases macros are provided to add the elements directly to the list, + and automatically set up the info structure fields correctly. You can also + iterate through the elements of the list using a pointer to the elements + itself, as the list structure can be obtained for each element. + + Otherwise, macros are provided to manipulate list info structures and + link them in any shape or form into double linked lists. This allows + having NULL values as members of such lists. + + :NOTE: If you use a macro with a field argument, you must not have NULL + elements because the field of any element must be/point to the list + info structure + + DZLIST macros + + Having the list info structure separate from the element structure also + allows to link elements into many separate lists (with separate info + structure fields/pointers). However, for cases where only a single list + is desired, a set of easy macros are also provided. + + These macros combine the element and list structures. These macros + require the following 2 members in each element structure: + + *next, *last: as pointers to the element structure. These are the next and + previous elements in the list. + + :NOTE: In case of the DZLIST-s, the head of the list must be an element + structure, where only the next and last members are used. */ + +/* + Usage: + + DLIST macros are designed for preallocating the list info structures, e.g. in + an array. This is why most macros take a list info structure, and not a + pointer to a list info structure. + + Basic linked list consists of element structure and list info structure + + struct elem { + int data; + } *elA, *elB; + struct list { + struct elem *me; + struct list *last, *next; + } head, *inA, *inB, *in; + + DLIST_INIT(head); // initialization -> () + DLIST_IS_EMPTY(head) == TRUE; // emptiness check + + // add element at beginning of list -> (1) + elA = NEW(struct elem); + elA->data = 1; + inA = NEW(struct list); + DLIST_ADD_AFTER(head, elA, *inA); + + // add before an element -> (2, 1) + elB = NEW(struct elem); + elB->data = 2; + inB = NEW(struct list); + DLIST_ADD_BEFORE(*inA, elB, *inB); + + // move an element to another position or another list -> (1, 2) + DLIST_MOVE_BEFORE(head, *inB); + + // works even if the position is the same -> (1, 2) + DLIST_MOVE_BEFORE(head, *inB); + + // get first and last elements + DLIST_FIRST(head) == elA; + DLIST_LAST(head) == elB; + + // loop through elements + DLIST_LOOP(head, in) { + P("%d", in->me->data); + } + + // remove element -> (2) + DLIST_REMOVE(*inA); + FREE(elA); + FREE(inA); + + // delete list + DLIST_SAFE_LOOP(head, in, inA) { + DLIST_REMOVE(*in); + FREE(in->me); + FREE(in); + } + + You can combine the element and list info structures to create an easy list, + but you still need to specify both element and info structure while adding + elements. + + struct elem { + int data; + struct elem *me, *last, *next; + } head, *el, *elA, *elB; + + DLIST_INIT(head); // initialization -> () + DLIST_IS_EMPTY(head) == TRUE; // emptiness check + + // add element at beginning of list -> (1) + elA = NEW(struct elem); + elA->data = 1; + DLIST_ADD_AFTER(head, elA, *elA); + + // add before an element -> (2, 1) + elB = NEW(struct elem); + elB->data = 2; + DLIST_ADD_BEFORE(*elA, elB, *elB); + + // move an element to another position or another list -> (1, 2) + DLIST_MOVE_BEFORE(head, *elB); + + // works even if the position is the same -> (1, 2) + DLIST_MOVE_BEFORE(head, *elB); + + // get first and last elements + DLIST_FIRST(head) == elA; + DLIST_LAST(head) == elB; + + // loop through elements + DLIST_LOOP(head, el) { + P("%d", el->data); + } + + // remove element -> (2) + DLIST_REMOVE(*elA); + FREE(elA); + + // delete list + DLIST_SAFE_LOOP(head, el, elA) { + DLIST_REMOVE(*el); + FREE(el); + } + + Or, you can use a DZLIST. + + struct elem { + int data; + struct elem *last, *next; + } head, *el, *elA, *elB; + + DZLIST_INIT(head); // initialization -> () + DZLIST_IS_EMPTY(head) == TRUE; // emptiness check + + // add element at beginning of list -> (1) + elA = NEW(struct elem); + elA->data = 1; + DZLIST_ADD_AFTER(head, *elA); + + // add before an element -> (2, 1) + elB = NEW(struct elem); + elB->data = 2; + DZLIST_ADD_BEFORE(*elA, *elB); + + // move an element to another position or another list -> (1, 2) + DZLIST_MOVE_BEFORE(head, *elB); + + // works even if the position is the same -> (1, 2) + DZLIST_MOVE_BEFORE(head, *elB); + + // get first and last elements + DZLIST_FIRST(head) == elA; + DZLIST_LAST(head) == elB; + + // loop through elements + DZLIST_LOOP(head, el) { + P("%d", el->data); + } + + // remove element -> (2) + DZLIST_REMOVE(*elA); + FREE(elA); + + // delete list + DZLIST_SAFE_LOOP(head, el, elA) { + DZLIST_REMOVE(*el); + FREE(el); + } + + A better way to get to the list structure from the element structure is to + enclose a pointer the list structure in the element structure. This allows + getting to the next/previous element from the element itself. + + struct elem; + struct list { + struct elem *me; + struct list *last, *next; + } head, *inA, *inB, *in; + struct elem { + int data; + struct list *list_data; + } *elA, *elB, *el; + + // or + + struct elem { + int data; + struct list { + struct elem *me; + struct list *last, *next; + } *list_data; + } *elA, *elB, *el; + struct list head, *inA, *inB, *in; + + DLIST_INIT(head); // initialization -> () + DLIST_IS_EMPTY(head) == TRUE; // emptiness check + + // add element at beginning of list -> (1) + elA = NEW(struct elem); + elA->data = 1; + inA = NEW(struct list); + DLIST_PADD_AFTER(head, elA, inA, list_data); + + // add before an element -> (2, 1) + elB = NEW(struct elem); + elB->data = 2; + inB = NEW(struct list); + DLIST_PADD_BEFORE(*elA, elB, inB, list_data); + + // move an element to another position or another list -> (1, 2) + DLIST_MOVE_BEFORE(head, *inB); + + // works even if the position is the same -> (1, 2) + DLIST_MOVE_BEFORE(head, *inB); + + // get first and last elements + DLIST_FIRST(head) == elA; + DLIST_LAST(head) == elB; + + // loop through elements + DLIST_LOOP(head, in) { + P("%d", in->me->data); + } + DLIST_PLOOP(head, el, list_data) { + P("%d", el->data); + } + + // remove element + DLIST_REMOVE(*inA); + FREE(inA); + FREE(elA); + + // delete list + DLIST_SAFE_PLOOP(head, el, elA, list_data) { + DLIST_REMOVE(*el->list_data); + FREE(el->list_data); + FREE(el); + } + + Lastly, you can include the list data in the element structure itself. + + struct elem { + int data; + struct list { + struct list *last, *next; + struct elem *me; + } list_data; + } *elA, *elB, *el; + struct list head, *in; + + DLIST_INIT(head); // initialization -> () + DLIST_IS_EMPTY(head) == TRUE; // emptiness check + + // add element at beginning of list -> (1) + elA = NEW(struct elem); + elA->data = 1; + DLIST_MADD_AFTER(head, elA, list_data); + + // add before an element -> (2, 1) + elB = NEW(struct elem); + elB->data = 2; + DLIST_PADD_BEFORE(elA->list_data, elB, list_data); + + // move an element to another position or another list -> (1, 2) + DLIST_MOVE_BEFORE(head, elB->list_data); + + // works even if the position is the same -> (1, 2) + DLIST_MOVE_BEFORE(head, elB->list_data); + + // get first and last elements + DLIST_FIRST(head) == elA; + DLIST_LAST(head) == elB; + + // loop through elements + DLIST_LOOP(head, in) { + P("%d", in->me->data); + } + DLIST_MLOOP(head, el, list_data) { + P("%d", el->data); + } + + // remove element + DLIST_REMOVE(elA->list_data); + FREE(elA); + + // delete list + DLIST_SAFE_MLOOP(head, el, elA, list_data) { + DLIST_REMOVE(el->list_data); + FREE(el); + } + + */ + +/* -- internal (generic direction) macros -- */ +#define DLIST_move__(base, info, next, last) \ + ((info).last = &base)->next = ((info).next = (base).next)->last = &(info) +#define DLIST_padd__(base, pInfo, pElem, pField, next, last) \ + ((pInfo)->last = &base)->next = ((pInfo)->next = (base).next)->last = \ + pElem->pField = pInfo +#define DLIST_loop__(head, pInfo, next) \ + for (pInfo=(head).next; pInfo != &(head); pInfo = (pInfo)->next) +#define DLIST_ploop__(head, pElem, pField, next) \ + for (pElem=(head).next->me; pElem; pElem = (pElem)->pField->next->me) +#define DLIST_mloop__(head, pElem, mField, next) \ + for (pElem=(head).next->me; pElem; pElem = (pElem)->mField.next->me) +#define DLIST_safe_loop__(head, pInfo, pInfo_safe, next) \ + for (pInfo=(head).next; pInfo != &(head); pInfo = pInfo_safe) \ + if ((pInfo_safe = (pInfo)->next) || 1) +#define DLIST_safe_ploop__(head, pElem, pElem_safe, pField, next) \ + for (pElem=(head).next->me; pElem; pElem = pElem_safe) \ + if ((pElem_safe = (pElem)->pField->next->me) || 1) +#define DLIST_safe_mloop__(head, pElem, pElem_safe, mField, next) \ + for (pElem=(head).next->me; pElem; pElem = pElem_safe) \ + if ((pElem_safe = (pElem)->mField.next->me) || 1) + +#define DLIST_IS_EMPTY(head) ((head).next == &(head)) + +/* Adds the element (referred to by the info structure) before/or after another + element (or list header) (base). */ + +#define DLIST_ADD_AFTER(base, pElem, info) \ + (DLIST_move__(base, info, next, last))->me = pElem +#define DLIST_ADD_BEFORE(base, pElem, info) \ + (DLIST_move__(base, info, last, next))->me = pElem + +/* Adds the element (referred to by pElem pointer) along with its info + structure (referred to by pInfo pointer) before/or after an element or + list header (base). It also sets up the list structure header to point to + the element as well as the element's field to point back to the list info + structure. */ +#define DLIST_PADD_BEFORE(base, pElem, pInfo, pField) \ + (DLIST_padd__(base, pInfo, pElem, pField, last, next))->me = pElem +#define DLIST_PADD_AFTER(base, pElem, pInfo, pField) \ + (DLIST_padd__(base, pInfo, pElem, pField, next, last))->me = pElem + +/* Adds the element (referred to by pElem pointer) before/or after an element or + list header (base). It also sets up the list structure header (which is a + member of the element's structure) to point to the element. */ +#define DLIST_MADD_BEFORE(base, pElem, mField) \ + (DLIST_move__(base, pElem->mField, last, next))->me = pElem +#define DLIST_MADD_AFTER(base, pElem, mField) \ + (DLIST_move__(base, pElem->mField, next, last))->me = pElem + +/* Removes the element (referred to by the info structure) from its current + list. This requires that the element is a part of a list. + + :NOTE: the info structure will still think that it belongs to the list it + used to belong to. However, the old list will not contain this element any + longer. You want to discard the info/element after this call. Otherwise, + you can use one of the MOVE macros to also add the item to another list, + or another place in the same list. */ +#define DLIST_REMOVE(info) ((info).last->next = (info).next)->last = (info).last + +/* Initializes the list header (to an empty list) */ +#define DLIST_INIT(head) \ + do { (head).me = NULL; (head).next = (head).last = &(head); } while(0) + +/* These functions move an element (referred to by the info structure) before + or after another element (or the list head). + :NOTE: This logic also works for moving an element after/before itself. */ +#define DLIST_MOVE_AFTER(base, info) \ + do { DLIST_REMOVE(info); DLIST_move__(base, info, next, last); } while(0) +#define DLIST_MOVE_BEFORE(base, info) \ + do { DLIST_REMOVE(info); DLIST_move__(base, info, last, next); } while(0) + +/* Loops behave syntactically as a for() statement. They traverse the loop + variable from the 1st to the last element (or in the opposite direction in + case of RLOOP). There are 3 flavors of loops depending on the type of the + loop variable. + + DLIST_LOOP's loop variable is a pointer to the list info structure. You can + get to the element by using the 'me' member. Nonetheless, this loop + construct allows having NULL elements in the list. + + DLIST_MLOOP's loop variable is a pointer to a list element. mField is the + field of the element containing the list info structure. Naturally, this + list cannot have NULL elements. + + DLIST_PLOOP's loop variable is also a pointer to a list element. Use this + construct if the element contains a pointer to the list info structure + instead of embedding it directly into the element structure. + +*/ +#define DLIST_LOOP(head, pInfo) DLIST_loop__(head, pInfo, next) +#define DLIST_RLOOP(head, pInfo) DLIST_loop__(head, pInfo, last) +#define DLIST_MLOOP(head, pElem, mField) \ + DLIST_mloop__(head, pElem, mField, next) +#define DLIST_RMLOOP(head, pElem, mField) \ + DLIST_mloop__(head, pElem, mField, last) +#define DLIST_PLOOP(head, pElem, pField) \ + DLIST_ploop__(head, pElem, pField, next) +#define DLIST_RPLOOP(head, pElem, pField) \ + DLIST_ploop__(head, pElem, pField, last) + +/* Safe loops are like ordinary loops, but they allow removal of the current + element from the list. They require an extra loop variable that holds the + value of the next element in case the current element is moved/removed. */ +#define DLIST_SAFE_LOOP(head, pInfo, pInfo_safe) \ + DLIST_safe_loop__(head, pInfo, pInfo_safe, next) +#define DLIST_SAFE_RLOOP(head, pInfo, pInfo_safe) \ + DLIST_safe_loop__(head, pInfo, pInfo_safe, last) +#define DLIST_SAFE_MLOOP(head, pElem, pElem_safe, mField) \ + DLIST_safe_mloop__(head, pElem, pElem_safe, mField, next) +#define DLIST_SAFE_RMLOOP(head, pElem, pElem_safe, mField) \ + DLIST_safe_mloop__(head, pElem, pElem_safe, mField, last) +#define DLIST_SAFE_PLOOP(head, pElem, pElem_safe, pField) \ + DLIST_safe_ploop__(head, pElem, pElem_safe, pField, next) +#define DLIST_SAFE_RPLOOP(head, pElem, pElem_safe, pField) \ + DLIST_safe_ploop__(head, pElem, pElem_safe, pField, last) + +/* returns the first element of a list */ +#define DLIST_FIRST(head) (head).next->me +/* returns the last element of a list */ +#define DLIST_LAST(head) (head).last->me + + +/* DZLIST equivalent API - provided so arguments are specified */ +#define DZLIST_INIT(head) do { (head).next = (head).last = &(head); } while(0) +#define DZLIST_IS_EMPTY(head) DLIST_IS_EMPTY(head) +#define DZLIST_FIRST(head) (head).next +#define DZLIST_LAST(head) (head).last + +#define DZLIST_ADD_AFTER(base, elem) DLIST_move__(base, elem, next, last) +#define DZLIST_ADD_BEFORE(base, elem) DLIST_move__(base, elem, last, next) + +#define DZLIST_REMOVE(elem) DLIST_REMOVE(elem) + +#define DZLIST_MOVE_AFTER(base, elem) DLIST_MOVE_AFTER(base, elem) +#define DZLIST_MOVE_BEFORE(base, elem) DLIST_MOVE_BEFORE(base, elem) + +#define DZLIST_LOOP(head, pElem) DLIST_LOOP(head, pElem) +#define DZLIST_RLOOP(head, pElem) DLIST_RLOOP(head, pElem) +#define DZLIST_SAFE_LOOP(head, pElem, pElem_safe) \ + DLIST_SAFE_LOOP(head, pElem, pElem_safe) +#define DZLIST_SAFE_RLOOP(head, pElem, pElem_safe) \ + DLIST_SAFE_RLOOP(head, pElem, pElem_safe) + +#endif + diff --git a/tiler/mem_types.h b/tiler/mem_types.h new file mode 100644 index 0000000..18453bb --- /dev/null +++ b/tiler/mem_types.h @@ -0,0 +1,101 @@ +/* + * types.h + * + * Type definitions for the Memory Interface for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MEM_TYPES_H_ +#define _MEM_TYPES_H_ + +/* for bool definition */ +#include <stdbool.h> +#include <stdint.h> + +/** --------------------------------------------------------------------------- + * Type definitions + */ + +/** + * Buffer length in bytes + */ +typedef uint32_t bytes_t; + +/** + * Length in pixels + */ +typedef uint16_t pixels_t; + + +/** + * Pixel format + * + * Page mode is encoded in the pixel format to handle different + * set of buffers uniformly + */ +enum pixel_fmt_t { + PIXEL_FMT_MIN = 0, + PIXEL_FMT_8BIT = 0, + PIXEL_FMT_16BIT = 1, + PIXEL_FMT_32BIT = 2, + PIXEL_FMT_PAGE = 3, + PIXEL_FMT_MAX = 3 +}; + +typedef enum pixel_fmt_t pixel_fmt_t; + +/** + * Ducati Space Virtual Address Pointer + * + * This is handled as a unsigned long so that no dereferencing + * is allowed by user space components. + */ +typedef uint32_t DSPtr; + +/** + * System Space Pointer + * + * This is handled as a unsigned long so that no dereferencing + * is allowed by user space components. + */ +typedef uint32_t SSPtr; + +/** + * Error values + * + * Page mode is encoded in the pixel format to handle different + * set of buffers uniformly + */ +#define MEMMGR_ERR_NONE 0 +#define MEMMGR_ERR_GENERIC 1 + +#endif + diff --git a/tiler/memmgr.c b/tiler/memmgr.c new file mode 100644 index 0000000..1f780cc --- /dev/null +++ b/tiler/memmgr.c @@ -0,0 +1,1078 @@ +/* + * memmgr.c + * + * Memory Allocator Interface functions for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> +#include <errno.h> + +#define BUF_ALLOCED 1 +#define BUF_MAPPED 2 +#define BUF_ANY ~0 + +#include <tiler.h> + +typedef struct tiler_block_info tiler_block_info; + +#define __DEBUG__ +#undef __DEBUG_ENTRY__ +#define __DEBUG_ASSERT__ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif +#include "utils.h" +#include "list_utils.h" +#include "debug_utils.h" +#include "tilermem.h" +#include "tilermem_utils.h" +#include "memmgr.h" + +/* list of allocations */ +struct _AllocData { + struct tiler_buf_info buf; + int buf_type; + struct _AllocList { + struct _AllocList *next, *last; + struct _AllocData *me; + } link; +}; +static struct _AllocList bufs = {0}; +static int bufs_inited = 0; + +typedef struct _AllocList _AllocList; +typedef struct _AllocData _AllocData; + +static int refCnt = 0; +static int td = -1; +static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t che_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Initializes the static structures + * + * @author a0194118 (9/8/2009) + */ +static void init() +{ + if (!bufs_inited) + { + DLIST_INIT(bufs); + bufs_inited = 1; + } +} + +/** + * Increases the reference count. Initialized tiler if this was + * the first reference + * + * @author a0194118 (9/2/2009) + * + * @return 0 on success, non-0 error value on failure. + */ +static int inc_ref() +{ + /* initialize tiler on first call */ + pthread_mutex_lock(&ref_mutex); + + int res = MEMMGR_ERR_NONE; + + if (!refCnt++) { + /* initialize lists */ + init(); +#ifndef STUB_TILER + td = open("/dev/tiler", O_RDWR | O_SYNC); + if (NOT_I(td,>=,0)) res = MEMMGR_ERR_GENERIC; +#else + td = 2; + res = MEMMGR_ERR_NONE; +#endif + } + if (res) + { + refCnt--; + } + + pthread_mutex_unlock(&ref_mutex); + return res; +} + +/** + * Decreases the reference count. Deinitialized tiler if this + * was the last reference + * + * @author a0194118 (9/2/2009) + * + * @return 0 on success, non-0 error value on failure. + */ +static int dec_ref() +{ + pthread_mutex_lock(&ref_mutex); + + int res = MEMMGR_ERR_NONE;; + + if (refCnt <= 0) res = MEMMGR_ERR_GENERIC; + else if (!--refCnt) { +#ifndef STUB_TILER + close(td); + td = -1; +#endif + } + + pthread_mutex_unlock(&ref_mutex); + return res; +} + +/** + * Returns the default page stride for this block + * + * @author a0194118 (9/4/2009) + * + * @param width Width of 2D container in bytes + * + * @return Stride + */ +static bytes_t def_stride(bytes_t width) +{ + return ROUND_UP_TO2POW(width, PAGE_SIZE); +} + +/** + * Returns the bytes per pixel for the pixel format. + * + * @author a0194118 (9/4/2009) + * + * @param pixelFormat Pixelformat + * + * @return Bytes per pixel + */ +static bytes_t def_bpp(pixel_fmt_t pixelFormat) +{ + return (pixelFormat == PIXEL_FMT_32BIT ? 4 : + pixelFormat == PIXEL_FMT_16BIT ? 2 : 1); +} + +/** + * Returns the size of the supplied block + * + * @author a0194118 (9/4/2009) + * + * @param blk Pointer to the tiler_block_info struct + * + * @return size of the block in bytes + */ +static bytes_t def_size(tiler_block_info *blk) +{ + return (blk->fmt == PIXEL_FMT_PAGE ? + def_stride(blk->dim.len) : + blk->dim.area.height * def_stride(blk->dim.area.width * def_bpp(blk->fmt))); +} + +/** + * Returns the map size based on an offset and buffer size + * + * @author a0194118 (7/8/2010) + * + * @param size Size of buffer + * @param offs Buffer offset + * + * @return (page aligned) size for mapping + */ +static bytes_t map_size(bytes_t size, bytes_t offs) +{ + return def_stride(size + (offs & (PAGE_SIZE - 1))); +} + +/** + * Records a buffer-pointer -- tiler-ID mapping for a specific + * buffer type. + * + * @author a0194118 (9/7/2009) + * + * @param bufPtr Buffer pointer + * @param tiler_id Tiler ID + * @param buf_type Buffer type: BUF_ALLOCED or BUF_MAPPED + * + * @return 0 on success, -ENOMEM on memory allocation failure + */ +static int buf_cache_add(struct tiler_buf_info *buf, int buf_type) +{ + pthread_mutex_lock(&che_mutex); + _AllocData *ad = NEW(_AllocData); + if (ad) + { + memcpy(&ad->buf, buf, sizeof(ad->buf)); + ad->buf_type = buf_type; + DLIST_MADD_BEFORE(bufs, ad, link); + } + pthread_mutex_unlock(&che_mutex); + return ad == NULL ? -ENOMEM : 0; +} + +/** + * Retrieves the tiler ID for given pointer and buffer type from + * the records. If the pointer lies within a tracked buffer, + * the tiler ID is returned. Otherwise 0 is returned. + * + * @author a0194118 (9/7/2009) + * + * @param bufPtr Buffer pointer + * @param buf_type Buffer type: BUF_ALLOCED or BUF_MAPPED + * + * @return Tiler ID on success, 0 on failure. + */ +static void buf_cache_query(void *ptr, struct tiler_buf_info *buf, + int buf_type_mask) +{ + IN; + if(0) DP("in(p=%p,t=%d,bp*=%p)", ptr, buf_type_mask, buf->blocks[0].ptr); + _AllocData *ad; + pthread_mutex_lock(&che_mutex); + DLIST_MLOOP(bufs, ad, link) { + if(0) { + DP("got(%p-%p,%d)", ad->buf.blocks->ptr, ad->buf.blocks->ptr + ad->buf.length, ad->buf_type); + CHK_P(ad->buf.blocks->ptr,<=,ptr); + CHK_P(ptr,<,ad->buf.blocks->ptr + ad->buf.length); + CHK_I(ad->buf_type & buf_type_mask,!=,0); + CHK_P(buf->blocks->ptr,!=,0); + } + if ((ad->buf_type & buf_type_mask) && + ad->buf.blocks->ptr <= ptr && ptr < ad->buf.blocks->ptr + ad->buf.length) { + memcpy(buf, &ad->buf, sizeof(*buf)); + pthread_mutex_unlock(&che_mutex); + return; + } + } + pthread_mutex_unlock(&che_mutex); + ZERO(*buf); + OUT; +} + +/** + * Retrieves the tiler ID for given buffer pointer and buffer + * type from the records. If the tiler ID is found, it is + * removed from the records as well. + * + * @author a0194118 (9/7/2009) + * + * @param bufPtr Buffer pointer + * @param buf_type Buffer type: BUF_ALLOCED or BUF_MAPPED + * + * @return Tiler ID on success, 0 on failure. + */ +static void buf_cache_del(void *bufPtr, struct tiler_buf_info *buf, + int buf_type) +{ + _AllocData *ad; + pthread_mutex_lock(&che_mutex); + DLIST_MLOOP(bufs, ad, link) { + if (ad->buf.blocks->ptr == bufPtr && ad->buf_type == buf_type) { + memcpy(buf, &ad->buf, sizeof(*buf)); + DLIST_REMOVE(ad->link); + FREE(ad); + pthread_mutex_unlock(&che_mutex); + return; + } + } + pthread_mutex_unlock(&che_mutex); + OUT; + return; +} + +/** + * Checks the consistency of the internal record cache. The + * number of elements in the cache should equal to the number of + * references. + * + * @author a0194118 (9/7/2009) + * + * @return 0 on success, non-0 error value on failure. + */ +static int cache_check() +{ + int num_bufs = 0; + pthread_mutex_lock(&che_mutex); + + init(); + + _AllocData *ad; + DLIST_MLOOP(bufs, ad, link) { num_bufs++; } + + pthread_mutex_unlock(&che_mutex); + return (num_bufs == refCnt) ? MEMMGR_ERR_NONE : MEMMGR_ERR_GENERIC; +} + +static void dump_block(struct tiler_block_info *blk, char *prefix, char *suffix) +{ +#if 0 + switch (blk->fmt) + { + case TILFMT_PAGE: + P("%s [%d:(%d,%08x), p=%p(0x%x),l=0x%x,s=%d,%d+%d]%s", prefix, blk->group_id, blk->key, blk->id, blk->ptr, blk->ssptr, + blk->dim.len, blk->stride, blk->align, blk->offs, suffix); + break; + case TILFMT_8BIT: + case TILFMT_16BIT: + case TILFMT_32BIT: + P("%s [%d:(%d,%08x), p=%p(0x%x),%d*%d*%d,s=%d,%d+%d]%s", prefix, blk->group_id, blk->key, blk->id, blk->ptr, blk->ssptr, + blk->dim.area.width, blk->dim.area.height, def_bpp(blk->fmt) * 8, + blk->stride, blk->align, blk->offs, suffix); + break; + default: + P("%s*[%d:(%d,%08x), p=%p(0x%x),l=0x%x,s=%d,%d+%d,fmt=0x%x]%s", prefix, blk->group_id, blk->key, blk->id, blk->ptr, + blk->ssptr, blk->dim.len, blk->stride, blk->align, blk->offs, blk->fmt, suffix); + } +#endif +} + +static void dump_buf(struct tiler_buf_info* buf, char* prefix) +{ +#if 0 + P("%sbuf={n=%d,id=0x%x,len=0x%x", prefix, buf->num_blocks, buf->offset, buf->length); + int ix = 0; + for (ix = 0; ix < buf->num_blocks; ix++) + { + dump_block(buf->blocks + ix, "", ix + 1 == buf->num_blocks ? "}" : ""); + } +#endif +} + +/** + * Returns the tiler format for an address + * + * @author a0194118 (9/7/2009) + * + * @param ssptr Address + * + * @return The tiler format + */ +static enum tiler_fmt tiler_get_fmt(SSPtr ssptr) +{ +#ifndef STUB_TILER + return (ssptr == 0 ? TILFMT_INVALID : + ssptr < TILER_MEM_8BIT ? TILFMT_NONE : + ssptr < TILER_MEM_16BIT ? TILFMT_8BIT : + ssptr < TILER_MEM_32BIT ? TILFMT_16BIT : + ssptr < TILER_MEM_PAGED ? TILFMT_32BIT : + ssptr < TILER_MEM_END ? TILFMT_PAGE : TILFMT_NONE); +#else + /* if emulating, we need to get through all allocated memory segments */ + pthread_mutex_lock(&che_mutex); + init(); + _AllocData *ad; + void *ptr = (void *) ssptr; + if (!ptr) return TILFMT_INVALID; + /* P("?%p", (void *)ssptr); */ + DLIST_MLOOP(bufs, ad, link) { + int ix; + struct tiler_buf_info *buf = (struct tiler_buf_info *) ad->buf.offset; + /* P("buf[%d]", buf->num_blocks); */ + for (ix = 0; ix < buf->num_blocks; ix++) + { + /* P("block[%p-%p]", buf->blocks[ix].ptr, buf->blocks[ix].ptr + def_size(buf->blocks + ix)); */ + if (ptr >= buf->blocks[ix].ptr && + ptr < buf->blocks[ix].ptr + def_size(buf->blocks + ix)) { + enum tiler_fmt fmt = buf->blocks[ix].fmt; + pthread_mutex_unlock(&che_mutex); + return fmt; + } + } + } + pthread_mutex_unlock(&che_mutex); + return TILFMT_NONE; +#endif +} + + +/** + * Allocates a memory block using tiler + * + * @author a0194118 (9/7/2009) + * + * @param blk Pointer to the block info + * + * @return ssptr of block allocated, or 0 on error + */ +static int tiler_alloc(struct tiler_block_info *blk) +{ + dump_block(blk, "=(ta)=>", ""); + blk->ptr = NULL; + int ret = A_S(ioctl(td, TILIOC_GBLK, blk),==,0); + dump_block(blk, "alloced: ", ""); + return R_I(ret); +} + +/** + * Frees a memory block using tiler + * + * @author a0194118 (9/7/2009) + * + * @param blk Pointer to the block info + * + * @return 0 on success, non-0 error value on failure. + */ +static int tiler_free(struct tiler_block_info *blk) +{ + return R_I(ioctl(td, TILIOC_FBLK, blk)); +} + +/** + * Maps a memory block into tiler using tiler + * + * @author a0194118 (9/7/2009) + * + * @param blk Pointer to the block info + * + * @return ssptr of block mapped, or 0 on error + */ +static int tiler_map(struct tiler_block_info *blk) +{ + dump_block(blk, "=(tm)=>", ""); + int ret = A_S(ioctl(td, TILIOC_MBLK, blk),==,0); + dump_block(blk, "mapped: ", ""); + return R_I(ret); +} + +/** + * Unmaps a memory block from tiler using tiler + * + * @author a0194118 (9/7/2009) + * + * @param blk Pointer to the block info + * + * @return 0 on success, non-0 error value on failure. + */ +static int tiler_unmap(struct tiler_block_info *blk) +{ + return ioctl(td, TILIOC_UMBLK, blk); +} + +/** + * Registers a buffer structure with tiler, and maps the buffer + * into memory using tiler. On success, it writes the tiler ID + * of the buffer into the area pointed by tiler ID. + * + * @author a0194118 (9/7/2009) + * + * @param blks Pointer to array of block info structures + * @param num_blocks Number of blocks + * @param tiler_id Pointer to tiler ID. + * + * @return pointer to the mapped buffer. + */ +static void *tiler_mmap(struct tiler_block_info *blks, int num_blocks, + int buf_type) +{ + IN; + + /* get size */ + int ix; + bytes_t size; + + /* register buffer with tiler */ + struct tiler_buf_info buf; + buf.num_blocks = num_blocks; + /* work on copy in buf */ + memcpy(buf.blocks, blks, sizeof(tiler_block_info) * num_blocks); +#ifndef STUB_TILER + dump_buf(&buf, "==(RBUF)=>"); + int ret = ioctl(td, TILIOC_RBUF, &buf); + dump_buf(&buf, "<=(RBUF)=="); + if (NOT_I(ret,==,0)) return NULL; + size = buf.length; +#else + /* save buffer in stub */ + struct tiler_buf_info *buf_c = NEWN(struct tiler_buf_info,2); + buf.offset = (uint32_t) buf_c; +#endif + if (NOT_P(buf.offset,!=,0)) return NULL; + + /* map blocks to process space */ +#ifndef STUB_TILER + void *bufPtr = mmap(0, map_size(size, buf.offset), + PROT_READ | PROT_WRITE, MAP_SHARED, + td, buf.offset & ~(PAGE_SIZE - 1)); + if (bufPtr == MAP_FAILED){ + bufPtr = NULL; + } else { + bufPtr += buf.offset & (PAGE_SIZE - 1); + } + if(0) DP("ptr=%p", bufPtr); +#else + void *bufPtr = malloc(size + PAGE_SIZE - 1); + buf_c[1].blocks[0].ptr = bufPtr; + bufPtr = ROUND_UP_TO2POW(bufPtr, PAGE_SIZE); + /* P("<= [0x%x]", size); */ + + /* fill out pointers - this is needed for caching 1D/2D type */ + for (size = ix = 0; ix < num_blocks; ix++) + { + buf.blocks[ix].ptr = bufPtr ? bufPtr + size : bufPtr; + size += def_size(blks + ix); + } + + memcpy(buf_c, &buf, sizeof(struct tiler_buf_info)); +#endif + + if (bufPtr != NULL) + { + /* fill out pointers */ + for (size = ix = 0; ix < num_blocks; ix++) + { + buf.blocks[ix].ptr = bufPtr + size; + /* P(" [0x%p]", buf.blocks[ix].ptr); */ + size += def_size(blks + ix); +#ifdef STUB_TILER + buf.blocks[ix].ssptr = (uint32_t) buf.blocks[ix].ptr; +#else + CHK_I((buf.blocks[ix].ssptr & (PAGE_SIZE - 1)),==,((uint32_t) buf.blocks[ix].ptr & (PAGE_SIZE - 1))); +#endif + } + } + /* if failed to map: unregister buffer */ + if (NOT_P(bufPtr,!=,NULL) || + /* or failed to cache tiler buffer */ + NOT_I(buf_cache_add(&buf, buf_type),==,0)) + { +#ifndef STUB_TILER + A_I(ioctl(td, TILIOC_URBUF, &buf),==,0); +#else + FREE(buf_c); + buf.offset = 0; +#endif + } else { + /* update original from local copy */ + memcpy(blks, buf.blocks, sizeof(tiler_block_info) * num_blocks); + } + + return R_P(bufPtr); +} + +/** + * Checks whether the tiler_block_info is filled in correctly. + * Verifies the pixel format, correct length, width and or + * height, the length/stride relationship for 1D buffers, and + * the correct stride for 2D buffers. Also verifies block size + * to be page sized if desired. + * + * @author a0194118 (9/4/2009) + * + * @param blk Pointer to the tiler_block_info struct + * @param is_page_sized Whether the block needs to be page + * sized (fit on whole pages). + * @return 0 on success, non-0 error value on failure. + */ +static int check_block(tiler_block_info *blk, bool is_page_sized) +{ + /* check pixelformat */ + if (NOT_I(blk->fmt,>=,PIXEL_FMT_MIN) || + NOT_I(blk->fmt,<=,PIXEL_FMT_MAX)) return MEMMGR_ERR_GENERIC; + + + if (blk->fmt == PIXEL_FMT_PAGE) + { /* check 1D buffers */ + + /* length must be multiple of stride if stride > 0 */ + if (NOT_I(blk->dim.len,>,0) || + (blk->stride && NOT_I(blk->dim.len % blk->stride,==,0))) + return MEMMGR_ERR_GENERIC; + } + else + { /* check 2D buffers */ + + /* check width, height and stride (must be the default stride or 0) */ + bytes_t stride = def_stride(blk->dim.area.width * def_bpp(blk->fmt)); + if (NOT_I(blk->dim.area.width,>,0) || + NOT_I(blk->dim.area.height,>,0) || + (blk->stride && NOT_I(blk->stride,==,stride))) + return MEMMGR_ERR_GENERIC; + } + + if (is_page_sized && NOT_I(def_size(blk) & (PAGE_SIZE - 1),==,0)) + return MEMMGR_ERR_GENERIC; + + return MEMMGR_ERR_NONE; +} + +/** + * Checks whether the block information is correct for map and + * alloc operations. Checks the number of blocks, and validity + * of each block. Warns if reserved member is not 0. Also + * checks if the alignment/offset requirements are consistent + * across the buffer + * + * @author a0194118 (9/7/2009) + * + * @param blks Pointer to the block info array. + * @param num_blocks Number of blocks. + * @param num_pagesize_blocks Number of blocks that must be + * page sized (these must be in + * front) + * + * @return 0 on success, non-0 error value on failure. + */ +static int check_blocks(struct tiler_block_info *blks, int num_blocks, + int num_pagesize_blocks) +{ + /* check arguments */ + if (NOT_I(num_blocks,>,0) || + NOT_I(num_blocks,<=,TILER_MAX_NUM_BLOCKS)) return MEMMGR_ERR_GENERIC; + + /* check block allocation params */ + int ix; + for (ix = 0; ix < num_blocks; ix++) + { + struct tiler_block_info *blk = blks + ix; + CHK_I(blk->ssptr,==,0); + CHK_I(blk->id,==,0); + int ret = check_block(blk, ix < num_pagesize_blocks); + + /* check alignment */ + if (!ret) + { + } + if (ret) + { + DP("for block[%d]", ix); + return ret; + } + + + } + + /* set alignment parameters */ + return MEMMGR_ERR_NONE; +} + +/** + * Resets the ptr and reserved fields of the block info + * structures. + * + * @author a0194118 (9/7/2009) + * + * @param blks Pointer to the block info array. + * @param num_blocks Number of blocks. + */ +static void reset_blocks(struct tiler_block_info *blks, int num_blocks) +{ + int ix; + for (ix = 0; ix < num_blocks; ix++) + { + blks[ix].ssptr = 0; + blks[ix].id = 0; + blks[ix].ptr = NULL; + } + +} + +bytes_t MemMgr_PageSize() +{ + return PAGE_SIZE; +} + +void *MemMgr_Alloc(MemAllocBlock blocks[], int num_blocks) +{ + IN; + void *bufPtr = NULL; + + /* need to access ssptrs */ + struct tiler_block_info *blks = (tiler_block_info *) blocks; + + /* check block allocation params, and state */ + if (NOT_I(check_blocks(blks, num_blocks, num_blocks - 1),==,0) || + NOT_I(inc_ref(),==,0)) goto DONE; + + /* ----- begin recoverable portion ----- */ + int ix; + + /* allocate each buffer using tiler driver and initialize block info */ + for (ix = 0; ix < num_blocks; ix++) + { + if (ix) + { + /* continue offset between pages */ + } + CHK_I(blks[ix].ptr,==,NULL); + if (NOT_I(tiler_alloc(blks + ix),==,0)) goto FAIL_ALLOC; + } + + bufPtr = tiler_mmap(blks, num_blocks, BUF_ALLOCED); + if (A_P(bufPtr,!=,0)) goto DONE; + + /* ------ error handling ------ */ +FAIL_ALLOC: + while (ix) + { + tiler_free(blks + --ix); + } + + /* clear ssptr and ptr fields for all blocks */ + reset_blocks(blks, num_blocks); + + A_I(dec_ref(),==,0); +DONE: + CHK_I(cache_check(),==,0); + return R_P(bufPtr); +} + +int MemMgr_Free(void *bufPtr) +{ + IN; + + int ret = MEMMGR_ERR_GENERIC; + struct tiler_buf_info buf; + ZERO(buf); + + /* retrieve registered buffers from vsptr */ + /* :NOTE: if this succeeds, Memory Allocator stops tracking this buffer */ + buf_cache_del(bufPtr, &buf, BUF_ALLOCED); + + if (A_L(buf.offset,!=,0)) + { +#ifndef STUB_TILER + dump_buf(&buf, "==(URBUF)=>"); + ret = A_I(ioctl(td, TILIOC_URBUF, &buf),==,0); + dump_buf(&buf, "<=(URBUF)=="); + + /* free each block */ + int ix; + for (ix = 0; ix < buf.num_blocks; ix++) + { + ERR_ADD(ret, tiler_free(buf.blocks + ix)); + } + + /* unmap buffer */ + bufPtr = (void *)((uint32_t)bufPtr & ~(PAGE_SIZE - 1)); + ERR_ADD(ret, munmap(bufPtr, map_size(buf.length, buf.offset))); +#else + void *ptr = (void *) buf.offset; + FREE(ptr); + ret = MEMMGR_ERR_NONE; +#endif + ERR_ADD(ret, dec_ref()); + } + + CHK_I(cache_check(),==,0); + return R_I(ret); +} + +void *MemMgr_Map(MemAllocBlock blocks[], int num_blocks) +{ + IN; + void *bufPtr = NULL; + + /* need to access ssptrs */ + struct tiler_block_info *blks = (tiler_block_info *) blocks; + + /* check block params, and state */ + if (check_blocks(blks, num_blocks, num_blocks) || + NOT_I(inc_ref(),==,0)) goto DONE; + + /* we only map 1 page aligned 1D buffer for now */ + if (NOT_I(num_blocks,==,1) || + NOT_I(blocks[0].pixelFormat,==,PIXEL_FMT_PAGE) || + NOT_I(blocks[0].dim.len & (PAGE_SIZE - 1),==,0) || +#ifdef STUB_TILER + NOT_I(MemMgr_IsMapped(blocks[0].ptr),==,0) || +#endif + NOT_I((uint32_t)blocks[0].ptr & (PAGE_SIZE - 1),==,0)) + goto FAIL; + + /* ----- begin recoverable portion ----- */ + int ix; + + /* allocate each buffer using tiler driver */ + for (ix = 0; ix < num_blocks; ix++) + { + if (ix) + { + /* continue offset between pages */ + } + if (NOT_I(blks[ix].ptr,!=,NULL) || + NOT_I(tiler_map(blks + ix),==,0)) goto FAIL_MAP; + } + + /* map bufer into tiler space and register with tiler manager */ + bufPtr = tiler_mmap(blks, num_blocks, BUF_MAPPED); + if (A_P(bufPtr,!=,0)) goto DONE; + + /* ------ error handling ------ */ +FAIL_MAP: + while (ix) + { + tiler_unmap(blks + --ix); + } + +FAIL: + /* clear ssptr and ptr fields for all blocks */ + reset_blocks(blks, num_blocks); + + A_I(dec_ref(),==,0); +DONE: + CHK_I(cache_check(),==,0); + return R_P(bufPtr); +} + +int MemMgr_UnMap(void *bufPtr) +{ + IN; + + int ret = MEMMGR_ERR_GENERIC; + struct tiler_buf_info buf; + ZERO(buf); + + /* retrieve registered buffers from vsptr */ + /* :NOTE: if this succeeds, Memory Allocator stops tracking this buffer */ + buf_cache_del(bufPtr, &buf, BUF_MAPPED); + + if (A_L(buf.offset,!=,0)) + { +#ifndef STUB_TILER + dump_buf(&buf, "==(URBUF)=>"); + ret = A_I(ioctl(td, TILIOC_URBUF, &buf),==,0); + dump_buf(&buf, "<=(URBUF)=="); + + /* unmap each block */ + int ix; + for (ix = 0; ix < buf.num_blocks; ix++) + { + ERR_ADD(ret, tiler_unmap(buf.blocks + ix)); + } + + /* unmap buffer */ + bufPtr = (void *)((uint32_t)bufPtr & ~(PAGE_SIZE - 1)); + ERR_ADD(ret, munmap(bufPtr, map_size(buf.length, buf.offset))); +#else + struct tiler_buf_info *ptr = (struct tiler_buf_info *) buf.offset; + FREE(ptr[1].blocks[0].ptr); + FREE(ptr); + ret = MEMMGR_ERR_NONE; +#endif + ERR_ADD(ret, dec_ref()); + } + + CHK_I(cache_check(),==,0); + return R_I(ret); +} + +bool MemMgr_Is1DBlock(void *ptr) +{ + IN; + + SSPtr ssptr = TilerMem_VirtToPhys(ptr); + enum tiler_fmt fmt = tiler_get_fmt(ssptr); + return R_I(fmt == TILFMT_PAGE); +} + +bool MemMgr_Is2DBlock(void *ptr) +{ + IN; + + SSPtr ssptr = TilerMem_VirtToPhys(ptr); + enum tiler_fmt fmt = tiler_get_fmt(ssptr); + return R_I(fmt == TILFMT_8BIT || fmt == TILFMT_16BIT || + fmt == TILFMT_32BIT); +} + +bool MemMgr_IsMapped(void *ptr) +{ + IN; + SSPtr ssptr = TilerMem_VirtToPhys(ptr); + enum tiler_fmt fmt = tiler_get_fmt(ssptr); + return R_I(fmt == TILFMT_8BIT || fmt == TILFMT_16BIT || + fmt == TILFMT_32BIT || fmt == TILFMT_PAGE); +} + +bytes_t MemMgr_GetStride(void *ptr) +{ + IN; +#ifndef STUB_TILER + struct tiler_buf_info buf; + ZERO(buf); + + /* find block that this buffer belongs to */ + buf_cache_query(ptr, &buf, BUF_ALLOCED | BUF_MAPPED); + void *bufPtr = buf.blocks[0].ptr; + + A_I(inc_ref(),==,0); + + /* for tiler mapped buffers, get saved stride information */ + if (buf.offset) + { + /* walk through block to determine which stride we need */ + int ix; + for (ix = 0; ix < buf.num_blocks; ix++) + { + bytes_t size = def_size(buf.blocks + ix); + if (bufPtr <= ptr && ptr < bufPtr + size) { + A_I(dec_ref(),==,0); + return R_UP(buf.blocks[ix].stride); + } + bufPtr += size; + } + A_I(dec_ref(),==,0); + DP("assert: should not ever get here"); + return R_UP(0); + } + /* see if pointer is valid */ + else if (TilerMem_VirtToPhys(ptr) == 0) + { + A_I(dec_ref(),==,0); + return R_UP(0); + } + A_I(dec_ref(),==,0); +#else + /* if emulating, we need to get through all allocated memory segments */ + pthread_mutex_lock(&che_mutex); + init(); + + _AllocData *ad; + if (!ptr) return R_UP(0); + DLIST_MLOOP(bufs, ad, link) { + int ix; + struct tiler_buf_info *buf = (struct tiler_buf_info *) ad->buf.offset; + for (ix = 0; ix < buf->num_blocks; ix++) + { + if (ptr >= buf->blocks[ix].ptr && + ptr < buf->blocks[ix].ptr + def_size(buf->blocks + ix)) + { + bytes_t stride = buf->blocks[ix].stride; + pthread_mutex_unlock(&che_mutex); + return R_UP(stride); + } + } + } + pthread_mutex_unlock(&che_mutex); +#endif + return R_UP(PAGE_SIZE); +} + +bytes_t TilerMem_GetStride(SSPtr ssptr) +{ + IN; + switch(tiler_get_fmt(ssptr)) + { + case TILFMT_8BIT: return R_UP(TILER_STRIDE_8BIT); + case TILFMT_16BIT: return R_UP(TILER_STRIDE_16BIT); + case TILFMT_32BIT: return R_UP(TILER_STRIDE_32BIT); + case TILFMT_PAGE: return R_UP(PAGE_SIZE); + default: return R_UP(0); + } +} + +SSPtr TilerMem_VirtToPhys(void *ptr) +{ +#ifndef STUB_TILER + SSPtr ssptr = 0; + if(!NOT_I(inc_ref(),==,0)) + { + ssptr = ioctl(td, TILIOC_GSSP, (unsigned long) ptr); + A_I(dec_ref(),==,0); + } + return (SSPtr)R_P(ssptr); +#else + return (SSPtr)ptr; +#endif +} + +/** + * Internal Unit Test. Tests the static methods of this + * library. Assumes an unitialized state as well. + * + * @author a0194118 (9/4/2009) + * + * @return 0 for success, non-0 error value for failure. + */ +int __test__MemMgr() +{ + int ret = 0; + + /* state check */ + ret |= NOT_I(TILER_PAGE_WIDTH * TILER_PAGE_HEIGHT,==,PAGE_SIZE); + ret |= NOT_I(refCnt,==,0); + ret |= NOT_I(inc_ref(),==,0); + ret |= NOT_I(refCnt,==,1); + ret |= NOT_I(dec_ref(),==,0); + ret |= NOT_I(refCnt,==,0); + + /* enumeration check */ + ret |= NOT_I(PIXEL_FMT_8BIT,==,TILFMT_8BIT); + ret |= NOT_I(PIXEL_FMT_16BIT,==,TILFMT_16BIT); + ret |= NOT_I(PIXEL_FMT_32BIT,==,TILFMT_32BIT); + ret |= NOT_I(PIXEL_FMT_PAGE,==,TILFMT_PAGE); + ret |= NOT_I(sizeof(MemAllocBlock),==,sizeof(struct tiler_block_info)); + + /* void * arithmetic */ + void *a = (void *)1000, *b = a + 2000, *c = (void *)3000; + ret |= NOT_P(b,==,c); + + /* def_stride */ + ret |= NOT_I(def_stride(0),==,0); + ret |= NOT_I(def_stride(1),==,PAGE_SIZE); + ret |= NOT_I(def_stride(PAGE_SIZE),==,PAGE_SIZE); + ret |= NOT_I(def_stride(PAGE_SIZE + 1),==,2 * PAGE_SIZE); + + /* def_bpp */ + ret |= NOT_I(def_bpp(PIXEL_FMT_32BIT),==,4); + ret |= NOT_I(def_bpp(PIXEL_FMT_16BIT),==,2); + ret |= NOT_I(def_bpp(PIXEL_FMT_8BIT),==,1); + + /* def_size */ + tiler_block_info blk = {0}; + blk.fmt = TILFMT_8BIT; + blk.dim.area.width = PAGE_SIZE * 8 / 10; + blk.dim.area.height = 10; + ret |= NOT_I(def_size(&blk),==,10 * PAGE_SIZE); + + blk.fmt = TILFMT_16BIT; + blk.dim.area.width = PAGE_SIZE * 7 / 10; + ret |= NOT_I(def_size(&blk),==,20 * PAGE_SIZE); + blk.dim.area.width = PAGE_SIZE * 4 / 10; + ret |= NOT_I(def_size(&blk),==,10 * PAGE_SIZE); + + blk.fmt = TILFMT_32BIT; + ret |= NOT_I(def_size(&blk),==,20 * PAGE_SIZE); + blk.dim.area.width = PAGE_SIZE * 6 / 10; + ret |= NOT_I(def_size(&blk),==,30 * PAGE_SIZE); + + return ret; +} + diff --git a/tiler/memmgr.h b/tiler/memmgr.h new file mode 100644 index 0000000..8f99904 --- /dev/null +++ b/tiler/memmgr.h @@ -0,0 +1,311 @@ +/* + * memmgr.h + * + * Memory Allocator Interface functions for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MEMMGR_H_ +#define _MEMMGR_H_ + +/* retrieve type definitions */ +#include "mem_types.h" + +/** + * Memory Allocator is responsible for: + * <ol> + * <li>Allocate 1D and 2D blocks and pack them into a buffer. + * <li>Free such allocated blocks + * <li>Map 1D buffers into tiler space + * <li>Unmap 1D buffers from tiler space + * <li>Verify if an address lies in 1D or 2D space, whether it + * is mapped (to tiler space) + * <li>Mapping Ducati memory blocks to host processor and vice + * versa. + * </ol> + * + * The allocator distinguishes between: + * <ul> + * <li>1D and 2D blocks + * <li>2D blocks allocated by MemAlloc are non-cacheable. All + * other blocks are cacheable (e.g. 1D blocks). Preallocated + * may or may not be cacheable, depending on how they've been + * allocated, but are assumed to be cacheable. + * <li>buffers (an ordered collection of one or more blocks + * mapped consecutively) + * </ul> + * + * The allocator tracks each buffer based on (addr, size). + * + * Also, via the tiler manager, it tracks each block. The tiler + * manager itself also tracks each buffer. + * + */ + +/** + * Memory Allocator block specification + * + * Size of a 2D buffer is calculated as height * stride. stride + * is the smallest multiple of page size that is at least + * the width, and is set by MemMgr_Alloc. + * + * Size of a 1D buffer is calculated as length. stride is not + * set by MemMgr_Alloc, but it can be set by the user. length + * must be a multiple of stride unless stride is 0. + * + * @author a0194118 (9/1/2009) + */ +struct MemAllocBlock { + pixel_fmt_t pixelFormat; /* pixel format */ + union { + struct { + pixels_t width; /* width of 2D buffer */ + pixels_t height; /* height of 2D buffer */ + } area; + bytes_t len; /* length of 1D buffer. Must be multiple of + stride if stride is not 0. */ + } dim; + uint32_t stride; /* must be multiple of page size. Can be 0 only + if pixelFormat is PIXEL_FMT_PAGE. */ + void *ptr; /* pointer to beginning of buffer */ + uint32_t id; /* buffer ID - received at allocation */ + uint32_t key; /* buffer key - given at allocation */ + uint32_t group_id; /* group ID */ + /* alignment requirements for ssptr: ssptr & (align - 1) == offs */ + uint32_t reserved; /* system space address (used internally) */ +}; + +typedef struct MemAllocBlock MemAllocBlock; + +/** + * Returns the page size. This is required for allocating 1D + * blocks that stack under any other blocks. + * + * @author a0194118 (9/3/2009) + * + * @return Page size. + */ +bytes_t MemMgr_PageSize(); + +/** + * Allocates a buffer as a list of blocks (1D or 2D), and maps + * them so that they are packaged consecutively. Returns the + * pointer to the first block, or NULL on failure. + * <p> + * The size of each block other than the last must be a multiple + * of the page size. This ensures that the blocks stack + * correctly. Set stride to 0 to avoid stride/length alignment + * constraints. Stride of 2D blocks will be updated by this + * method. + * <p> + * 2D blocks will be non-cacheable, while 1D blocks will be + * cacheable. + * <p> + * On success, the buffer is registered with the memory + * allocator. + * <p> + * As a side effect, if the operation was successful, the ssptr + * fields of the block specification will be filled with the + * system-space addresses, while the ptr fields will be set to + * the individual blocks. The stride information is set for 2D + * blocks. + * + * @author a0194118 (9/1/2009) + * + * @param blocks Block specification information. This + * should be an array of at least num_blocks + * elements. + * @param num_blocks Number of blocks to be included in the + * allocated memory segment + * + * @return Pointer to the buffer, which is also the pointer to + * the first allocated block. NULL if allocation failed. + */ +void *MemMgr_Alloc(MemAllocBlock blocks[], int num_blocks); + +/** + * Frees a buffer allocated by MemMgr_Alloc(). It fails for + * any buffer not allocated by MemMgr_Alloc() or one that has + * been already freed. + * <p> + * It also unregisters the buffer with the memory allocator. + * <p> + * This function unmaps the processor's virtual address to the + * tiler address for all blocks allocated, unregisters the + * buffer, and frees all of its tiler blocks. + * + * @author a0194118 (9/1/2009) + * + * @param bufPtr Pointer to the buffer allocated (returned) + * by MemMgr_Alloc() + * + * @return 0 on success. Non-0 error value on failure. + */ +int MemMgr_Free(void *bufPtr); + +/** + * This function maps the user provided data buffer to the tiler + * space as blocks, and maps that area into the process space + * consecutively. You can map a data buffer multiple times, + * resulting in multiple mapping for the same buffer. However, + * you cannot map a buffer that is already mapped to tiler, e.g. + * a buffer pointer returned by this method. + * + * In phase 1 and 2, the supported configurations are: + * <ol> + * <li> Mapping exactly one 1D block to tiler space (e.g. + * MapIn1DMode). + * </ol> + * + * @author a0194118 (9/3/2009) + * + * @param blocks Block specification information. This + * should be an array of at least num_blocks + * elements. The ptr fields must contain the + * user allocated buffers for the block. + * These will be updated with the mapped + * addresses of these blocks on success. + * + * Each block must be page aligned. Length of + * each block also must be page aligned. + * + * @param num_blocks Number of blocks to be included in the + * mapped memory segment + * + * @return Pointer to the buffer, which is also the pointer to + * the first mapped block. NULL if allocation failed. + */ +void *MemMgr_Map(MemAllocBlock blocks[], int num_blocks); + +/** + * This function unmaps the user provided data buffer from tiler + * space that was mapped to the tiler space in paged mode using + * MemMgr_Map(). It also unmaps the buffer itself from the + * process space. Trying to unmap a previously unmapped buffer + * will fail. + * + * @author a0194118 (9/1/2009) + * + * @param bufPtr Pointer to the buffer as returned by a + * previous call to MemMgr_MapIn1DMode() + * + * @return 0 on success. Non-0 error value on failure. + */ +int MemMgr_UnMap(void *bufPtr); + +/** + * Checks if a given virtual address is mapped by tiler manager + * to tiler space. + * <p> + * This function is equivalent to MemMgr_Is1DBuffer(ptr) || + * MemMgr_Is2DBuffer(ptr). It retrieves the system space + * address that the virtual address maps to. If this system + * space address lies within the tiler area, the function + * returns TRUE. + * + * + * @author a0194118 (9/1/2009) + * + * @param ptr Pointer to a virtual address + * + * @return TRUE (non-0) if the virtual address is within a + * buffer that was mapped into tiler space, e.g. by + * calling MemMgr_MapIn1DMode() or MemMgr_MapIn2DMode() + */ +bool MemMgr_IsMapped(void *ptr); + +/** + * Checks if a given virtual address lies in a tiler 1D buffer. + * <p> + * This function retrieves the system space address that the + * virtual address maps to. If this system space address is + * within the 1D tiler area, it is considered lying within a 1D + * buffer. + * + * @author a0194118 (9/1/2009) + * + * @param ptr Pointer to a virtual address + * + * @return TRUE (non-0) if the virtual address is within a + * mapped 1D tiler buffer. FALSE (0) if the virtual + * address is not mapped, invalid, or is mapped to an + * area other than a 1D tiler buffer. In phase 1, + * however, it is TRUE it the virtual address is mapped + * to the page-mode area of the tiler space. + */ +bool MemMgr_Is1DBlock(void *ptr); + +/** + * Checks if a given virtual address lies in a 2D buffer. + * <p> + * This function retrieves the system space address that the + * virtual address maps to. If this system space address is + * within the 2D tiler area, it is considered lying within a 2D + * buffer. + * + * @author a0194118 (9/1/2009) + * + * @param ptr Pointer to a virtual address + * + * @return TRUE (non-0) if the virtual address is within a + * mapped 2D buffer. FALSE (0) if the virtual address + * is not mapped, invalid, or is mapped to an area other + * than a 2D buffer. In phase 1, however, it is TRUE it + * the virtual address is mapped to any area of the + * tiler space other than page mode. + */ +bool MemMgr_Is2DBlock(void *ptr); + +/** + * Returns the stride corresponding to a virtual address. For + * 1D and 2D buffers it returns the stride supplied + * with/acquired during the allocation/mapping. For non-tiler + * buffers it returns the page size. + * <p> + * NOTE: on Ducati phase 1, stride should return 16K for 8-bit + * 2D buffers, 32K for 16-bit and 32-bit 2D buffers, the stride + * used for alloc/map for 1D buffers, and the page size for + * non-tiler buffers. + * + * For unmapped addresses it returns 0. However, this cannot be + * used to determine if an address is unmapped as 1D buffers + * could also have 0 stride (e.g. compressed buffers). + * + * @author a0194118 (9/1/2009) + * + * @param ptr pointer to a virtual address + * + * @return The virtual stride of the block that contains the + * address. + */ +bytes_t MemMgr_GetStride(void *ptr); + +#endif diff --git a/tiler/memmgr_test.c b/tiler/memmgr_test.c new file mode 100644 index 0000000..2bb76b6 --- /dev/null +++ b/tiler/memmgr_test.c @@ -0,0 +1,1693 @@ +/* + * memmgr_test.c + * + * Memory Allocator Interface tests. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* retrieve type definitions */ +#define __DEBUG__ +#undef __DEBUG_ENTRY__ +#define __DEBUG_ASSERT__ + +#define __MAP_OK__ +#undef __WRITE_IN_STRIDE__ +#undef STAR_TRACE_MEM + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif +#include <utils.h> +#include <list_utils.h> +#include <debug_utils.h> +#include <memmgr.h> +#include <tilermem.h> +#include <tilermem_utils.h> +#include <testlib.h> + +/* for star_tiler_test */ +#include <fcntl.h> /* open() */ +#include <unistd.h> /* close() */ +#include <sys/ioctl.h> /* ioctl() */ + +#define FALSE 0 +#define TESTERR_NOTIMPLEMENTED -65378 + +#define MAX_ALLOCS 512 + +#define TESTS\ + T(alloc_1D_test(4096, 0))\ + T(alloc_2D_test(64, 64, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(64, 64, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(64, 64, PIXEL_FMT_32BIT))\ + T(alloc_NV12_test(64, 64))\ + T(map_1D_test(4096, 0))\ + T(alloc_1D_test(176 * 144 * 2, 0))\ + T(alloc_2D_test(176, 144, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(176, 144, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(176, 144, PIXEL_FMT_32BIT))\ + T(alloc_NV12_test(176, 144))\ + T(map_1D_test(176 * 144 * 2, 0))\ + T(alloc_1D_test(640 * 480 * 2, 0))\ + T(alloc_2D_test(640, 480, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(640, 480, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(640, 480, PIXEL_FMT_32BIT))\ + T(alloc_NV12_test(640, 480))\ + T(map_1D_test(640 * 480 * 2, 0))\ + T(alloc_1D_test(848 * 480 * 2, 0))\ + T(alloc_2D_test(848, 480, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(848, 480, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(848, 480, PIXEL_FMT_32BIT))\ + T(alloc_NV12_test(848, 480))\ + T(map_1D_test(848 * 480 * 2, 0))\ + T(alloc_1D_test(1280 * 720 * 2, 0))\ + T(alloc_2D_test(1280, 720, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(1280, 720, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(1280, 720, PIXEL_FMT_32BIT))\ + T(alloc_NV12_test(1280, 720))\ + T(map_1D_test(1280 * 720 * 2, 0))\ + T(alloc_1D_test(1920 * 1080 * 2, 0))\ + T(alloc_2D_test(1920, 1080, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(1920, 1080, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(1920, 1080, PIXEL_FMT_32BIT))\ + T(alloc_NV12_test(1920, 1080))\ + T(map_1D_test(1920 * 1080 * 2, 0))\ + T(map_1D_test(4096, 0))\ + T(map_1D_test(8192, 0))\ + T(map_1D_test(16384, 0))\ + T(map_1D_test(32768, 0))\ + T(map_1D_test(65536, 0))\ + T(neg_alloc_tests())\ + T(neg_free_tests())\ + T(neg_map_tests())\ + T(neg_unmap_tests())\ + T(neg_check_tests())\ + T(page_size_test())\ + T(maxalloc_2D_test(2500, 32, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(2500, 16, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(1250, 16, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(5000, 32, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(5000, 16, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(2500, 16, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(alloc_2D_test(8193, 16, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(8193, 16, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(4097, 16, PIXEL_FMT_32BIT))\ + T(alloc_2D_test(16384, 16, PIXEL_FMT_8BIT))\ + T(alloc_2D_test(16384, 16, PIXEL_FMT_16BIT))\ + T(alloc_2D_test(8192, 16, PIXEL_FMT_32BIT))\ + T(!alloc_2D_test(16385, 16, PIXEL_FMT_8BIT))\ + T(!alloc_2D_test(16385, 16, PIXEL_FMT_16BIT))\ + T(!alloc_2D_test(8193, 16, PIXEL_FMT_32BIT))\ + T(maxalloc_1D_test(4096, MAX_ALLOCS))\ + T(maxalloc_2D_test(64, 64, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(64, 64, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(64, 64, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_NV12_test(64, 64, MAX_ALLOCS))\ + T(maxmap_1D_test(4096, MAX_ALLOCS))\ + T(maxalloc_1D_test(176 * 144 * 2, MAX_ALLOCS))\ + T(maxalloc_2D_test(176, 144, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(176, 144, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(176, 144, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_NV12_test(176, 144, MAX_ALLOCS))\ + T(maxmap_1D_test(176 * 144 * 2, MAX_ALLOCS))\ + T(maxalloc_1D_test(640 * 480 * 2, MAX_ALLOCS))\ + T(maxalloc_2D_test(640, 480, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(640, 480, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(640, 480, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_NV12_test(640, 480, MAX_ALLOCS))\ + T(maxmap_1D_test(640 * 480 * 2, MAX_ALLOCS))\ + T(maxalloc_1D_test(848 * 480 * 2, MAX_ALLOCS))\ + T(maxalloc_2D_test(848, 480, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(848, 480, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(848, 480, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_NV12_test(848, 480, MAX_ALLOCS))\ + T(maxmap_1D_test(848 * 480 * 2, MAX_ALLOCS))\ + T(maxalloc_1D_test(1280 * 720 * 2, MAX_ALLOCS))\ + T(maxalloc_2D_test(1280, 720, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(1280, 720, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(1280, 720, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_NV12_test(1280, 720, MAX_ALLOCS))\ + T(maxmap_1D_test(1280 * 720 * 2, MAX_ALLOCS))\ + T(maxalloc_1D_test(1920 * 1080 * 2, MAX_ALLOCS))\ + T(maxalloc_2D_test(1920, 1080, PIXEL_FMT_8BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(1920, 1080, PIXEL_FMT_16BIT, MAX_ALLOCS))\ + T(maxalloc_2D_test(1920, 1080, PIXEL_FMT_32BIT, MAX_ALLOCS))\ + T(maxalloc_NV12_test(1920, 1080, 2))\ + T(maxalloc_NV12_test(1920, 1080, MAX_ALLOCS))\ + T(maxmap_1D_test(1920 * 1080 * 2, MAX_ALLOCS))\ + T(star_tiler_test(1000, 10))\ + T(star_tiler_test(1000, 30))\ + T(star_test(100, 10))\ + T(star_test(1000, 10))\ + +/* this is defined in memmgr.c, but not exported as it is for internal + use only */ +extern int __test__MemMgr(); + +/** + * Returns the default page stride for this block + * + * @author a0194118 (9/4/2009) + * + * @param width Width of 2D container + * + * @return Stride + */ +static bytes_t def_stride(bytes_t width) +{ + return ROUND_UP_TO2POW(width, PAGE_SIZE); +} + +/** + * Returns the bytes per pixel for the pixel format. + * + * @author a0194118 (9/4/2009) + * + * @param pixelFormat Pixelformat + * + * @return Bytes per pixel + */ +static bytes_t def_bpp(pixel_fmt_t pixelFormat) +{ + return (pixelFormat == PIXEL_FMT_32BIT ? 4 : + pixelFormat == PIXEL_FMT_16BIT ? 2 : 1); +} + +/** + * This method fills up a range of memory using a start address + * and start value. The method of filling ensures that + * accidentally overlapping regions have minimal chances of + * matching, even if the same starting value is used. This is + * because the difference between successive values varies as + * such. This series only repeats after 704189 values, so the + * probability of a match for a range of at least 2 values is + * less than 2*10^-11. + * + * V(i + 1) - V(i) = { 1, 2, 3, ..., 65535, 2, 4, 6, 8 ..., + * 65534, 3, 6, 9, 12, ..., 4, 8, 12, 16, ... } + * + * @author a0194118 (9/6/2009) + * + * @param start start value + * @param block pointer to block info strucure + */ +void fill_mem(uint16_t start, MemAllocBlock *block) +{ + IN; + uint16_t *ptr = (uint16_t *)block->ptr, delta = 1, step = 1; + bytes_t height, width, stride, i; + if (block->pixelFormat == PIXEL_FMT_PAGE) + { + height = 1; + stride = width = block->dim.len; + } + else + { + height = block->dim.area.height; + width = block->dim.area.width; + stride = block->stride; + } + width *= def_bpp(block->pixelFormat); + bytes_t size = height * stride; + + P("(%p,0x%x*0x%x,s=0x%x)=0x%x", block->ptr, width, height, stride, start); + + CHK_I(width,<=,stride); + uint32_t *ptr32 = (uint32_t *)ptr; + while (height--) + { + if (block->pixelFormat == PIXEL_FMT_32BIT) + { + for (i = 0; i < width; i += sizeof(uint32_t)) + { + uint32_t val = (start & 0xFFFF) | (((uint32_t)(start + delta) & 0xFFFF) << 16); + *ptr32++ = val; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && (height || ((PAGE_SIZE - 1) & (uint32_t)ptr32))) + { + *ptr32++ = 0; + i += sizeof(uint32_t); + } +#else + ptr32 += (stride - i) / sizeof(uint32_t); +#endif + } + else + { + for (i = 0; i < width; i += sizeof(uint16_t)) + { + *ptr++ = start; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && (height || ((PAGE_SIZE - 1) & (uint32_t)ptr))) + { + *ptr++ = 0; + i += sizeof(uint16_t); + } +#else + ptr += (stride - i) / sizeof(uint16_t); +#endif + + } + } + CHK_P((block->pixelFormat == PIXEL_FMT_32BIT ? (void *)ptr32 : (void *)ptr),==, + (block->ptr + size)); + OUT; +} + +/** + * This verifies if a range of memory at a given address was + * filled up using the start value. + * + * @author a0194118 (9/6/2009) + * + * @param start start value + * @param block pointer to block info strucure + * + * @return 0 on success, non-0 error value on failure + */ +int check_mem(uint16_t start, MemAllocBlock *block) +{ + IN; + uint16_t *ptr = (uint16_t *)block->ptr, delta = 1, step = 1; + bytes_t height, width, stride, r, i; + if (block->pixelFormat == PIXEL_FMT_PAGE) + { + height = 1; + stride = width = block->dim.len; + } + else + { + height = block->dim.area.height; + width = block->dim.area.width; + stride = block->stride; + } + width *= def_bpp(block->pixelFormat); + + CHK_I(width,<=,stride); + uint32_t *ptr32 = (uint32_t *)ptr; + for (r = 0; r < height; r++) + { + if (block->pixelFormat == PIXEL_FMT_32BIT) + { + for (i = 0; i < width; i += sizeof(uint32_t)) + { + uint32_t val = (start & 0xFFFF) | (((uint32_t)(start + delta) & 0xFFFF) << 16); + if (*ptr32++ != val) { + DP("assert: val[%u,%u] (=0x%x) != 0x%x", r, i, *--ptr32, val); + return R_I(MEMMGR_ERR_GENERIC); + } + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && ((r < height - 1) || ((PAGE_SIZE - 1) & (uint32_t)ptr32))) + { + if (*ptr32++) { + DP("assert: val[%u,%u] (=0x%x) != 0", r, i, *--ptr32); + return R_I(MEMMGR_ERR_GENERIC); + } + i += sizeof(uint32_t); + } +#else + ptr32 += (stride - i) / sizeof(uint32_t); +#endif + } + else + { + for (i = 0; i < width; i += sizeof(uint16_t)) + { + if (*ptr++ != start) { + DP("assert: val[%u,%u] (=0x%x) != 0x%x", r, i, *--ptr, start); + return R_I(MEMMGR_ERR_GENERIC); + } + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && ((r < height - 1) || ((PAGE_SIZE - 1) & (uint32_t)ptr))) + { + if (*ptr++) { + DP("assert: val[%u,%u] (=0x%x) != 0", r, i, *--ptr); + return R_I(MEMMGR_ERR_GENERIC); + } + i += sizeof(uint16_t); + } +#else + ptr += (stride - i) / sizeof(uint16_t); +#endif + } + } + return R_I(MEMMGR_ERR_NONE); +} + +/** + * This method allocates a 1D tiled buffer of the given length + * and stride using MemMgr_Alloc. If successful, it checks + * that the block information was updated with the pointer to + * the block. Additionally, it verifies the correct return + * values for MemMgr_IsMapped, MemMgr_Is1DBlock, + * MemMgr_Is2DBlock, MemMgr_GetStride, TilerMem_GetStride. It + * also verifies TilerMem_VirtToPhys using an internally stored + * value of the ssptr. If any of these verifications fail, the + * buffer is freed. Otherwise, it is filled using the given + * start value. + * + * @author a0194118 (9/7/2009) + * + * @param length Buffer length + * @param stride Buffer stride + * @param val Fill start value + * + * @return pointer to the allocated buffer, or NULL on failure + */ +void *alloc_1D(bytes_t length, bytes_t stride, uint16_t val) +{ + MemAllocBlock block; + memset(&block, 0, sizeof(block)); + + block.pixelFormat = PIXEL_FMT_PAGE; + block.dim.len = length; + block.stride = stride; + + void *bufPtr = MemMgr_Alloc(&block, 1); + CHK_P(bufPtr,==,block.ptr); + if (bufPtr) { + if (NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || + NOT_I(MemMgr_Is1DBlock(bufPtr),!=,0) || + NOT_I(MemMgr_Is2DBlock(bufPtr),==,0) || + NOT_I(MemMgr_GetStride(bufPtr),==,block.stride) || + NOT_P(TilerMem_VirtToPhys(bufPtr),==,block.reserved) || + NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,PAGE_SIZE) || + NOT_L((PAGE_SIZE - 1) & (long)bufPtr,==,(PAGE_SIZE - 1) & block.reserved)) + { + MemMgr_Free(bufPtr); + return NULL; + } + fill_mem(val, &block); + } + return bufPtr; +} + +/** + * This method frees a 1D tiled buffer. The given length, + * stride and start values are used to verify that the buffer is + * still correctly filled. In the event of any errors, the + * error value is returned. + * + * @author a0194118 (9/7/2009) + * + * @param length Buffer length + * @param stride Buffer stride + * @param val Fill start value + * @param bufPtr Pointer to the allocated buffer + * + * @return 0 on success, non-0 error value on failure + */ +int free_1D(bytes_t length, bytes_t stride, uint16_t val, void *bufPtr) +{ + MemAllocBlock block; + memset(&block, 0, sizeof(block)); + + block.pixelFormat = PIXEL_FMT_PAGE; + block.dim.len = length; + block.stride = stride; + block.ptr = bufPtr; + + int ret = A_I(check_mem(val, &block),==,0); + ERR_ADD(ret, MemMgr_Free(bufPtr)); + return ret; +} + +/** + * This method allocates a 2D tiled buffer of the given width, + * height, stride and pixel format using + * MemMgr_Alloc. If successful, it checks that the block + * information was updated with the pointer to the block. + * Additionally, it verifies the correct return values for + * MemMgr_IsMapped, MemMgr_Is1DBlock, MemMgr_Is2DBlock, + * MemMgr_GetStride, TilerMem_GetStride. It also verifies + * TilerMem_VirtToPhys using an internally stored value of the + * ssptr. If any of these verifications fail, the buffer is + * freed. Otherwise, it is filled using the given start value. + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * @param fmt Pixel format + * @param stride Buffer stride + * @param val Fill start value + * + * @return pointer to the allocated buffer, or NULL on failure + */ +void *alloc_2D(pixels_t width, pixels_t height, pixel_fmt_t fmt, bytes_t stride, + uint16_t val) +{ + MemAllocBlock block; + memset(&block, 0, sizeof(block)); + + block.pixelFormat = fmt; + block.dim.area.width = width; + block.dim.area.height = height; + block.stride = stride; + + void *bufPtr = MemMgr_Alloc(&block, 1); + CHK_P(bufPtr,==,block.ptr); + if (bufPtr) { + bytes_t cstride = (fmt == PIXEL_FMT_8BIT ? TILER_STRIDE_8BIT : + fmt == PIXEL_FMT_16BIT ? TILER_STRIDE_16BIT : + TILER_STRIDE_32BIT); + + if (NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || + NOT_I(MemMgr_Is1DBlock(bufPtr),==,0) || + NOT_I(MemMgr_Is2DBlock(bufPtr),!=,0) || + NOT_I(block.stride,!=,0) || + NOT_I(MemMgr_GetStride(bufPtr),==,block.stride) || + NOT_P(TilerMem_VirtToPhys(bufPtr),==,block.reserved) || + NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,cstride) || + NOT_L((PAGE_SIZE - 1) & (long)bufPtr,==,(PAGE_SIZE - 1) & block.reserved)) + { + MemMgr_Free(bufPtr); + return NULL; + } + fill_mem(val, &block); + } + return bufPtr; +} + +/** + * This method frees a 2D tiled buffer. The given width, + * height, pixel format, stride and start values are used to + * verify that the buffer is still correctly filled. In the + * event of any errors, the error value is returned. + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * @param fmt Pixel format + * @param stride Buffer stride + * @param val Fill start value + * @param bufPtr Pointer to the allocated buffer + * + * @return 0 on success, non-0 error value on failure + */ +int free_2D(pixels_t width, pixels_t height, pixel_fmt_t fmt, bytes_t stride, + uint16_t val, void *bufPtr) +{ + MemAllocBlock block; + memset(&block, 0, sizeof(block)); + + block.pixelFormat = fmt; + block.dim.area.width = width; + block.dim.area.height = height; + block.stride = def_stride(width * def_bpp(fmt)); + block.ptr = bufPtr; + + int ret = A_I(check_mem(val, &block),==,0); + ERR_ADD(ret, MemMgr_Free(bufPtr)); + return ret; +} + +/** + * This method allocates an NV12 tiled buffer of the given width + * and height using MemMgr_Alloc. If successful, it checks that + * the block informations were updated with the pointers to the + * individual blocks. Additionally, it verifies the correct + * return values for MemMgr_IsMapped, MemMgr_Is1DBlock, + * MemMgr_Is2DBlock, MemMgr_GetStride, TilerMem_GetStride for + * both blocks. It also verifies TilerMem_VirtToPhys using an + * internally stored values of the ssptr. If any of these + * verifications fail, the buffer is freed. Otherwise, it is + * filled using the given start value. + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * @param val Fill start value + * + * @return pointer to the allocated buffer, or NULL on failure + */ +void *alloc_NV12(pixels_t width, pixels_t height, uint16_t val) +{ + MemAllocBlock blocks[2]; + ZERO(blocks); + + blocks[0].pixelFormat = PIXEL_FMT_8BIT; + blocks[0].dim.area.width = width; + blocks[0].dim.area.height = height; + blocks[1].pixelFormat = PIXEL_FMT_16BIT; + blocks[1].dim.area.width = width >> 1; + blocks[1].dim.area.height = height >> 1; + + void *bufPtr = MemMgr_Alloc(blocks, 2); + CHK_P(blocks[0].ptr,==,bufPtr); + if (bufPtr) { + void *buf2 = bufPtr + blocks[0].stride * height; + if (NOT_P(blocks[1].ptr,==,buf2) || + NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || + NOT_I(MemMgr_IsMapped(buf2),!=,0) || + NOT_I(MemMgr_Is1DBlock(bufPtr),==,0) || + NOT_I(MemMgr_Is1DBlock(buf2),==,0) || + NOT_I(MemMgr_Is2DBlock(bufPtr),!=,0) || + NOT_I(MemMgr_Is2DBlock(buf2),!=,0) || + NOT_I(blocks[0].stride,!=,0) || + NOT_I(blocks[1].stride,!=,0) || + NOT_I(MemMgr_GetStride(bufPtr),==,blocks[0].stride) || + NOT_I(MemMgr_GetStride(buf2),==,blocks[1].stride) || + NOT_P(TilerMem_VirtToPhys(bufPtr),==,blocks[0].reserved) || + NOT_P(TilerMem_VirtToPhys(buf2),==,blocks[1].reserved) || + NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,TILER_STRIDE_8BIT) || + NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(buf2)),==,TILER_STRIDE_16BIT) || + NOT_L((PAGE_SIZE - 1) & (long)blocks[0].ptr,==,(PAGE_SIZE - 1) & blocks[0].reserved) || + NOT_L((PAGE_SIZE - 1) & (long)blocks[1].ptr,==,(PAGE_SIZE - 1) & blocks[1].reserved)) + { + MemMgr_Free(bufPtr); + return NULL; + } + + fill_mem(val, blocks); + fill_mem(val, blocks + 1); + } else { + CHK_P(blocks[1].ptr,==,NULL); + } + + return bufPtr; +} + +/** + * This method frees an NV12 tiled buffer. The given width, + * height and start values are used to verify that the buffer is + * still correctly filled. In the event of any errors, the + * error value is returned. + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * @param val Fill start value + * @param bufPtr Pointer to the allocated buffer + * + * @return 0 on success, non-0 error value on failure + */ +int free_NV12(pixels_t width, pixels_t height, uint16_t val, void *bufPtr) +{ + MemAllocBlock blocks[2]; + memset(blocks, 0, sizeof(blocks)); + + blocks[0].pixelFormat = PIXEL_FMT_8BIT; + blocks[0].dim.area.width = width; + blocks[0].dim.area.height = height; + blocks[0].stride = def_stride(width); + blocks[0].ptr = bufPtr; + blocks[1].pixelFormat = PIXEL_FMT_16BIT; + blocks[1].dim.area.width = width >> 1; + blocks[1].dim.area.height = height >> 1; + blocks[1].stride = def_stride(width); + blocks[1].ptr = bufPtr + blocks[0].stride * height; + + int ret = A_I(check_mem(val, blocks),==,0); + ERR_ADD(ret, check_mem(val, blocks + 1)); + ERR_ADD(ret, MemMgr_Free(bufPtr)); + return ret; +} + +/** + * This method maps a preallocated 1D buffer of the given length + * and stride into tiler space using MemMgr_Map. The mapped + * address must differ from the supplied address is successful. + * Moreover, it checks that the block information was + * updated with the pointer to the block. Additionally, it + * verifies the correct return values for MemMgr_IsMapped, + * MemMgr_Is1DBlock, MemMgr_Is2DBlock, MemMgr_GetStride, + * TilerMem_GetStride. It also verifies TilerMem_VirtToPhys + * using an internally stored value of the ssptr. If any of + * these verifications fail, the buffer is unmapped. Otherwise, + * the original buffer is filled using the given start value. + * + * :TODO: how do we verify the mapping? + * + * @author a0194118 (9/7/2009) + * + * @param dataPtr Pointer to the allocated buffer + * @param length Buffer length + * @param stride Buffer stride + * @param val Fill start value + * + * @return pointer to the mapped buffer, or NULL on failure + */ +void *map_1D(void *dataPtr, bytes_t length, bytes_t stride, uint16_t val) +{ + MemAllocBlock block; + memset(&block, 0, sizeof(block)); + + block.pixelFormat = PIXEL_FMT_PAGE; + block.dim.len = length; + block.stride = stride; + block.ptr = dataPtr; + + void *bufPtr = MemMgr_Map(&block, 1); + CHK_P(bufPtr,==,block.ptr); + if (bufPtr) { + if (NOT_P(bufPtr,!=,dataPtr) || + NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || + NOT_I(MemMgr_Is1DBlock(bufPtr),!=,0) || + NOT_I(MemMgr_Is2DBlock(bufPtr),==,0) || + NOT_I(MemMgr_GetStride(bufPtr),==,block.stride) || + NOT_P(TilerMem_VirtToPhys(bufPtr),==,block.reserved) || + NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,PAGE_SIZE) || + NOT_L((PAGE_SIZE - 1) & (long)bufPtr,==,0) || + NOT_L((PAGE_SIZE - 1) & block.reserved,==,0)) + { + MemMgr_UnMap(bufPtr); + return NULL; + } + block.ptr = dataPtr; + fill_mem(val, &block); + } + return bufPtr; +} + +/** + * This method unmaps a 1D tiled buffer. The given data + * pointer, length, stride and start values are used to verify + * that the buffer is still correctly filled. In the event of + * any errors, the error value is returned. + * + * :TODO: how do we verify the mapping? + * + * @author a0194118 (9/7/2009) + * + * @param dataPtr Pointer to the preallocated buffer + * @param length Buffer length + * @param stride Buffer stride + * @param val Fill start value + * @param bufPtr Pointer to the mapped buffer + * + * @return 0 on success, non-0 error value on failure + */ +int unmap_1D(void *dataPtr, bytes_t length, bytes_t stride, uint16_t val, void *bufPtr) +{ + MemAllocBlock block; + memset(&block, 0, sizeof(block)); + + block.pixelFormat = PIXEL_FMT_PAGE; + block.dim.len = length; + block.stride = stride; + block.ptr = dataPtr; + int ret = A_I(check_mem(val, &block),==,0); + ERR_ADD(ret, MemMgr_UnMap(bufPtr)); + return ret; +} + +/** + * Tests the MemMgr_PageSize method. + * + * @author a0194118 (9/15/2009) + * + * @return 0 on success, non-0 error value on failure. + */ +int page_size_test() +{ + return NOT_I(MemMgr_PageSize(),==,PAGE_SIZE); +} + +/** + * This method tests the allocation and freeing of a 1D tiled + * buffer. + * + * @author a0194118 (9/7/2009) + * + * @param length Buffer length + * @param stride Buffer stride + * + * @return 0 on success, non-0 error value on failure + */ +int alloc_1D_test(bytes_t length, bytes_t stride) +{ + printf("Allocate & Free %ub 1D buffer\n", length); + + uint16_t val = (uint16_t) rand(); + void *ptr = alloc_1D(length, stride, val); + if (!ptr) return 1; + int res = free_1D(length, stride, val, ptr); + return res; +} + +/** + * This method tests the allocation and freeing of a 2D tiled + * buffer. + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * @param fmt Pixel format + * + * @return 0 on success, non-0 error value on failure + */ +int alloc_2D_test(pixels_t width, pixels_t height, pixel_fmt_t fmt) +{ + printf("Allocate & Free %ux%ux%ub 1D buffer\n", width, height, def_bpp(fmt)); + + uint16_t val = (uint16_t) rand(); + void *ptr = alloc_2D(width, height, fmt, 0, val); + if (!ptr) return 1; + int res = free_2D(width, height, fmt, 0, val, ptr); + return res; +} + +/** + * This method tests the allocation and freeing of an NV12 tiled + * buffer. + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * + * @return 0 on success, non-0 error value on failure + */ +int alloc_NV12_test(pixels_t width, pixels_t height) +{ + printf("Allocate & Free %ux%u NV12 buffer\n", width, height); + + uint16_t val = (uint16_t) rand(); + void *ptr = alloc_NV12(width, height, val); + if (!ptr) return 1; + int res = free_NV12(width, height, val, ptr); + return res; +} + +/** + * This method tests the mapping and unmapping of a 1D buffer. + * + * @author a0194118 (9/7/2009) + * + * @param length Buffer length + * @param stride Buffer stride + * + * @return 0 on success, non-0 error value on failure + */ +int map_1D_test(bytes_t length, bytes_t stride) +{ + length = (length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); + printf("Mapping and UnMapping 0x%xb 1D buffer\n", length); + +#ifdef __MAP_OK__ + /* allocate aligned buffer */ + void *buffer = malloc(length + PAGE_SIZE - 1); + void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + uint16_t val = (uint16_t) rand(); + void *ptr = map_1D(dataPtr, length, stride, val); + if (!ptr) return 1; + int res = unmap_1D(dataPtr, length, stride, val, ptr); + FREE(buffer); +#else + int res = TESTERR_NOTIMPLEMENTED; +#endif + return res; +} + +/** + * This method tests the allocation and freeing of a number of + * 1D tiled buffers (up to MAX_ALLOCS) + * + * @author a0194118 (9/7/2009) + * + * @param length Buffer length + * + * @return 0 on success, non-0 error value on failure + */ +int maxalloc_1D_test(bytes_t length, int max_allocs) +{ + printf("Allocate & Free max # of %ub 1D buffers\n", length); + + struct data { + uint16_t val; + void *bufPtr; + } *mem; + + /* allocate as many buffers as we can */ + mem = NEWN(struct data, max_allocs); + void *ptr = (void *)mem; + int ix, res = 0; + for (ix = 0; ptr && ix < max_allocs;) + { + uint16_t val = (uint16_t) rand(); + ptr = alloc_1D(length, 0, val); + if (ptr) + { + mem[ix].val = val; + mem[ix].bufPtr = ptr; + ix++; + } + } + + P(":: Allocated %d buffers", ix); + + while (ix--) + { + ERR_ADD(res, free_1D(length, 0, mem[ix].val, mem[ix].bufPtr)); + } + FREE(mem); + return res; +} + +/** + * This method tests the allocation and freeing of a number of + * 2D tiled buffers (up to MAX_ALLOCS) + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * @param fmt Pixel format + * + * @return 0 on success, non-0 error value on failure + */ +int maxalloc_2D_test(pixels_t width, pixels_t height, pixel_fmt_t fmt, int max_allocs) +{ + printf("Allocate & Free max # of %ux%ux%ub 1D buffers\n", width, height, def_bpp(fmt)); + + struct data { + uint16_t val; + void *bufPtr; + } *mem; + + /* allocate as many buffers as we can */ + mem = NEWN(struct data, max_allocs); + void *ptr = (void *)mem; + int ix, res = 0; + for (ix = 0; ptr && ix < max_allocs;) + { + uint16_t val = (uint16_t) rand(); + ptr = alloc_2D(width, height, fmt, 0, val); + if (ptr) + { + mem[ix].val = val; + mem[ix].bufPtr = ptr; + ix++; + } + } + + P(":: Allocated %d buffers", ix); + + while (ix--) + { + ERR_ADD(res, free_2D(width, height, fmt, 0, mem[ix].val, mem[ix].bufPtr)); + } + FREE(mem); + return res; +} + +/** + * This method tests the allocation and freeing of a number of + * NV12 tiled buffers (up to MAX_ALLOCS) + * + * @author a0194118 (9/7/2009) + * + * @param width Buffer width + * @param height Buffer height + * + * @return 0 on success, non-0 error value on failure + */ +int maxalloc_NV12_test(pixels_t width, pixels_t height, int max_allocs) +{ + printf("Allocate & Free max # of %ux%u NV12 buffers\n", width, height); + + struct data { + uint16_t val; + void *bufPtr; + } *mem; + + /* allocate as many buffers as we can */ + mem = NEWN(struct data, max_allocs); + void *ptr = (void *)mem; + int ix, res = 0; + for (ix = 0; ptr && ix < max_allocs;) + { + uint16_t val = (uint16_t) rand(); + ptr = alloc_NV12(width, height, val); + if (ptr) + { + mem[ix].val = val; + mem[ix].bufPtr = ptr; + ix++; + } + } + + P(":: Allocated %d buffers", ix); + + while (ix--) + { + ERR_ADD(res, free_NV12(width, height, mem[ix].val, mem[ix].bufPtr)); + } + FREE(mem); + return res; +} + +/** + * This method tests the mapping and unnapping of a number of + * 1D buffers (up to MAX_ALLOCS) + * + * @author a0194118 (9/7/2009) + * + * @param length Buffer length + * + * @return 0 on success, non-0 error value on failure + */ +int maxmap_1D_test(bytes_t length, int max_maps) +{ + length = (length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); + printf("Map & UnMap max # of %xb 1D buffers\n", length); + +#ifdef __MAP_OK__ + struct data { + uint16_t val; + void *bufPtr, *buffer, *dataPtr; + } *mem; + + /* map as many buffers as we can */ + mem = NEWN(struct data, max_maps); + void *ptr = (void *)mem; + int ix, res = 0; + for (ix = 0; ptr && ix < max_maps;) + { + /* allocate aligned buffer */ + ptr = malloc(length + PAGE_SIZE - 1); + if (ptr) + { + void *buffer = ptr; + void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + uint16_t val = (uint16_t) rand(); + ptr = map_1D(dataPtr, length, 0, val); + if (ptr) + { + mem[ix].val = val; + mem[ix].bufPtr = ptr; + mem[ix].buffer = buffer; + mem[ix].dataPtr = dataPtr; + ix++; + } + else + { + FREE(buffer); + break; + } + } + } + + P(":: Mapped %d buffers", ix); + + while (ix--) + { + ERR_ADD(res, unmap_1D(mem[ix].dataPtr, length, 0, mem[ix].val, mem[ix].bufPtr)); + FREE(mem[ix].buffer); + } +#else + int res = TESTERR_NOTIMPLEMENTED; +#endif + return res; +} + +/** + * This stress tests allocates/maps/frees/unmaps buffers at + * least num_ops times. The test maintains a set of slots that + * are initially NULL. For each operation, a slot is randomly + * selected. If the slot is not used, it is filled randomly + * with a 1D, 2D, NV12 or mapped buffer. If it is used, the + * slot is cleared by freeing/unmapping the buffer already + * there. The buffers are filled on alloc/map and this is + * checked on free/unmap to verify that there was no memory + * corruption. Failed allocation and maps are ignored as we may + * run out of memory. The return value is the first error code + * encountered, or 0 on success. + * + * This test sets the seed so that it produces reproducible + * results. + * + * @author a0194118 (9/7/2009) + * + * @param num_ops Number of operations to perform + * @param num_slots Number of slots to maintain + * + * @return 0 on success, non-0 error value on failure + */ +int star_test(uint32_t num_ops, uint16_t num_slots) +{ + printf("Random set of %d Allocs/Maps and Frees/UnMaps for %d slots\n", num_ops, num_slots); + srand(0x4B72316A); + struct data { + int op; + uint16_t val; + pixels_t width, height; + bytes_t length; + void *bufPtr; + void *buffer; + void *dataPtr; + } *mem; + + /* allocate memory state */ + mem = NEWN(struct data, num_slots); + if (!mem) return NOT_P(mem,!=,NULL); + + /* perform alloc/free/unmaps */ + int res = 0, ix; + while (!res && num_ops--) + { + ix = rand() % num_slots; + /* see if we need to free/unmap data */ + if (mem[ix].bufPtr) + { + /* check memory fill */ + switch (mem[ix].op) + { + case 0: res = unmap_1D(mem[ix].dataPtr, mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr); + FREE(mem[ix].buffer); + break; + case 1: res = free_1D(mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr); break; + case 2: res = free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_8BIT, 0, mem[ix].val, mem[ix].bufPtr); break; + case 3: res = free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_16BIT, 0, mem[ix].val, mem[ix].bufPtr); break; + case 4: res = free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_32BIT, 0, mem[ix].val, mem[ix].bufPtr); break; + case 5: res = free_NV12(mem[ix].width, mem[ix].height, mem[ix].val, mem[ix].bufPtr); break; + } + P("%s[%p]", mem[ix].op ? "free" : "unmap", mem[ix].bufPtr); + ZERO(mem[ix]); + } + /* we need to allocate/map data */ + else + { + int op = rand(); + /* set width */ + pixels_t width, height; + switch ("AAAABBBBCCCDDEEF"[op & 15]) { + case 'F': width = 1920; height = 1080; break; + case 'E': width = 1280; height = 720; break; + case 'D': width = 640; height = 480; break; + case 'C': width = 848; height = 480; break; + case 'B': width = 176; height = 144; break; + case 'A': width = height = 64; break; + } + mem[ix].length = (bytes_t)width * height; + mem[ix].width = width; + mem[ix].height = height; + mem[ix].val = ((uint16_t)rand()); + + /* perform operation */ + mem[ix].op = "AAABBBBCCCCDDDDE"[(op >> 4) & 15] - 'A'; + switch (mem[ix].op) + { + case 0: /* map 1D buffer */ +#ifdef __MAP_OK__ + /* allocate aligned buffer */ + mem[ix].length = (mem[ix].length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); + mem[ix].buffer = malloc(mem[ix].length + PAGE_SIZE - 1); + if (mem[ix].buffer) + { + mem[ix].dataPtr = (void *)(((uint32_t)mem[ix].buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + mem[ix].bufPtr = map_1D(mem[ix].dataPtr, mem[ix].length, 0, mem[ix].val); + if (!mem[ix].bufPtr) FREE(mem[ix].buffer); + } + P("map[l=0x%x] = %p", mem[ix].length, mem[ix].bufPtr); + break; +#else + mem[ix].op = 1; +#endif + case 1: + mem[ix].bufPtr = alloc_1D(mem[ix].length, 0, mem[ix].val); + P("alloc[l=0x%x] = %p", mem[ix].length, mem[ix].bufPtr); + break; + case 2: + mem[ix].bufPtr = alloc_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_8BIT, 0, mem[ix].val); + P("alloc[%d*%d*8] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); + break; + case 3: + mem[ix].bufPtr = alloc_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_16BIT, 0, mem[ix].val); + P("alloc[%d*%d*16] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); + break; + case 4: + mem[ix].bufPtr = alloc_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_32BIT, 0, mem[ix].val); + P("alloc[%d*%d*32] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); + break; + case 5: + mem[ix].bufPtr = alloc_NV12(mem[ix].width, mem[ix].height, mem[ix].val); + P("alloc[%d*%d*NV12] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); + break; + } + + /* check all previous buffers */ +#ifdef STAR_TRACE_MEM + for (ix = 0; ix < num_slots; ix++) + { + MemAllocBlock blk; + if (mem[ix].bufPtr) + { + if(0) P("ptr=%p, op=%d, w=%d, h=%d, l=%x, val=%x", + mem[ix].bufPtr, mem[ix].op, mem[ix].width, mem[ix].height, + mem[ix].length, mem[ix].val); + switch (mem[ix].op) + { + case 0: case 1: + blk.pixelFormat = PIXEL_FMT_PAGE; + blk.dim.len = mem[ix].length; + break; + case 5: + blk.pixelFormat = PIXEL_FMT_16BIT; + blk.dim.area.width = mem[ix].width >> 1; + blk.dim.area.height = mem[ix].height >> 1; + blk.stride = def_stride(mem[ix].width); /* same for Y and UV */ + blk.ptr = mem[ix].bufPtr + mem[ix].height * blk.stride; + check_mem(mem[ix].val, &blk); + case 2: + blk.pixelFormat = PIXEL_FMT_8BIT; + blk.dim.area.width = mem[ix].width; + blk.dim.area.height = mem[ix].height; + blk.stride = def_stride(mem[ix].width); + break; + case 3: + blk.pixelFormat = PIXEL_FMT_16BIT; + blk.dim.area.width = mem[ix].width; + blk.dim.area.height = mem[ix].height; + blk.stride = def_stride(mem[ix].width * 2); + break; + case 4: + blk.pixelFormat = PIXEL_FMT_32BIT; + blk.dim.area.width = mem[ix].width; + blk.dim.area.height = mem[ix].height; + blk.stride = def_stride(mem[ix].width * 4); + break; + } + blk.ptr = mem[ix].bufPtr; + check_mem(mem[ix].val, &blk); + } + } +#endif + } + } + + /* unmap and free everything */ + for (ix = 0; ix < num_slots; ix++) + { + if (mem[ix].bufPtr) + { + /* check memory fill */ + switch (mem[ix].op) + { + case 0: ERR_ADD(res, unmap_1D(mem[ix].dataPtr, mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr)); + FREE(mem[ix].buffer); + break; + case 1: ERR_ADD(res, free_1D(mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr)); break; + case 2: ERR_ADD(res, free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_8BIT, 0, mem[ix].val, mem[ix].bufPtr)); break; + case 3: ERR_ADD(res, free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_16BIT, 0, mem[ix].val, mem[ix].bufPtr)); break; + case 4: ERR_ADD(res, free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_32BIT, 0, mem[ix].val, mem[ix].bufPtr)); break; + case 5: ERR_ADD(res, free_NV12(mem[ix].width, mem[ix].height, mem[ix].val, mem[ix].bufPtr)); break; + } + } + } + FREE(mem); + + return res; +} + +/** + * This stress tests allocates/maps/frees/unmaps buffers at + * least num_ops times. The test maintains a set of slots that + * are initially NULL. For each operation, a slot is randomly + * selected. If the slot is not used, it is filled randomly + * with a 1D, 2D, NV12 or mapped buffer. If it is used, the + * slot is cleared by freeing/unmapping the buffer already + * there. The buffers are filled on alloc/map and this is + * checked on free/unmap to verify that there was no memory + * corruption. Failed allocation and maps are ignored as we may + * run out of memory. The return value is the first error code + * encountered, or 0 on success. + * + * This test sets the seed so that it produces reproducible + * results. + * + * @author a0194118 (9/7/2009) + * + * @param num_ops Number of operations to perform + * @param num_slots Number of slots to maintain + * + * @return 0 on success, non-0 error value on failure + */ +int star_tiler_test(uint32_t num_ops, uint16_t num_slots) +{ + printf("Random set of %d tiler Allocs/Maps and Frees/UnMaps for %d slots\n", num_ops, num_slots); + srand(0x4B72316A); + struct data { + int op; + struct tiler_block_info blk; + void *buffer; + } *mem; + + /* allocate memory state */ + mem = NEWN(struct data, num_slots); + if (!mem) return NOT_P(mem,!=,NULL); + + /* perform alloc/free/unmaps */ + int ix, td = A_S(open("/dev/tiler", O_RDWR),>=,0), res = td < 0 ? td : 0; + while (!res && num_ops--) + { + ix = rand() % num_slots; + /* see if we need to free/unmap data */ + if (mem[ix].blk.id) + { + P("free [0x%x(0x%x)]", mem[ix].blk.id, mem[ix].blk.ssptr); + res = A_S(ioctl(td, TILIOC_FBLK, &mem[ix].blk),==,0); + FREE(mem[ix].buffer); + ZERO(mem[ix]); + } + /* we need to allocate/map data */ + else + { + int op = rand(); + /* set width */ + pixels_t width, height; + switch ("AAAABBBBCCCDDEEF"[op & 15]) { + case 'F': width = 1920; height = 1080; break; + case 'E': width = 1280; height = 720; break; + case 'D': width = 640; height = 480; break; + case 'C': width = 848; height = 480; break; + case 'B': width = 176; height = 144; break; + case 'A': width = height = 64; break; + } + bytes_t length = (bytes_t)width * height; + + /* perform operation */ + mem[ix].op = "AAABBBBCCCCDDDDE"[(op >> 4) & 15] - 'A'; + switch (mem[ix].op) + { + case 0: /* map 1D buffer */ + /* allocate aligned buffer */ + length = (length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); + mem[ix].buffer = malloc(length + PAGE_SIZE - 1); + if (mem[ix].buffer) + { + mem[ix].blk.dim.len = length; + mem[ix].blk.fmt = TILFMT_PAGE; + mem[ix].blk.ptr = (void *)(((uint32_t)mem[ix].buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + res = A_S(ioctl(td, TILIOC_MBLK, &mem[ix].blk),==,0); + if (res) + FREE(mem[ix].buffer); + } + P("map[l=0x%x] = 0x%x(0x%x)", length, mem[ix].blk.id, mem[ix].blk.ssptr); + break; + case 1: + mem[ix].blk.dim.len = length; + mem[ix].blk.fmt = TILFMT_PAGE; + res = A_S(ioctl(td, TILIOC_GBLK, &mem[ix].blk),==,0); + P("alloc[l=0x%x] = 0x%x(0x%x)", length, mem[ix].blk.id, mem[ix].blk.ssptr); + break; + case 2: case 3: case 4: + mem[ix].blk.dim.area.width = width; + mem[ix].blk.dim.area.height = height; + mem[ix].blk.fmt = TILFMT_8BIT + mem[ix].op - 2; + res = A_S(ioctl(td, TILIOC_GBLK, &mem[ix].blk),==,0); + P("alloc[%d*%d*%d] = 0x%x(0x%x)", width, height, 8 << (mem[ix].op -2), mem[ix].blk.id, mem[ix].blk.ssptr); + break; + } + } + } + + /* unmap and free everything */ + for (ix = 0; ix < num_slots; ix++) + { + if (mem[ix].blk.id) + { + res = A_S(ioctl(td, TILIOC_FBLK, &mem[ix].blk),==,0); + FREE(mem[ix].buffer); + } + } + ERR_ADD_S(res, close(td)); + FREE(mem); + + return res; +} + +#define NEGA(exp) ({ void *__ptr__ = A_P(exp,==,NULL); if (__ptr__) MemMgr_Free(__ptr__); __ptr__ != NULL; }) + +/** + * Performs negative tests for MemMgr_Alloc. + * + * @author a0194118 (9/7/2009) + * + * @return 0 on success, non-0 error value on failure + */ +int neg_alloc_tests() +{ + printf("Negative Alloc tests\n"); + + MemAllocBlock block[2], *blk; + memset(&block, 0, sizeof(block)); + + int ret = 0, num_blocks; + + for (num_blocks = 1; num_blocks < 3; num_blocks++) + { + blk = block + num_blocks - 1; + + P("/* bad pixel format */"); + blk->pixelFormat = PIXEL_FMT_MIN - 1; + blk->dim.len = PAGE_SIZE; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + blk->pixelFormat = PIXEL_FMT_MAX + 1; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + + P("/* bad 1D stride */"); + blk->pixelFormat = PIXEL_FMT_PAGE; + blk->stride = PAGE_SIZE - 1; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + + P("/* 0 1D length */"); + blk->dim.len = blk->stride = 0; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + + P("/* bad 2D stride */"); + blk->pixelFormat = PIXEL_FMT_8BIT; + blk->dim.area.width = PAGE_SIZE - 1; + blk->stride = PAGE_SIZE - 1; + blk->dim.area.height = 16; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + + P("/* bad 2D width */"); + blk->stride = blk->dim.area.width = 0; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + + P("/* bad 2D height */"); + blk->dim.area.height = 0; + blk->dim.area.width = 16; + ret |= NEGA(MemMgr_Alloc(block, num_blocks)); + + /* good 2D block */ + blk->dim.area.height = 16; + } + + block[0].pixelFormat = block[1].pixelFormat = PIXEL_FMT_8BIT; + block[0].dim.area.width = 16384; + block[0].dim.area.height = block[1].dim.area.width = 16; + block[1].dim.area.height = 8192; + ret |= NEGA(MemMgr_Alloc(block, 2)); + + return ret; +} + +/** + * Performs negative tests for MemMgr_Free. + * + * @author a0194118 (9/7/2009) + * + * @return 0 on success, non-0 error value on failure + */ +int neg_free_tests() +{ + printf("Negative Free tests\n"); + + void *ptr = alloc_2D(2500, 10, PIXEL_FMT_16BIT, 2 * PAGE_SIZE, 0); + int ret = 0; + + MemMgr_Free(ptr); + + P("/* free something twice */"); + ret |= NOT_I(MemMgr_Free(ptr),!=,0); + + P("/* free NULL */"); + ret |= NOT_I(MemMgr_Free(NULL),!=,0); + + P("/* free arbitrary value */"); + ret |= NOT_I(MemMgr_Free((void *)0x12345678),!=,0); + + P("/* free mapped buffer */"); + void *buffer = malloc(PAGE_SIZE * 2); + void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + ptr = map_1D(dataPtr, PAGE_SIZE, 0, 0); + ret |= NOT_I(MemMgr_Free(ptr),!=,0); + + MemMgr_UnMap(ptr); + + return ret; +} + +#define NEGM(exp) ({ void *__ptr__ = A_P(exp,==,NULL); if (__ptr__) MemMgr_UnMap(__ptr__); __ptr__ != NULL; }) + +/** + * Performs negative tests for MemMgr_Map. + * + * @author a0194118 (9/7/2009) + * + * @return 0 on success, non-0 error value on failure + */ +int neg_map_tests() +{ + printf("Negative Map tests\n"); + + MemAllocBlock block[2], *blk; + memset(&block, 0, sizeof(block)); + + int ret = 0, num_blocks; + + for (num_blocks = 1; num_blocks < 3; num_blocks++) + { + blk = block + num_blocks - 1; + + P("/* bad pixel format */"); + blk->pixelFormat = PIXEL_FMT_MIN - 1; + blk->dim.len = PAGE_SIZE; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + blk->pixelFormat = PIXEL_FMT_MAX + 1; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + + P("/* bad 1D stride */"); + blk->pixelFormat = PIXEL_FMT_PAGE; + blk->stride = PAGE_SIZE - 1; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + + P("/* 0 1D length */"); + blk->dim.len = blk->stride = 0; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + + P("/* bad 2D stride */"); + blk->pixelFormat = PIXEL_FMT_8BIT; + blk->dim.area.width = PAGE_SIZE - 1; + blk->stride = PAGE_SIZE - 1; + blk->dim.area.height = 16; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + + P("/* bad 2D width */"); + blk->stride = blk->dim.area.width = 0; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + + P("/* bad 2D height */"); + blk->dim.area.height = 0; + blk->dim.area.width = 16; + ret |= NEGM(MemMgr_Map(block, num_blocks)); + + /* good 2D block */ + blk->dim.area.height = 16; + } + + P("/* 2 buffers */"); + ret |= NEGM(MemMgr_Map(block, 2)); + + P("/* 1 2D buffer */"); + ret |= NEGM(MemMgr_Map(block, 1)); + + P("/* 1 1D buffer with no address */"); + block[0].pixelFormat = PIXEL_FMT_PAGE; + block[0].dim.len = 2 * PAGE_SIZE; + block[0].ptr = NULL; + ret |= NEGM(MemMgr_Map(block, 1)); + + P("/* 1 1D buffer with not aligned start address */"); + void *buffer = malloc(3 * PAGE_SIZE); + void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + block[0].ptr = dataPtr + 3; + ret |= NEGM(MemMgr_Map(block, 1)); + + P("/* 1 1D buffer with not aligned length */"); + block[0].ptr = dataPtr; + block[0].dim.len -= 5; + ret |= NEGM(MemMgr_Map(block, 1)); + +#if 0 /* TODO: it's possible that our va falls within the TILER addr range */ + P("/* Mapping a tiled 1D buffer */"); + void *ptr = alloc_1D(PAGE_SIZE * 2, 0, 0); + dataPtr = (void *)(((uint32_t)ptr + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + block[0].ptr = dataPtr; + block[0].dim.len = PAGE_SIZE; + ret |= NEGM(MemMgr_Map(block, 1)); + + MemMgr_Free(ptr); +#endif + + return ret; +} + +/** + * Performs negative tests for MemMgr_UnMap. + * + * @author a0194118 (9/7/2009) + * + * @return 0 on success, non-0 error value on failure + */ +int neg_unmap_tests() +{ + printf("Negative Unmap tests\n"); + + void *ptr = alloc_1D(PAGE_SIZE, 0, 0); + int ret = 0; + + P("/* unmap alloced buffer */"); + ret |= NOT_I(MemMgr_UnMap(ptr),!=,0); + + MemMgr_Free(ptr); + + void *buffer = malloc(PAGE_SIZE * 2); + void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); + ptr = map_1D(dataPtr, PAGE_SIZE, 0, 0); + MemMgr_UnMap(ptr); + + P("/* unmap something twice */"); + ret |= NOT_I(MemMgr_UnMap(ptr),!=,0); + + P("/* unmap NULL */"); + ret |= NOT_I(MemMgr_UnMap(NULL),!=,0); + + P("/* unmap arbitrary value */"); + ret |= NOT_I(MemMgr_UnMap((void *)0x12345678),!=,0); + + return ret; +} + +/** + * Performs negative tests for MemMgr_Is.. functions. + * + * @author a0194118 (9/7/2009) + * + * @return 0 on success, non-0 error value on failure + */ +int neg_check_tests() +{ + printf("Negative Is... tests\n"); + void *ptr = malloc(32); + + int ret = 0; + + ret |= NOT_I(MemMgr_Is1DBlock(NULL),==,FALSE); + ret |= NOT_I(MemMgr_Is1DBlock((void *)0x12345678),==,FALSE); + ret |= NOT_I(MemMgr_Is1DBlock(ptr),==,FALSE); + ret |= NOT_I(MemMgr_Is2DBlock(NULL),==,FALSE); + ret |= NOT_I(MemMgr_Is2DBlock((void *)0x12345678),==,FALSE); + ret |= NOT_I(MemMgr_Is2DBlock(ptr),==,FALSE); + ret |= NOT_I(MemMgr_IsMapped(NULL),==,FALSE); + ret |= NOT_I(MemMgr_IsMapped((void *)0x12345678),==,FALSE); + ret |= NOT_I(MemMgr_IsMapped(ptr),==,FALSE); + + ret |= NOT_I(MemMgr_GetStride(NULL),==,0); + ret |= NOT_I(MemMgr_GetStride((void *)0x12345678),==,0); + ret |= NOT_I(MemMgr_GetStride(ptr),==,PAGE_SIZE); + + ret |= NOT_P(TilerMem_VirtToPhys(NULL),==,0); + ret |= NOT_P(TilerMem_VirtToPhys((void *)0x12345678),==,0); + ret |= NOT_P(TilerMem_VirtToPhys(ptr),!=,0); + + ret |= NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(NULL)),==,0); + ret |= NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys((void *)0x12345678)),==,0); + ret |= NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(ptr)),==,0); + + FREE(ptr); + + return ret; +} + +DEFINE_TESTS(TESTS) + +/** + * We run the same identity check before and after running the + * tests. + * + * @author a0194118 (9/12/2009) + */ +void memmgr_identity_test(void *ptr) +{ + /* also execute internal unit tests - this also verifies that we did not + keep any references */ + __test__MemMgr(); +} + +/** + * Main test function. Checks arguments for test case ranges, + * runs tests and prints usage or test list if required. + * + * @author a0194118 (9/7/2009) + * + * @param argc Number of arguments + * @param argv Arguments + * + * @return -1 on usage or test list, otherwise # of failed + * tests. + */ +int main(int argc, char **argv) +{ + return TestLib_Run(argc, argv, + memmgr_identity_test, memmgr_identity_test, NULL); +} + diff --git a/tiler/testlib.c b/tiler/testlib.c new file mode 100644 index 0000000..63d1298 --- /dev/null +++ b/tiler/testlib.c @@ -0,0 +1,163 @@ +/* + * testlib.c + * + * Unit test interface. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* retrieve type definitions */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "testlib.h" + +#include <utils.h> +#include <debug_utils.h> + +#define TESTLIB_OK 0 +#define TESTLIB_FAIL 1 + +/** Returns TRUE iff str is a whole unsigned int */ +#define is_uint(str) \ + ({ unsigned i; char c; sscanf(str, "%u%c", &i, &c) == 1; }) + +extern int __internal__TestLib_DoList(int id); + +/** + * Prints test result and returns summary result + * + * @author a0194118 (9/7/2009) + * + * @param res Test result + * + * @return TEST_RESULT_OK on success, TEST_RESULT_FAIL on + * failure, TEST_RESULT_UNAVAILABLE if test is not + * available + */ +int __internal__TestLib_Report(int res) +{ + switch (res) + { + case TESTLIB_UNAVAILABLE: + printf("==> TEST NOT AVAILABLE\n"); + fflush(stdout); + return TESTLIB_UNAVAILABLE; + case 0: + printf("==> TEST OK\n"); + fflush(stdout); + return TESTLIB_OK; + default: + printf("==> TEST FAIL(%d)\n", res); + fflush(stdout); + return TESTLIB_FAIL; + } +} + +void __internal__TestLib_NullFn(void *ptr) +{ +} + +int TestLib_Run(int argc, char **argv, void(*init_fn)(void *), + void(*exit_fn)(void *), void *ptr) +{ + int start, end, res, failed = 0, succeeded = 0, unavailable = 0; + + /* all tests */ + if (argc == 1) + { + start = 1; end = -1; + } + /* test list */ + else if (argc == 2 && !strcmp(argv[1], "list")) + { + __internal__TestLib_DoList(0); + return -1; + } + /* single test */ + else if (argc == 2 && is_uint(argv[1])) + { + start = end = atoi(argv[1]); + } + /* open range .. b */ + else if (argc == 3 && !strcmp(argv[1], "..") && is_uint(argv[2])) + { + start = 1; + end = atoi(argv[2]); + } + /* open range a .. */ + else if (argc == 3 && !strcmp(argv[2], "..") && is_uint(argv[1])) + { + start = atoi(argv[1]); + end = -1; + } + else if (argc == 4 && !strcmp(argv[2], "..") && is_uint(argv[1]) && is_uint(argv[3])) + { + start = atoi(argv[1]); + end = atoi(argv[3]); + } + else + { + fprintf(stderr, "Usage: %s [<range>], where <range> is\n" + " empty: run all tests\n" + " list: list tests\n" + " ix: run test #ix\n" + " a ..: run tests #a, #a+1, ...\n" + " .. b: run tests #1, #2, .. #b\n" + " a .. b: run tests #a, #a+1, .. #b\n", argv[0]); + fflush(stderr); + return -1; + } + + /* execute tests */ + init_fn(ptr); + + do + { + res = __internal__TestLib_DoList(start++); + if (res == TESTLIB_FAIL) failed++; + else if (res == TESTLIB_OK) succeeded++; + else if (res == TESTLIB_UNAVAILABLE) unavailable++; + printf("so far FAILED: %d, SUCCEEDED: %d, UNAVAILABLE: %d\n", failed, succeeded, + unavailable); + fflush(stdout); + } while (res != TESTLIB_INVALID && (end < 0 || start <= end)); + + printf("FAILED: %d, SUCCEEDED: %d, UNAVAILABLE: %d\n", failed, succeeded, + unavailable); + fflush(stdout); + + /* also execute internal unit tests - this also verifies that we did not + keep any references */ + exit_fn(ptr); + + return failed; +} + diff --git a/tiler/testlib.h b/tiler/testlib.h new file mode 100644 index 0000000..bc1a799 --- /dev/null +++ b/tiler/testlib.h @@ -0,0 +1,101 @@ +/* + * testlib.h + * + * Unit test interface API. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TESTLIB_H_ +#define _TESTLIB_H_ + +/* error type definitions */ +#define TESTLIB_UNAVAILABLE -65378 +#define TESTLIB_INVALID -1 + +#define T(test) ++i; \ + if (!id || i == id) printf("TEST #% 3d - %s\n", i, #test); \ + if (i == id) { \ + printf("TEST_DESC - "); \ + fflush(stdout); \ + return __internal__TestLib_Report(test); \ + } + +/* test run function that must be defined from the test app */ + +/** + * Runs a specified test by id, or lists all test cases. This + * function uses the TESTS macros, and defines each T(test) to + * run a test starting from id == 1, and then return the result. + * + * @author a0194118 (9/7/2009) + * + * @param id Test case id, or 0 if only listing test cases + * + * @return Summary result: TEST_RESULT_OK, FAIL, INVALID or + * UNAVAILABLE. + */ +#define TESTS_ \ + int __internal__TestLib_DoList(int id) { int i = 0; + +#define _TESTS \ + return TESTLIB_INVALID; } + +#define DEFINE_TESTS(TESTS) TESTS_ TESTS _TESTS + +/* internal function prototypes and defines */ +extern int __internal__TestLib_Report(int res); +extern void __internal__TestLib_NullFn(void *ptr); + +#define nullfn __internal__TestLib_NullFn + +/** + * Parses argument list, prints usage on error, lists test + * cases, runs tests and reports results. + * + * @author a0194118 (9/12/2009) + * + * @param argc Number of test arguments + * @param argv Test argument array + * @param init_fn Initialization function of void fn(void *). + * This is called before the testing. + * @param exit_fn Deinit function of void fn(void *). This is + * done after the testing concludes. + * @param ptr Custom pointer that is passed into the + * initialization functions. + * + * @return # of test cases failed, 0 on success, -1 if no tests + * were run because of an error or a list request. + */ +int TestLib_Run(int argc, char **argv, void(*init_fn)(void *), + void(*exit_fn)(void *), void *ptr); + +#endif + diff --git a/tiler/tiler.h b/tiler/tiler.h new file mode 100644 index 0000000..8358f8d --- /dev/null +++ b/tiler/tiler.h @@ -0,0 +1,105 @@ +/* + * tiler.h + * + * TILER driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TILER_H_ +#define _TILER_H_ + +#define TILER_MEM_8BIT 0x60000000 +#define TILER_MEM_16BIT 0x68000000 +#define TILER_MEM_32BIT 0x70000000 +#define TILER_MEM_PAGED 0x78000000 +#define TILER_MEM_END 0x80000000 + +#define TILER_PAGE 0x1000 +#define TILER_WIDTH 256 +#define TILER_HEIGHT 128 +#define TILER_BLOCK_WIDTH 64 +#define TILER_BLOCK_HEIGHT 64 +#define TILER_LENGTH (TILER_WIDTH * TILER_HEIGHT * TILER_PAGE) + +#define TILER_DEVICE_PATH "/dev/tiler" +#define TILER_MAX_NUM_BLOCKS 16 + +enum tiler_fmt { + TILFMT_MIN = -2, + TILFMT_INVALID = -2, + TILFMT_NONE = -1, + TILFMT_8BIT = 0, + TILFMT_16BIT = 1, + TILFMT_32BIT = 2, + TILFMT_PAGE = 3, + TILFMT_MAX = 3, + TILFMT_8AND16 = 4, +}; + +struct area { + uint16_t width; + uint16_t height; +}; + +struct tiler_block_info { + enum tiler_fmt fmt; + union { + struct area area; + uint32_t len; + } dim; + uint32_t stride; + void *ptr; + uint32_t id; + uint32_t key; + uint32_t group_id; + uint32_t ssptr; +}; + +struct tiler_buf_info { + uint32_t num_blocks; + struct tiler_block_info blocks[TILER_MAX_NUM_BLOCKS]; + uint32_t offset; + uint32_t length; +}; + +#define TILIOC_GBLK _IOWR('z', 100, struct tiler_block_info) +#define TILIOC_FBLK _IOW('z', 101, struct tiler_block_info) +#define TILIOC_GSSP _IOWR('z', 102, uint32_t) +#define TILIOC_MBLK _IOWR('z', 103, struct tiler_block_info) +#define TILIOC_UMBLK _IOW('z', 104, struct tiler_block_info) +#define TILIOC_QBUF _IOWR('z', 105, struct tiler_buf_info) +#define TILIOC_RBUF _IOWR('z', 106, struct tiler_buf_info) +#define TILIOC_URBUF _IOWR('z', 107, struct tiler_buf_info) +#define TILIOC_QBLK _IOWR('z', 108, struct tiler_block_info) +#define TILIOC_PRBLK _IOW('z', 109, struct tiler_block_info) +#define TILIOC_URBLK _IOW('z', 110, uint32_t) + +#endif diff --git a/tiler/tiler_ptest.c b/tiler/tiler_ptest.c new file mode 100644 index 0000000..7f06940 --- /dev/null +++ b/tiler/tiler_ptest.c @@ -0,0 +1,729 @@ +/* + * tiler_ptest.c + * + * Memory Allocator Interface tests. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* retrieve type definitions */ +#define __DEBUG__ +#undef __DEBUG_ENTRY__ +#define __DEBUG_ASSERT__ + +#undef __WRITE_IN_STRIDE__ +#undef STAR_TRACE_MEM + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdint.h> +#include <ctype.h> + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif +#include <utils.h> +#include <list_utils.h> +#include <debug_utils.h> +#include <memmgr.h> +#include <tilermem.h> +#include <tilermem_utils.h> +#include <testlib.h> + +#define FALSE 0 + +/** + * Returns the default page stride for this block + * + * @author a0194118 (9/4/2009) + * + * @param width Width of 2D container + * + * @return Stride + */ +static bytes_t def_stride(pixels_t width) +{ + return (PAGE_SIZE - 1 + (bytes_t)width) & ~(PAGE_SIZE - 1); +} + +/** + * Returns the bytes per pixel for the pixel format. + * + * @author a0194118 (9/4/2009) + * + * @param pixelFormat Pixelformat + * + * @return Bytes per pixel + */ +static bytes_t def_bpp(pixel_fmt_t pixelFormat) +{ + return (pixelFormat == PIXEL_FMT_32BIT ? 4 : + pixelFormat == PIXEL_FMT_16BIT ? 2 : 1); +} + +enum ptr_type { + ptr_empty = 0, + ptr_alloced, + ptr_tiler_alloced, +}; + +struct ptr_info { + int num_blocks; + struct tiler_block_info blocks[TILER_MAX_NUM_BLOCKS]; + int ptr; + short type; + uint16_t val; +}; + +static void dump_block(struct tiler_block_info *blk, char *prefix, char *suffix) +{ + switch (blk->fmt) + { + case PIXEL_FMT_PAGE: + P("%s [p=%p(0x%x),l=0x%x,s=%d]%s", prefix, blk->ptr, blk->ssptr, + blk->dim.len, blk->stride, suffix); + break; + case PIXEL_FMT_8BIT: + case PIXEL_FMT_16BIT: + case PIXEL_FMT_32BIT: + P("%s [p=%p(0x%x),%d*%d*%d,s=%d]%s", prefix, blk->ptr, blk->ssptr, + blk->dim.area.width, blk->dim.area.height, def_bpp(blk->fmt) * 8, + blk->stride, suffix); + break; + default: + P("%s*[p=%p(0x%x),l=0x%x,s=%d,fmt=0x%x]%s", prefix, blk->ptr, + blk->ssptr, blk->dim.len, blk->stride, blk->fmt, suffix); + } +} + +static void dump_slot(struct ptr_info* buf, char* prefix) +{ + P("%sbuf={n=%d,ptr=0x%x,type=%d,", prefix, buf->num_blocks, buf->ptr, + buf->type); + int ix = 0; + for (ix = 0; ix < buf->num_blocks; ix++) + { + dump_block(buf->blocks + ix, "", ix + 1 == buf->num_blocks ? "}" : ""); + } +} + +/** + * This method fills up a range of memory using a start address + * and start value. The method of filling ensures that + * accidentally overlapping regions have minimal chances of + * matching, even if the same starting value is used. This is + * because the difference between successive values varies as + * such. This series only repeats after 704189 values, so the + * probability of a match for a range of at least 2 values is + * less than 2*10^-11. + * + * V(i + 1) - V(i) = { 1, 2, 3, ..., 65535, 2, 4, 6, 8 ..., + * 65534, 3, 6, 9, 12, ..., 4, 8, 12, 16, ... } + * + * @author a0194118 (9/6/2009) + * + * @param start start value + * @param block pointer to block info strucure + */ +void fill_mem(uint16_t start, MemAllocBlock *block) +{ + IN; + uint16_t *ptr = (uint16_t *)block->ptr, delta = 1, step = 1; + bytes_t height, width, stride, i; + if (block->pixelFormat == PIXEL_FMT_PAGE) + { + height = 1; + stride = width = block->dim.len; + } + else + { + height = block->dim.area.height; + width = block->dim.area.width; + stride = block->stride; + } + width *= def_bpp(block->pixelFormat); + bytes_t size = height * stride; + + P("(%p,0x%x*0x%x,s=0x%x)=0x%x", block->ptr, width, height, stride, start); + + CHK_I(width,<=,stride); + uint32_t *ptr32 = (uint32_t *)ptr; + while (height--) + { + if (block->pixelFormat == PIXEL_FMT_32BIT) + { + for (i = 0; i < width; i += sizeof(uint32_t)) + { + uint32_t val = (start & 0xFFFF) | (((uint32_t)(start + delta) & 0xFFFF) << 16); + *ptr32++ = val; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && (height || ((PAGE_SIZE - 1) & (uint32_t)ptr32))) + { + *ptr32++ = 0; + i += sizeof(uint32_t); + } +#else + ptr32 += (stride - i) / sizeof(uint32_t); +#endif + } + else + { + for (i = 0; i < width; i += sizeof(uint16_t)) + { + *ptr++ = start; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && (height || ((PAGE_SIZE - 1) & (uint32_t)ptr))) + { + *ptr++ = 0; + i += sizeof(uint16_t); + } +#else + ptr += (stride - i) / sizeof(uint16_t); +#endif + + } + } + CHK_P((block->pixelFormat == PIXEL_FMT_32BIT ? (void *)ptr32 : (void *)ptr),==, + (block->ptr + size)); + OUT; +} + +/** + * This verifies if a range of memory at a given address was + * filled up using the start value. + * + * @author a0194118 (9/6/2009) + * + * @param start start value + * @param block pointer to block info strucure + * + * @return 0 on success, non-0 error value on failure + */ +int check_mem(uint16_t start, MemAllocBlock *block) +{ + IN; + uint16_t *ptr = (uint16_t *)block->ptr, delta = 1, step = 1; + bytes_t height, width, stride, r, i; + if (block->pixelFormat == PIXEL_FMT_PAGE) + { + height = 1; + stride = width = block->dim.len; + } + else + { + height = block->dim.area.height; + width = block->dim.area.width; + stride = block->stride; + } + width *= def_bpp(block->pixelFormat); + + CHK_I(width,<=,stride); + uint32_t *ptr32 = (uint32_t *)ptr; + for (r = 0; r < height; r++) + { + if (block->pixelFormat == PIXEL_FMT_32BIT) + { + for (i = 0; i < width; i += sizeof(uint32_t)) + { + uint32_t val = (start & 0xFFFF) | (((uint32_t)(start + delta) & 0xFFFF) << 16); + if (*ptr32++ != val) { + DP("assert: val[%u,%u] (=0x%x) != 0x%x", r, i, *--ptr32, val); + return R_I(MEMMGR_ERR_GENERIC); + } + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && ((r < height - 1) || ((PAGE_SIZE - 1) & (uint32_t)ptr32))) + { + if (*ptr32++) { + DP("assert: val[%u,%u] (=0x%x) != 0", r, i, *--ptr32); + return R_I(MEMMGR_ERR_GENERIC); + } + i += sizeof(uint32_t); + } +#else + ptr32 += (stride - i) / sizeof(uint32_t); +#endif + } + else + { + for (i = 0; i < width; i += sizeof(uint16_t)) + { + if (*ptr++ != start) { + DP("assert: val[%u,%u] (=0x%x) != 0x%x", r, i, *--ptr, start); + return R_I(MEMMGR_ERR_GENERIC); + } + start += delta; + delta += step; + /* increase step if overflown */ + if (delta < step) delta = ++step; + } +#ifdef __WRITE_IN_STRIDE__ + while (i < stride && ((r < height - 1) || ((PAGE_SIZE - 1) & (uint32_t)ptr))) + { + if (*ptr++) { + DP("assert: val[%u,%u] (=0x%x) != 0", r, i, *--ptr); + return R_I(MEMMGR_ERR_GENERIC); + } + i += sizeof(uint16_t); + } +#else + ptr += (stride - i) / sizeof(uint16_t); +#endif + } + } + return R_I(MEMMGR_ERR_NONE); +} + +/** + * This method allocates a tiled buffer composed of an arbitrary + * set of tiled blocks. If successful, it checks + * that the block information was updated with the pointer to + * the block. Additionally, it verifies the correct return + * values for MemMgr_IsMapped, MemMgr_Is1DBlock, + * MemMgr_Is2DBlock, MemMgr_GetStride, TilerMem_GetStride. It + * also verifies TilerMem_VirtToPhys using an internally stored + * value of the ssptr. If any of these verifications fail, the + * buffer is freed. Otherwise, it is filled using the given + * start value. + * + * @author a0194118 (9/7/2009) + * + * @param num_blocks Number of blocks in the buffer + * @param blocks Block information + * @param val Fill start value + * @param bufPtr Pointer to the allocated buffer + * + * @return 0 on success, non-0 error value on failure + */ +void *alloc_buf(int num_blocks, MemAllocBlock blocks[], uint16_t val) +{ + void *bufPtr = MemMgr_Alloc(blocks, num_blocks); + void *ptr = bufPtr; + int i; + + for (i = 0; i < num_blocks; i++) + { + if (bufPtr) + { + pixel_fmt_t fmt = blocks[i].pixelFormat; + bytes_t cstride = (fmt == PIXEL_FMT_PAGE ? PAGE_SIZE : + fmt == PIXEL_FMT_8BIT ? TILER_STRIDE_8BIT : + fmt == PIXEL_FMT_16BIT ? TILER_STRIDE_16BIT : + TILER_STRIDE_32BIT); + if (NOT_P(blocks[i].ptr,==,ptr) || + NOT_I(MemMgr_IsMapped(ptr),!=,0) || + NOT_I(MemMgr_Is1DBlock(ptr),==,fmt == PIXEL_FMT_PAGE ? 1 : 0) || + NOT_I(MemMgr_Is2DBlock(ptr),==,fmt == PIXEL_FMT_PAGE ? 0 : 1) || + NOT_I(MemMgr_GetStride(bufPtr),==,blocks[i].stride) || + NOT_P(TilerMem_VirtToPhys(ptr),==,blocks[i].reserved) || + NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(ptr)),==,cstride) || + NOT_L((PAGE_SIZE - 1) & (long)ptr,==,(PAGE_SIZE - 1) & blocks[i].reserved) || + (fmt == PIXEL_FMT_PAGE || NOT_I(blocks[i].stride,!=,0))) + { + P(" for block %d", i); + MemMgr_Free(bufPtr); + return NULL; + } + fill_mem(val, blocks + i); + if (blocks[i].pixelFormat != PIXEL_FMT_PAGE) + { + ptr += def_stride(blocks[i].dim.area.width * + def_bpp(blocks[i].pixelFormat)) * blocks[i].dim.area.height; + } + else + { + ptr += def_stride(blocks[i].dim.len); + } + } + else + { + A_P(blocks[i].ptr,==,ptr); + A_I(blocks[i].reserved,==,0); + } + } + return bufPtr; +} + +/** + * This method frees a tiled buffer composed of an arbitrary set + * of tiled blocks. The given start value is used to verify that + * the buffer is still correctly filled. In the event of any + * errors, the error value is returned. + * + * @author a0194118 (9/7/2009) + * + * @param num_blocks Number of blocks in the buffer + * @param blocks Block information + * @param val Fill start value + * @param bufPtr Pointer to the allocated buffer + * + * @return 0 on success, non-0 error value on failure + */ +int free_buf(int num_blocks, MemAllocBlock blocks[], uint16_t val, void *bufPtr) +{ + MemAllocBlock blk; + void *ptr = bufPtr; + int ret = 0, i; + for (i = 0; i < num_blocks; i++) + { + blk = blocks[i]; + blk.ptr = ptr; + ERR_ADD(ret, check_mem(val, &blk)); + if (blk.pixelFormat != PIXEL_FMT_PAGE) + { + ptr += def_stride(blk.dim.area.width * + def_bpp(blk.pixelFormat)) * blk.dim.area.height; + } + else + { + ptr += def_stride(blk.dim.len); + } + blk.reserved = 0; + } + + ERR_ADD(ret, MemMgr_Free(bufPtr)); + return ret; +} + +#if 0 +struct slot { + int op; + SSPtr ssptr; + void *buffer; + void *dataPtr; +} *slots = NULL; + +enum op_enum { + op_map_1d, + op_alloc_1d, + op_alloc_8, + op_alloc_16, + op_alloc_32, + op_alloc_nv12, + op_alloc_gen, +}; + +static int free_slot(int ix) +{ + if (slots[ix].bufPtr) + { + /* check memory fill */ + switch (slots[ix].op) + { + case op_map_1d: + res = unmap_1D(slot[ix].dataPtr, slot[ix].length, 0, slot[ix].val, slot[ix].bufPtr); + FREE(mem[ix].buffer); + break; + case op_alloc_1d: + res = free_1D(slot[ix].length, 0, slot[ix].val, mem[ix].bufPtr); + break; + case op_alloc_8: + res = free_2D(slot[ix].width, slot[ix].height, PIXEL_FMT_8BIT, 0, slot[ix].val, slot[ix].bufPtr); + break; + case op_alloc_16: + res = free_2D(slot[ix].width, slot[ix].height, PIXEL_FMT_16BIT, 0, slot[ix].val, slot[ix].bufPtr); + break; + case op_alloc_32: + res = free_2D(slot[ix].width, slot[ix].height, PIXEL_FMT_32BIT, 0, slot[ix].val, slot[ix].bufPtr); + break; + case op_alloc_nv12: + res = free_NV12(slot[ix].width, slot[ix].height, slot[ix].val, slot[ix].bufPtr); + break; + } + P("%s[%p]", mem[ix].op ? "free" : "unmap", mem[ix].bufPtr); + ZERO(slot[ix]); + } +} +#endif + +#include <tilermgr.h> + +char *parse_num(char *p, int *tgt) +{ + int len; + if (!strncmp(p, "0x", 2)) { /* hex number */ + if (NOT_I(sscanf(p, "0x%x%n", tgt, &len),==,1)) + return NULL; + return p + len; + } else { + if (NOT_I(sscanf(p, "%d%n", tgt, &len),==,1)) + return NULL; + return p + len; + } +} + +/** + * Parametric memmgr test. This is similar to the star test + * except the operations are read from the command line: + * + * [#=]a:w*h*bits[,w*h*bits...] allocates a list of blocks as + * buffer # (it frees any previously allocated/mapped buffer + * f:# frees a buffer + * + * + * @author a0194118 (11/4/2009) + * + * @param argc + * @param argv + */ +int param_test(int argc, char **argv) +{ + int delta_slots = 16; + int ix, i, n, t, type, max_n, num_slots = delta_slots; + struct ptr_info *slots; + ALLOCN(slots, num_slots); + if (NOT_P(slots,!=,NULL)) return 1; + + int res = TilerMgr_Open(); + for (i = 1; i < argc && !res; i++) + { + uint16_t val = (uint16_t) rand(); + + char *p = argv[i], *q; + struct ptr_info buf; + ZERO(buf); + + /* read slot */ + ix = -1; + if (isdigit(*p)) + { + res = 1; + q = parse_num(p, &ix); + if (NOT_P(q,!=,NULL) || NOT_I(ix,>,0)) break; + p = q; + if (NOT_I(*p++,==,'.')) break; + res = 0; + ix--; + } + + type = *p++; + /* get default slot */ + if (ix < 0) + { + switch (type) + { + /* allocation defaults to the 1st free slot */ + case 'a': + case 'A': + for (ix = 0; ix < num_slots && slots[ix].type; ix++); + break; + + /* frees default to the 1st used block */ + case 'f': + case 'F': + for (ix = 0; ix < num_slots && !slots[ix].type; ix++); + if (NOT_I(ix,<,num_slots)) res = 1; + break; + } + } + if (res) break; + + /* allocate more slots if needed */ + if (ix >= num_slots) + { + int more_slots = ROUND_UP_TO(ix + 1, delta_slots); + struct ptr_info *new_slots; + ALLOCN(new_slots, more_slots); + if (NOT_P(new_slots,!=,NULL)) break; + memcpy(new_slots, slots, sizeof(*slots) * num_slots); + FREE(slots); + slots = new_slots; + num_slots = more_slots; + } + + /* perform opertaion */ + res = 1; /* assume failure */ + switch (type) + { + case 'a': /* allocate */ + case 'A': /* tiler-allocate */ + switch (type) + { + case 'a': buf.type = ptr_alloced; max_n = TILER_MAX_NUM_BLOCKS; break; + case 'A': buf.type = ptr_tiler_alloced; max_n = 1; break; + } + if (ix < num_slots && NOT_I(slots[ix].type,==,ptr_empty)) break; + if (NOT_I(*p++,==,':')) break; + for (n = 0; *p && n < max_n; n++) { + /* read length or width */ + p = parse_num(p, (int *) &buf.blocks[n].dim.len); + if (NOT_P(p,!=,NULL)) break; + if (*p == '*') { /* 2d block */ + buf.blocks[n].dim.area.width = (uint16_t) buf.blocks[n].dim.len; + /* read height */ + p = parse_num(++p, &t); + if (NOT_P(p,!=,NULL) || NOT_I(*p++,==,'*')) break; + buf.blocks[n].dim.area.height = (uint16_t) t; + /* read bits */ + p = parse_num(p, &t); + if (NOT_P(p,!=,NULL)) break; + /* handle nv12 */ + if (t == 12 && n + 1 < max_n) { + buf.blocks[n + 1].dim.area.width = buf.blocks[n].dim.area.width >> 1; + buf.blocks[n + 1].dim.area.height = buf.blocks[n].dim.area.height >> 1; + buf.blocks[n].fmt = TILFMT_8BIT; + t = 16; + n++; + } + + buf.blocks[n].fmt = (t == 8 ? TILFMT_8BIT : + t == 16 ? TILFMT_16BIT : + t == 32 ? TILFMT_32BIT : TILFMT_INVALID); + if (NOT_I(buf.blocks[n].fmt,!=,TILFMT_INVALID)) break; + } else { /* 1d block */ + buf.blocks[n].fmt = TILFMT_PAGE; + } + if (*p && NOT_I(*p++,==,',')) break; + /* we're OK */ + res = 0; + } + if (res || *p) break; + /* allocate buffer */ + + buf.num_blocks = n; + buf.val = val; + if (buf.type == ptr_alloced) + { + dump_slot(&buf, "==(alloc)=>"); + buf.ptr = (int) alloc_buf(n, (MemAllocBlock *) buf.blocks, val); + dump_slot(&buf, "<=(alloc)=="); + } + else + { + dump_slot(&buf, "==(tiler_alloc)=>"); + if (buf.blocks[0].fmt == TILFMT_PAGE) + { + buf.ptr = (int) TilerMgr_PageModeAlloc(buf.blocks[0].dim.len); + } + else + { + buf.ptr =(int) TilerMgr_Alloc(buf.blocks[0].fmt, + buf.blocks[0].dim.area.width, + buf.blocks[0].dim.area.height); + } + buf.blocks[0].ssptr = (unsigned long) buf.ptr; + dump_slot(&buf, "<=(tiler_alloc)=="); + } + if (NOT_I(buf.ptr,!=,0)) res = 1; + else memcpy(slots + ix, &buf, sizeof(buf)); + break; + + case 'f': /* free */ + case 'F': /* tiler-free */ + memcpy(&buf, slots + ix, sizeof(buf)); + switch (type) + { + case 'f': + if (NOT_I(buf.type,==,ptr_alloced)) break; + dump_slot(&buf, "==(free)=>"); + res = free_buf(buf.num_blocks, (MemAllocBlock *) buf.blocks, + buf.val, (void *) buf.ptr); + P("<=(free)==: %d", res); + break; + case 'F': + if (NOT_I(buf.type,==,ptr_tiler_alloced)) break; + dump_slot(&buf, "==(tiler_free)=>"); + if (buf.blocks[0].fmt == TILFMT_PAGE) + { + res = TilerMgr_PageModeFree((SSPtr) buf.ptr); + } + else + { + res = TilerMgr_Free((SSPtr) buf.ptr); + } + P("<=(tiler_free)==: %d", res); + break; + } + ZERO(slots[ix]); + break; + } + } + + /* free any memmgr allocated blocks */ + for (ix = 0; ix < num_slots; ix++) + { + if (slots[ix].type == ptr_alloced) + { + dump_slot(slots + ix, "==(free)=>"); + int res_free = free_buf(slots[ix].num_blocks, (MemAllocBlock *) slots[ix].blocks, + slots[ix].val, (void *) slots[ix].ptr); + P("<=(free)==: %d", res_free); + ERR_ADD(res, res_free); + } + } + ERR_ADD(res, TilerMgr_Close()); + + FREE(slots); + return res; +} + +/** + * Main test function. Checks arguments for test case ranges, + * runs tests and prints usage or test list if required. + * + * @author a0194118 (9/7/2009) + * + * @param argc Number of arguments + * @param argv Arguments + * + * @return -1 on usage or test list, otherwise # of failed + * tests. + */ +int main(int argc, char **argv) +{ + int res = param_test(argc, argv); + P(res ? "FAILURE: %d" : "SUCCESS", res); + return res; +} + diff --git a/tiler/tilermem.h b/tiler/tilermem.h new file mode 100644 index 0000000..2c89d84 --- /dev/null +++ b/tiler/tilermem.h @@ -0,0 +1,79 @@ +/* + * tilermem.h + * + * Tiler Memory Interface functions for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TILERMEM_H_ +#define _TILERMEM_H_ + +/* retrieve type definitions */ +#include "mem_types.h" + +/** + * Tiler Memory Allocator is responsible for: + * <ol> + * <li>Getting the stride information for containers(???) or + * buffers + * <li>Converting virtual addresses to physical addresses. + * </ol> + */ + +/** + * Returns the tiler stride corresponding to the system space + * address. For 2D buffers it returns the container stride. For + * 1D buffers it returns the page size. For non-tiler buffers + * it returns 0. + * + * @author a0194118 (9/1/2009) + * + * @param ptr pointer to a virtual address + * + * @return The stride of the block that contains the address. + */ +bytes_t TilerMem_GetStride(SSPtr ssptr); + +/** + * Retrieves the physical system-space address that corresponds + * to the virtual address. + * + * @author a0194118 (9/1/2009) + * + * @param ptr pointer to a virtual address + * + * @return The physical system-space address that the virtual + * address refers to. If the virtual address is invalid + * or unmapped, it returns 0. + */ +SSPtr TilerMem_VirtToPhys(void *ptr); + +#endif diff --git a/tiler/tilermem_utils.h b/tiler/tilermem_utils.h new file mode 100644 index 0000000..1d6210d --- /dev/null +++ b/tiler/tilermem_utils.h @@ -0,0 +1,52 @@ +/* + * tilermem_utils.h + * + * Memory Allocator Interface internal definitions and functions needed for + * unit testing. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TILERMEM_UTILS_H_ +#define _TILERMEM_UTILS_H_ + +#include <tiler.h> + +#define TILER_PAGE_WIDTH 64 +#define TILER_PAGE_HEIGHT 64 + +#define TILER_STRIDE_8BIT (TILER_WIDTH * TILER_PAGE_WIDTH) +#define TILER_STRIDE_16BIT (TILER_WIDTH * TILER_PAGE_WIDTH * 2) +#define TILER_STRIDE_32BIT (TILER_WIDTH * TILER_PAGE_WIDTH * 2) + +#define PAGE_SIZE TILER_PAGE + +#endif + diff --git a/tiler/tilermgr.c b/tiler/tilermgr.c new file mode 100644 index 0000000..470de5c --- /dev/null +++ b/tiler/tilermgr.c @@ -0,0 +1,203 @@ +/* + * tilermgr.c + * + * TILER library support functions for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> /* strerror() */ +#include <fcntl.h> /* open() */ +#include <unistd.h> /* close() */ +#include <errno.h> +#include <sys/ioctl.h> +#include <tiler.h> +#include "tilermgr.h" +#include "mem_types.h" + + +#define TILERMGR_ERROR() \ + fprintf(stderr, "%s()::%d: errno(%d) - \"%s\"\n", \ + __FUNCTION__, __LINE__, errno, strerror(errno)); \ + fflush(stderr); + +static int fd; + +int TilerMgr_Close() +{ + close(fd); + return TILERMGR_ERR_NONE; +} + +int TilerMgr_Open() +{ + fd = open(TILER_DEVICE_PATH, O_RDWR); + if (fd < 0) { + TILERMGR_ERROR(); + return TILERMGR_ERR_GENERIC; + } + + return TILERMGR_ERR_NONE; +} + +SSPtr TilerMgr_Alloc(enum pixel_fmt_t pixfmt, pixels_t width, pixels_t height) +{ + int ret = -1; + struct tiler_block_info block = {0}; + + if (pixfmt < PIXEL_FMT_8BIT || pixfmt > PIXEL_FMT_32BIT) + return 0x0; + if (width <= 0 || width > TILER_WIDTH * 64) + return 0x0; + if (height <= 0 || height > TILER_HEIGHT * 64) + return 0x0; + + block.fmt = pixfmt; + block.dim.area.width = width; + block.dim.area.height = height; + + ret = ioctl(fd, TILIOC_GBLK, (unsigned long)(&block)); + if (ret < 0) { + TILERMGR_ERROR(); + return 0x0; + } + return block.ssptr; +} + +int TilerMgr_Free(SSPtr addr) +{ + int ret = -1; + struct tiler_block_info block = {0}; + + if (addr < TILER_MEM_8BIT || addr >= TILER_MEM_PAGED) + return TILERMGR_ERR_GENERIC; + + block.ssptr = addr; + + ret = ioctl(fd, TILIOC_FBLK, (unsigned long)(&block)); + if (ret < 0) { + TILERMGR_ERROR(); + return TILERMGR_ERR_GENERIC; + } + return TILERMGR_ERR_NONE; +} + +SSPtr TilerMgr_PageModeAlloc(bytes_t len) +{ + int ret = -1; + struct tiler_block_info block = {0}; + + if(len < 0 || len > TILER_LENGTH) + return 0x0; + + block.fmt = TILFMT_PAGE; + block.dim.len = len; + + ret = ioctl(fd, TILIOC_GBLK, (unsigned long)(&block)); + if (ret < 0) { + TILERMGR_ERROR(); + return 0x0; + } + return block.ssptr; +} + +int TilerMgr_PageModeFree(SSPtr addr) +{ + int ret = -1; + struct tiler_block_info block = {0}; + + if (addr < TILER_MEM_PAGED || addr >= TILER_MEM_END) + return TILERMGR_ERR_GENERIC; + + block.ssptr = addr; + + ret = ioctl(fd, TILIOC_FBLK, (unsigned long)(&block)); + if (ret < 0) { + TILERMGR_ERROR(); + return TILERMGR_ERR_GENERIC; + } + return TILERMGR_ERR_NONE; +} + +SSPtr TilerMgr_VirtToPhys(void *ptr) +{ + int ret = -1; + unsigned long tmp = 0x0; + + if(ptr == NULL) + return 0x0; + + tmp = (unsigned long)ptr; + ret = ioctl(fd, TILIOC_GSSP, tmp); + + return (SSPtr)ret; +} + +SSPtr TilerMgr_Map(void *ptr, bytes_t len) +{ + int ret = -1; + struct tiler_block_info block = {0}; + + if (len < 0 || len > TILER_LENGTH) + return 0x0; + + block.fmt = TILFMT_PAGE; + block.dim.len = len; + block.ptr = ptr; + + ret = ioctl(fd, TILIOC_MBLK, (unsigned long)(&block)); + if (ret < 0) { + TILERMGR_ERROR(); + return 0x0; + } + return block.ssptr; +} + +int TilerMgr_Unmap(SSPtr addr) +{ + int ret = -1; + struct tiler_block_info block = {0}; + + if (addr < TILER_MEM_PAGED || addr >= TILER_MEM_END) + return TILERMGR_ERR_GENERIC; + + block.ssptr = addr; + + ret = ioctl(fd, TILIOC_UMBLK, (unsigned long)(&block)); + if (ret < 0) { + TILERMGR_ERROR(); + return TILERMGR_ERR_GENERIC; + } + return TILERMGR_ERR_NONE; +} + diff --git a/tiler/tilermgr.h b/tiler/tilermgr.h new file mode 100644 index 0000000..cd76822 --- /dev/null +++ b/tiler/tilermgr.h @@ -0,0 +1,54 @@ +/* + * tilermgr.h + * + * TILER library support functions for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TILERMGR_H_ +#define _TILERMGR_H_ + +#include "mem_types.h" + +#define TILERMGR_ERR_NONE (0) +#define TILERMGR_ERR_GENERIC (-1) + +int TilerMgr_Open(); +int TilerMgr_Close(); +SSPtr TilerMgr_Alloc(enum pixel_fmt_t pixfmt, pixels_t width, pixels_t height); +int TilerMgr_Free(SSPtr ssptr); +SSPtr TilerMgr_PageModeAlloc(bytes_t length); +int TilerMgr_PageModeFree(SSPtr ssptr); +SSPtr TilerMgr_Map(void *ptr, bytes_t length); +int TilerMgr_Unmap(SSPtr ssptr); +SSPtr TilerMgr_VirtToPhys(void *ptr); + +#endif diff --git a/tiler/utils.h b/tiler/utils.h new file mode 100644 index 0000000..d194a43 --- /dev/null +++ b/tiler/utils.h @@ -0,0 +1,63 @@ +/* + * utils.h + * + * Utility definitions for the Memory Interface for TI OMAP processors. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +/* ---------- Generic Macros Used in Macros ---------- */ + +/* allocation macro */ +#define NEW(type) (type*)calloc(1, sizeof(type)) +#define NEWN(type,n) (type*)calloc(n, sizeof(type)) +#define ALLOC(var) var = calloc(1, sizeof(*var)) +#define ALLOCN(var,n) var = calloc(n, sizeof(*var)) + + +/* free variable and set it to NULL */ +#define FREE(var) do { free(var); var = NULL; } while(0) + +/* clear variable */ +#define ZERO(var) memset(&(var), 0, sizeof(var)) + +/* binary round methods */ +#define ROUND_DOWN_TO2POW(x, N) ((x) & ~((N)-1)) +#define ROUND_UP_TO2POW(x, N) ROUND_DOWN_TO2POW((x) + (N) - 1, N) + +/* regulare round methods */ +#define ROUND_DOWN_TO(x, N) ((x) / (N) * (N)) +#define ROUND_UP_TO(x, N) ROUND_DOWN_TO((x) + (N) - 1, N) + +#endif + diff --git a/tiler/utils_test.c b/tiler/utils_test.c new file mode 100644 index 0000000..c152125 --- /dev/null +++ b/tiler/utils_test.c @@ -0,0 +1,489 @@ +/* + * utils_test.c + * + * Memory Allocator Utility tests. + * + * Copyright (C) 2009-2011 Texas Instruments, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define __DEBUG__ +#define __DEBUG_ASSERT__ +#define __DEBUG_ENTRY__ + +#include <utils.h> +#include <list_utils.h> +#include <debug_utils.h> +#include "testlib.h" + +#define TESTS\ + T(test_new())\ + T(test_list())\ + T(test_ezlist())\ + T(test_dzlist())\ + T(test_plist())\ + T(test_mlist())\ + T(test_math()) + +#define F() in = head.next; +#define N(a) res |= NOT_P(in,!=,&head); \ + res |= NOT_P(in->me,!=,NULL) || NOT_I(in->me->data,==,a); in = in->next; +#define Z(a) res |= NOT_P(in,!=,&head); \ + res |= NOT_I(in->data,==,a); in = in->next; +#define L() res |= NOT_P(in,==,&head); + +int all_zero(int *p, int len) +{ + IN; + int ix = 0; + for (ix = 0; ix < len; ix ++) + { + if (p[ix]) + { + P("[%d]=%d\n", ix, p[ix]); + return R_I(1); + } + } + return R_I(0); +} + +int test_new() { + IN; + int *p; + p = NEW(int); + int res = NOT_I(all_zero(p, 1),==,0); + FREE(p); + res |= NOT_I(p,==,NULL); + p = NEWN(int, 8000); + res |= NOT_I(all_zero(p, 8000),==,0); + FREE(p); + p = NEWN(int, 1000000); + res |= NOT_I(all_zero(p, 1000000),==,0); + FREE(p); + return R_I(res); +} + +int test_list() { + IN; + + struct elem { + int data; + } *elA, *elB; + struct list { + struct elem *me; + struct list *last, *next; + } head, *inA, *inB, *in, *in_safe; + + /* initialization */ + DLIST_INIT(head); + int res = NOT_I(DLIST_IS_EMPTY(head),!=,0); + + /* add element at beginning of list */ + elA = NEW(struct elem); + elA->data = 1; + inA = NEW(struct list); + DLIST_ADD_AFTER(head, elA, *inA); + F()N(1)L(); + + /* add element after an element */ + elB = NEW(struct elem); + elB->data = 2; + inB = NEW(struct list); + DLIST_ADD_AFTER(*inA, elB, *inB); + F()N(1)N(2)L(); + + /* add element at the end of the list */ + elB = NEW(struct elem); + inB = NEW(struct list); + (DLIST_ADD_BEFORE(head, elB, *inB))->data = 3; + F()N(1)N(2)N(3)L(); + + /* move an element to another position or another list */ + DLIST_MOVE_AFTER(head, *inB); + F()N(3)N(1)N(2)L(); + + DLIST_MOVE_BEFORE(head, *inB); + F()N(1)N(2)N(3)L(); + + /* works even if the position is the same */ + DLIST_MOVE_BEFORE(head, *inB); + F()N(1)N(2)N(3)L(); + + res |= NOT_I(DLIST_FIRST(head)->data,==,1); + res |= NOT_I(DLIST_LAST(head)->data,==,3); + + DLIST_LOOP(head, in) { + P("%d", in->me->data); + } + P("."); + + /* remove elements */ + DLIST_SAFE_LOOP(head, in, in_safe) { + if (in->me->data > 1) + { + DLIST_REMOVE(*in); + FREE(in->me); + FREE(in); + } + } + F()N(1)L(); + + /* delete list */ + DLIST_SAFE_LOOP(head, in, in_safe) { + DLIST_REMOVE(*in); + FREE(in->me); + FREE(in); + } + F()L(); + + return R_I(res); +} + +int test_ezlist() { + IN; + + struct elem { + int data; + struct elem *me, *last, *next; + } *elA, *elB, head, *el, *el_safe, *in; + + /* initialization */ + DLIST_INIT(head); + int res = NOT_I(DLIST_IS_EMPTY(head),!=,0); + + /* add element at beginning of list */ + elA = NEW(struct elem); + elA->data = 1; + DLIST_ADD_AFTER(head, elA, *elA); + F()N(1)L(); + + /* add element after an element */ + elB = NEW(struct elem); + elB->data = 2; + DLIST_ADD_AFTER(*elA, elB, *elB); + F()N(1)N(2)L(); + + /* add element at the end of the list */ + elB = NEW(struct elem); + (DLIST_ADD_BEFORE(head, elB, *elB))->data = 3; + F()N(1)N(2)N(3)L(); + + /* move an element to another position or another list */ + DLIST_MOVE_AFTER(head, *elB); + F()N(3)N(1)N(2)L(); + + DLIST_MOVE_BEFORE(head, *elB); + F()N(1)N(2)N(3)L(); + + /* works even if the position is the same */ + DLIST_MOVE_BEFORE(head, *elB); + F()N(1)N(2)N(3)L(); + + res |= NOT_I(DLIST_FIRST(head)->data,==,1); + res |= NOT_I(DLIST_LAST(head)->data,==,3); + + DLIST_LOOP(head, el) { + P("%d", el->data); + } + P("."); + + /* remove elements */ + DLIST_SAFE_RLOOP(head, el, el_safe) { + if (el->me->data == 1) + { + DLIST_REMOVE(*el); + FREE(el); + } + } + F()N(2)N(3)L(); + + /* delete list */ + DLIST_SAFE_LOOP(head, el, el_safe) { + DLIST_REMOVE(*el); + FREE(el); + } + F()L(); + + return R_I(res); +} + +int test_dzlist() { + IN; + + struct elem { + int data; + struct elem *last, *next; + } *elA, *elB, head, *el, *el_safe, *in; + + /* initialization */ + DZLIST_INIT(head); + int res = NOT_I(DZLIST_IS_EMPTY(head),!=,0); + + /* add element at beginning of list */ + elA = NEW(struct elem); + elA->data = 1; + DZLIST_ADD_AFTER(head, *elA); + F()Z(1)L(); + + /* add element after an element */ + elB = NEW(struct elem); + elB->data = 2; + DZLIST_ADD_AFTER(*elA, *elB); + F()Z(1)Z(2)L(); + + /* add element at the end of the list */ + elB = NEW(struct elem); + (DZLIST_ADD_BEFORE(head, *elB))->data = 3; + F()Z(1)Z(2)Z(3)L(); + + /* move an element to another position or another list */ + DZLIST_MOVE_AFTER(head, *elB); + F()Z(3)Z(1)Z(2)L(); + + DZLIST_MOVE_BEFORE(head, *elB); + F()Z(1)Z(2)Z(3)L(); + + /* works even if the position is the same */ + DZLIST_MOVE_BEFORE(head, *elB); + F()Z(1)Z(2)Z(3)L(); + + res |= NOT_I(DZLIST_FIRST(head)->data,==,1); + res |= NOT_I(DZLIST_LAST(head)->data,==,3); + + DZLIST_LOOP(head, el) { + P("%d", el->data); + } + P("."); + + /* remove elements */ + DZLIST_SAFE_RLOOP(head, el, el_safe) { + if (el->data == 1) + { + DZLIST_REMOVE(*el); + FREE(el); + } + } + F()Z(2)Z(3)L(); + + /* delete list */ + DZLIST_SAFE_LOOP(head, el, el_safe) { + DZLIST_REMOVE(*el); + FREE(el); + } + F()L(); + + return R_I(res); +} + +int test_plist() { + IN; + + struct elem; + struct list { + struct elem *me; + struct list *last, *next; + } head, *inA, *inB, *in; + struct elem { + int data; + struct list *list_data; + } *elA, *elB, *el, *el_safe; + + /* initialization */ + DLIST_INIT(head); + int res = NOT_I(DLIST_IS_EMPTY(head),!=,0); + + /* add element at beginning of list */ + elA = NEW(struct elem); + elA->data = 1; + inA = NEW(struct list); + DLIST_PADD_AFTER(head, elA, inA, list_data); + F()N(1)L(); + + /* add element after an element */ + elB = NEW(struct elem); + elB->data = 2; + inB = NEW(struct list); + DLIST_PADD_AFTER(*inA, elB, inB, list_data); + F()N(1)N(2)L(); + + /* add element at the end of the list */ + elB = NEW(struct elem); + inB = NEW(struct list); + (DLIST_PADD_BEFORE(head, elB, inB, list_data))->data = 3; + F()N(1)N(2)N(3)L(); + + /* move an element to another position or another list */ + DLIST_MOVE_AFTER(head, *inB); + F()N(3)N(1)N(2)L(); + + DLIST_MOVE_BEFORE(head, *inB); + F()N(1)N(2)N(3)L(); + + /* works even if the position is the same */ + DLIST_MOVE_BEFORE(head, *inB); + F()N(1)N(2)N(3)L(); + + res |= NOT_I(DLIST_FIRST(head)->data,==,1); + res |= NOT_I(DLIST_LAST(head)->data,==,3); + + DLIST_LOOP(head, in) { + P("%d", in->me->data); + } + P("."); + DLIST_PLOOP(head, el, list_data) { + P("%d", el->data); + } + P("."); + + /* remove elements */ + DLIST_SAFE_PLOOP(head, el, el_safe, list_data) { + if (el->data == 2) + { + DLIST_REMOVE(*el->list_data); + FREE(el->list_data); + FREE(el); + } + } + F()N(1)N(3)L(); + + /* delete list */ + DLIST_SAFE_PLOOP(head, el, el_safe, list_data) { + DLIST_REMOVE(*el->list_data); + FREE(el->list_data); + FREE(el); + } + F()L(); + + return R_I(res); +} + +int test_mlist() { + IN; + + struct elem { + int data; + struct list { + struct list *last, *next; + struct elem *me; + } list_data; + } *elA, *elB, *el, *el_safe; + struct list head, *in; + + /* initialization */ + DLIST_INIT(head); + int res = NOT_I(DLIST_IS_EMPTY(head),!=,0); + + /* add element at beginning of list */ + elA = NEW(struct elem); + elA->data = 1; + DLIST_MADD_AFTER(head, elA, list_data); + F()N(1)L(); + + /* add element after an element */ + elB = NEW(struct elem); + elB->data = 2; + DLIST_MADD_AFTER(elA->list_data, elB, list_data); + F()N(1)N(2)L(); + + /* add element at the end of the list */ + elB = NEW(struct elem); + (DLIST_MADD_BEFORE(head, elB, list_data))->data = 3; + F()N(1)N(2)N(3)L(); + + /* move an element to another position or another list */ + DLIST_MOVE_AFTER(head, elB->list_data); + F()N(3)N(1)N(2)L(); + + DLIST_MOVE_BEFORE(head, elB->list_data); + F()N(1)N(2)N(3)L(); + + /* works even if the position is the same */ + DLIST_MOVE_BEFORE(head, elB->list_data); + F()N(1)N(2)N(3)L(); + + res |= NOT_I(DLIST_FIRST(head)->data,==,1); + res |= NOT_I(DLIST_LAST(head)->data,==,3); + + DLIST_LOOP(head, in) { + P("%d", in->me->data); + } + P("."); + DLIST_MLOOP(head, el, list_data) { + P("%d", el->data); + } + P("."); + + /* remove elements */ + DLIST_SAFE_MLOOP(head, el, el_safe, list_data) { + if (el->data != 2) + { + DLIST_REMOVE(el->list_data); + FREE(el); + } + } + F()N(2)L(); + + /* delete list */ + DLIST_SAFE_MLOOP(head, el, el_safe, list_data) { + DLIST_REMOVE(el->list_data); + FREE(el); + } + F()L(); + + return R_I(res); +} + +int test_math() +{ + IN; + int res = 0; + res |= NOT_I(ROUND_UP_TO2POW(0, 4096),==,0); + res |= NOT_I(ROUND_UP_TO2POW(1, 4096),==,4096); + res |= NOT_I(ROUND_UP_TO2POW(4095, 4096),==,4096); + res |= NOT_I(ROUND_UP_TO2POW(4096, 4096),==,4096); + res |= NOT_I(ROUND_UP_TO2POW(4097, 4096),==,8192); + res |= NOT_I(ROUND_DOWN_TO2POW(0, 4096),==,0); + res |= NOT_I(ROUND_DOWN_TO2POW(1, 4096),==,0); + res |= NOT_I(ROUND_DOWN_TO2POW(4095, 4096),==,0); + res |= NOT_I(ROUND_DOWN_TO2POW(4096, 4096),==,4096); + res |= NOT_I(ROUND_DOWN_TO2POW(4097, 4096),==,4096); + return R_I(res); +} + +DEFINE_TESTS(TESTS) + +int main(int argc, char **argv) +{ + return TestLib_Run(argc, argv, nullfn, nullfn, NULL); +} + @@ -0,0 +1,54 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + +static void printf_log(const char *fmt, ...) +{ + va_list lst; + va_start(lst, fmt); + vprintf(fmt, lst); + va_end(lst); +} + +/* Override this for non-printf reporting */ +extern void (*malloc_log)(const char *fmt, ...); +static void ctor(void) __attribute__((constructor)); +static void ctor(void) +{ + malloc_log = printf_log; +} + +int main(void) +{ + char *ptr[6]; + char *uaf; + char *cf, *cb; + + ptr[0] = malloc(10); + ptr[1] = calloc(1,20); + ptr[2] = malloc(30); + ptr[3] = malloc(40); + ptr[4] = malloc(50); + ptr[5] = malloc(60); + + free(ptr[1]); + free(ptr[1]); + free(ptr[2]); + ptr[2] = realloc(ptr[2], 300); +// free(ptr[2]); +// free(ptr[2]); + + uaf = ptr[3]; + free(uaf); + uaf[5] = 'a'; + + cf = ptr[4]; + cf[-1] = 'a'; + + cb = ptr[5]; + cb[60] = 'a'; + + sleep(10); + + return 0; +} |