blob: e4a70ae50a744259cde531da112924a253b697fb [file] [log] [blame]
/*
* 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/GraphicBuffer.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;
mANativeWindow = NULL;
mFrameWidth = 0;
mFrameHeight = 0;
mPreviewWidth = 0;
mPreviewHeight = 0;
mSuspend = false;
mFailedDQs = 0;
mPaused = false;
mXOff = -1;
mYOff = -1;
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);
delete mFrameProvider;
mFrameProvider = NULL;
}
///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;
}
if ( window == mANativeWindow ) {
return ALREADY_EXISTS;
}
///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;
}
//Release any previous frame providers
if ( NULL != mFrameProvider ) {
delete mFrameProvider;
}
/** 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(bool cancel_buffer)
{
status_t ret = NO_ERROR;
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
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);
mFrameProvider->removeFramePointers();
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 = -1;
mYOff = -1;
///Reset the frame width and height values
mFrameWidth =0;
mFrameHeight = 0;
mPreviewWidth = 0;
mPreviewHeight = 0;
if(cancel_buffer)
{
// Return the buffers to ANativeWindow here, the mFramesWithCameraAdapterMap is also cleared inside
returnBuffersToWindow();
}
else
{
mANativeWindow = 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(false);
}
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;
mBufferHandleMap = new buffer_handle_t*[lnumBufs];
mGrallocHandleMap = new IMG_native_handle_t*[lnumBufs];
int undequeued = 0;
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
Rect bounds;
if ( NULL == mANativeWindow ) {
return NULL;
}
// Set gralloc usage bits for window.
err = mANativeWindow->set_usage(mANativeWindow, CAMHAL_GRALLOC_USAGE);
if (err != 0) {
ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
return NULL;
}
CAMHAL_LOGDB("Number of buffers set to ANativeWindow %d", numBufs);
///Set the number of buffers needed for camera preview
err = mANativeWindow->set_buffer_count(mANativeWindow, numBufs);
if (err != 0) {
ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
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_TI_NV12); // Gralloc only supports NV12 alloc!
if (err != 0) {
ALOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
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 ( mBufferHandleMap == NULL )
{
CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers");
LOG_FUNCTION_NAME_EXIT;
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);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
goto fail;
}
handle = *hndl2hndl;
mBufferHandleMap[i] = (buffer_handle_t*) hndl2hndl;
mGrallocHandleMap[i] = handle;
mFramesWithCameraAdapterMap.add((int) mGrallocHandleMap[i], i);
bytes = getBufSize(format, width, height);
}
// lock the initial queueable buffers
bounds.left = 0;
bounds.top = 0;
bounds.right = width;
bounds.bottom = height;
for( i = 0; i < mBufferCount-undequeued; i++ )
{
void *y_uv[2];
mANativeWindow->lock_buffer(mANativeWindow, mBufferHandleMap[i]);
mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv);
mFrameProvider->addFramePointers(mGrallocHandleMap[i] , y_uv);
}
// return the rest of the buffers back to ANativeWindow
for(i = (mBufferCount-undequeued); i >= 0 && i < mBufferCount; i++)
{
err = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]);
if (err != 0) {
CAMHAL_LOGEB("cancel_buffer failed: %s (%d)", strerror(-err), -err);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
goto fail;
}
mFramesWithCameraAdapterMap.removeItem((int) mGrallocHandleMap[i]);
//LOCK UNLOCK TO GET YUV POINTERS
void *y_uv[2];
mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv);
mFrameProvider->addFramePointers(mGrallocHandleMap[i] , y_uv);
mapper.unlock((buffer_handle_t) mGrallocHandleMap[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);
break;
}
mFramesWithCameraAdapterMap.removeItem((int) mGrallocHandleMap[start]);
}
freeBuffer(mGrallocHandleMap);
CAMHAL_LOGEA("Error occurred, performing cleanup");
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;
}
ret = mANativeWindow->get_min_undequeued_buffer_count(mANativeWindow, &undequeued);
if ( NO_ERROR != ret ) {
CAMHAL_LOGEB("get_min_undequeued_buffer_count failed: %s (%d)", strerror(-ret), -ret);
if ( ENODEV == ret ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
return -ret;
}
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;
}
status_t ANativeWindowDisplayAdapter::returnBuffersToWindow()
{
status_t ret = NO_ERROR;
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
//Give the buffers back to display here - sort of free it
if (mANativeWindow)
for(unsigned int i = 0; i < mFramesWithCameraAdapterMap.size(); i++) {
int value = mFramesWithCameraAdapterMap.valueAt(i);
// unlock buffer before giving it up
mapper.unlock((buffer_handle_t) mGrallocHandleMap[value]);
ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[value]);
if ( ENODEV == ret ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
return -ret;
} else if ( NO_ERROR != ret ) {
CAMHAL_LOGEB("cancel_buffer() failed: %s (%d)",
strerror(-ret),
-ret);
return -ret;
}
}
else
ALOGE("mANativeWindow is NULL");
///Clear the frames with camera adapter map
mFramesWithCameraAdapterMap.clear();
return ret;
}
int ANativeWindowDisplayAdapter::freeBuffer(void* buf)
{
LOG_FUNCTION_NAME;
int *buffers = (int *) buf;
status_t ret = NO_ERROR;
Mutex::Autolock lock(mLock);
if((int *)mGrallocHandleMap != buffers)
{
CAMHAL_LOGEA("CameraHal passed wrong set of buffers to free!!!");
if (mGrallocHandleMap != NULL)
delete []mGrallocHandleMap;
mGrallocHandleMap = NULL;
}
returnBuffersToWindow();
if ( NULL != buf )
{
delete [] buffers;
mGrallocHandleMap = NULL;
}
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;
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
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
if (!mGrallocHandleMap || !dispFrame.mBuffer) {
CAMHAL_LOGEA("NULL sent to PostFrame");
return -EINVAL;
}
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;
}
// unlock buffer before sending to display
mapper.unlock((buffer_handle_t) mGrallocHandleMap[i]);
ret = mANativeWindow->enqueue_buffer(mANativeWindow, mBufferHandleMap[i]);
if (ret != 0) {
ALOGE("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);
// unlock buffer before giving it up
mapper.unlock((buffer_handle_t) mGrallocHandleMap[i]);
// cancel buffer and dequeue another one
ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]);
if (ret != 0) {
ALOGE("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
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
Rect bounds;
void *y_uv[2];
// TODO(XXX): Do we need to keep stride information in camera hal?
if ( NULL == mANativeWindow ) {
return false;
}
err = mANativeWindow->dequeue_buffer(mANativeWindow, &buf, &stride);
if (err != 0) {
CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
return false;
}
err = mANativeWindow->lock_buffer(mANativeWindow, buf);
if (err != 0) {
CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err);
if ( ENODEV == err ) {
CAMHAL_LOGEA("Preview surface abandoned!");
mANativeWindow = NULL;
}
return false;
}
for(i = 0; i < mBufferCount; i++)
{
if (mBufferHandleMap[i] == buf)
break;
}
// lock buffer before sending to FrameProvider for filling
bounds.left = 0;
bounds.top = 0;
bounds.right = mFrameWidth;
bounds.bottom = mFrameHeight;
int lock_try_count = 0;
while (mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv) < 0){
if (++lock_try_count > LOCK_BUFFER_TRIES){
if ( NULL != mErrorNotifier.get() ){
mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN);
}
return false;
}
CAMHAL_LOGEA("Gralloc Lock FrameReturn Error: Sleeping 15ms");
usleep(15000);
}
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-----------------------------*/
};