1269 lines
34 KiB
C++
1269 lines
34 KiB
C++
/*
|
|
* 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-----------------------------*/
|
|
|
|
};
|
|
|