1001 lines
28 KiB
C++
1001 lines
28 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.
|
|
*/
|
|
|
|
#ifdef OMAP_ENHANCEMENT_CPCAM
|
|
|
|
#include "BufferSourceAdapter.h"
|
|
#include <ui/GraphicBuffer.h>
|
|
#include <ui/GraphicBufferMapper.h>
|
|
#include <hal_public.h>
|
|
|
|
namespace Ti {
|
|
namespace Camera {
|
|
|
|
static int getANWFormat(const char* parameters_format)
|
|
{
|
|
int format = HAL_PIXEL_FORMAT_TI_NV12;
|
|
|
|
if (parameters_format != NULL) {
|
|
if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV422I) == 0) {
|
|
CAMHAL_LOGDA("CbYCrY format selected");
|
|
format = HAL_PIXEL_FORMAT_TI_UYVY;
|
|
} else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
|
|
CAMHAL_LOGDA("YUV420SP format selected");
|
|
format = HAL_PIXEL_FORMAT_TI_NV12;
|
|
} else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_RGB565) == 0) {
|
|
CAMHAL_LOGDA("RGB565 format selected");
|
|
// TODO(XXX): not defined yet
|
|
format = -1;
|
|
} else if (strcmp(parameters_format, android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB) == 0) {
|
|
format = HAL_PIXEL_FORMAT_TI_Y16;
|
|
} else {
|
|
CAMHAL_LOGDA("Invalid format, NV12 format selected as default");
|
|
format = HAL_PIXEL_FORMAT_TI_NV12;
|
|
}
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
static int getUsageFromANW(int format)
|
|
{
|
|
int usage = GRALLOC_USAGE_SW_READ_RARELY |
|
|
GRALLOC_USAGE_SW_WRITE_NEVER;
|
|
|
|
switch (format) {
|
|
case HAL_PIXEL_FORMAT_TI_NV12:
|
|
case HAL_PIXEL_FORMAT_TI_Y16:
|
|
// This usage flag indicates to gralloc we want the
|
|
// buffers to come from system heap
|
|
usage |= GRALLOC_USAGE_PRIVATE_0;
|
|
break;
|
|
default:
|
|
// No special flags needed
|
|
break;
|
|
}
|
|
return usage;
|
|
}
|
|
|
|
static const char* getFormatFromANW(int format)
|
|
{
|
|
switch (format) {
|
|
case HAL_PIXEL_FORMAT_TI_NV12:
|
|
// Assuming NV12 1D is RAW or Image frame
|
|
return android::CameraParameters::PIXEL_FORMAT_YUV420SP;
|
|
case HAL_PIXEL_FORMAT_TI_Y16:
|
|
return android::CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
|
|
case HAL_PIXEL_FORMAT_TI_UYVY:
|
|
return android::CameraParameters::PIXEL_FORMAT_YUV422I;
|
|
default:
|
|
break;
|
|
}
|
|
return android::CameraParameters::PIXEL_FORMAT_YUV420SP;
|
|
}
|
|
|
|
static CameraFrame::FrameType formatToOutputFrameType(const char* format) {
|
|
switch (getANWFormat(format)) {
|
|
case HAL_PIXEL_FORMAT_TI_NV12:
|
|
case HAL_PIXEL_FORMAT_TI_Y16:
|
|
case HAL_PIXEL_FORMAT_TI_UYVY:
|
|
// Assuming NV12 1D is RAW or Image frame
|
|
return CameraFrame::RAW_FRAME;
|
|
default:
|
|
break;
|
|
}
|
|
return CameraFrame::RAW_FRAME;
|
|
}
|
|
|
|
static int getHeightFromFormat(const char* format, int stride, int size) {
|
|
CAMHAL_ASSERT((NULL != format) && (0 <= stride) && (0 <= size));
|
|
switch (getANWFormat(format)) {
|
|
case HAL_PIXEL_FORMAT_TI_NV12:
|
|
return (size / (3 * stride)) * 2;
|
|
case HAL_PIXEL_FORMAT_TI_Y16:
|
|
case HAL_PIXEL_FORMAT_TI_UYVY:
|
|
return (size / stride) / 2;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------BufferSourceAdapter Class STARTS here-----------------------------*/
|
|
|
|
|
|
///Constant definitions
|
|
// TODO(XXX): Temporarily increase number of buffers we can allocate from ANW
|
|
// until faux-NPA mode is implemented
|
|
const int BufferSourceAdapter::NO_BUFFERS_IMAGE_CAPTURE_SYSTEM_HEAP = 15;
|
|
|
|
/**
|
|
* Display Adapter class STARTS here..
|
|
*/
|
|
BufferSourceAdapter::BufferSourceAdapter() : mBufferCount(0)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
mPixelFormat = NULL;
|
|
mBuffers = NULL;
|
|
mFrameProvider = NULL;
|
|
mBufferSource = NULL;
|
|
|
|
mFrameWidth = 0;
|
|
mFrameHeight = 0;
|
|
mPreviewWidth = 0;
|
|
mPreviewHeight = 0;
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
}
|
|
|
|
BufferSourceAdapter::~BufferSourceAdapter()
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
freeBufferList(mBuffers);
|
|
|
|
android::AutoMutex lock(mLock);
|
|
|
|
destroy();
|
|
|
|
if (mFrameProvider) {
|
|
// Unregister with the frame provider
|
|
mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES);
|
|
delete mFrameProvider;
|
|
mFrameProvider = NULL;
|
|
}
|
|
|
|
if (mQueueFrame.get()) {
|
|
mQueueFrame->requestExit();
|
|
mQueueFrame.clear();
|
|
}
|
|
|
|
if (mReturnFrame.get()) {
|
|
mReturnFrame->requestExit();
|
|
mReturnFrame.clear();
|
|
}
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
}
|
|
|
|
status_t BufferSourceAdapter::initialize()
|
|
{
|
|
status_t ret = NO_ERROR;
|
|
|
|
LOG_FUNCTION_NAME;
|
|
|
|
mReturnFrame.clear();
|
|
mReturnFrame = new ReturnFrame(this);
|
|
mReturnFrame->run();
|
|
|
|
mQueueFrame.clear();
|
|
mQueueFrame = new QueueFrame(this);
|
|
mQueueFrame->run();
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int BufferSourceAdapter::setPreviewWindow(preview_stream_ops_t *source)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
if (!source) {
|
|
CAMHAL_LOGEA("NULL window object passed to DisplayAdapter");
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
if (mBufferSource) {
|
|
char id1[OP_STR_SIZE], id2[OP_STR_SIZE];
|
|
status_t ret;
|
|
|
|
ret = extendedOps()->get_id(mBufferSource, id1, sizeof(id1));
|
|
if (ret != 0) {
|
|
CAMHAL_LOGE("Surface::getId returned error %d", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = extendedOps()->get_id(source, id2, sizeof(id2));
|
|
if (ret != 0) {
|
|
CAMHAL_LOGE("Surface::getId returned error %d", ret);
|
|
return ret;
|
|
}
|
|
if ((0 >= strlen(id1)) || (0 >= strlen(id2))) {
|
|
CAMHAL_LOGE("Cannot set ST without name: id1:\"%s\" id2:\"%s\"",
|
|
id1, id2);
|
|
return NOT_ENOUGH_DATA;
|
|
}
|
|
if (0 == strcmp(id1, id2)) {
|
|
return ALREADY_EXISTS;
|
|
}
|
|
|
|
// client has to unset mBufferSource before being able to set a new one
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// Move to new source obj
|
|
mBufferSource = source;
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
bool BufferSourceAdapter::match(const char * str) {
|
|
char id1[OP_STR_SIZE];
|
|
status_t ret;
|
|
|
|
ret = extendedOps()->get_id(mBufferSource, id1, sizeof(id1));
|
|
|
|
if (ret != 0) {
|
|
CAMHAL_LOGE("Surface::getId returned error %d", ret);
|
|
}
|
|
|
|
return strcmp(id1, str) == 0;
|
|
}
|
|
|
|
int BufferSourceAdapter::setFrameProvider(FrameNotifier *frameProvider)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
if ( !frameProvider ) {
|
|
CAMHAL_LOGEA("NULL passed for frame provider");
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
if ( NULL != mFrameProvider ) {
|
|
delete mFrameProvider;
|
|
}
|
|
|
|
mFrameProvider = new FrameProvider(frameProvider, this, frameCallback);
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int BufferSourceAdapter::setErrorHandler(ErrorNotifier *errorNotifier)
|
|
{
|
|
status_t ret = NO_ERROR;
|
|
|
|
LOG_FUNCTION_NAME;
|
|
|
|
if ( NULL == errorNotifier ) {
|
|
CAMHAL_LOGEA("Invalid Error Notifier reference");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mErrorNotifier = errorNotifier;
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int BufferSourceAdapter::enableDisplay(int width, int height,
|
|
struct timeval *refTime)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
CameraFrame::FrameType frameType;
|
|
|
|
if (mFrameProvider == NULL) {
|
|
// no-op frame provider not set yet
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (mBufferSourceDirection == BUFFER_SOURCE_TAP_IN) {
|
|
// only supporting one type of input frame
|
|
frameType = CameraFrame::REPROCESS_INPUT_FRAME;
|
|
} else {
|
|
frameType = formatToOutputFrameType(mPixelFormat);
|
|
}
|
|
|
|
mFrameProvider->enableFrameNotification(frameType);
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int BufferSourceAdapter::disableDisplay(bool cancel_buffer)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
if (mFrameProvider) mFrameProvider->disableFrameNotification(CameraFrame::ALL_FRAMES);
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t BufferSourceAdapter::pauseDisplay(bool pause)
|
|
{
|
|
status_t ret = NO_ERROR;
|
|
|
|
LOG_FUNCTION_NAME;
|
|
|
|
// no-op for BufferSourceAdapter
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void BufferSourceAdapter::destroy()
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
mBufferCount = 0;
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
}
|
|
|
|
CameraBuffer* BufferSourceAdapter::allocateBufferList(int width, int dummyHeight, const char* format,
|
|
int &bytes, int numBufs)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
status_t err;
|
|
int i = -1;
|
|
const int lnumBufs = numBufs;
|
|
int undequeued = 0;
|
|
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
|
|
|
|
mBuffers = new CameraBuffer [lnumBufs];
|
|
memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs);
|
|
|
|
if ( NULL == mBufferSource ) {
|
|
return NULL;
|
|
}
|
|
|
|
int pixFormat = getANWFormat(format);
|
|
int usage = getUsageFromANW(pixFormat);
|
|
mPixelFormat = CameraHal::getPixelFormatConstant(format);
|
|
|
|
// Set gralloc usage bits for window.
|
|
err = mBufferSource->set_usage(mBufferSource, usage);
|
|
if (err != 0) {
|
|
CAMHAL_LOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
|
|
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CAMHAL_LOGDB("Number of buffers set to BufferSourceAdapter %d", numBufs);
|
|
// Set the number of buffers needed for this buffer source
|
|
err = mBufferSource->set_buffer_count(mBufferSource, numBufs);
|
|
if (err != 0) {
|
|
CAMHAL_LOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), -err);
|
|
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CAMHAL_LOGDB("Configuring %d buffers for ANativeWindow", numBufs);
|
|
mBufferCount = numBufs;
|
|
|
|
// re-calculate height depending on stride and size
|
|
int height = getHeightFromFormat(format, width, bytes);
|
|
|
|
// Set window geometry
|
|
err = mBufferSource->set_buffers_geometry(mBufferSource,
|
|
width, height,
|
|
pixFormat);
|
|
|
|
if (err != 0) {
|
|
CAMHAL_LOGE("native_window_set_buffers_geometry failed: %s (%d)", strerror(-err), -err);
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
if ( mBuffers == NULL ) {
|
|
CAMHAL_LOGEA("Couldn't create array for ANativeWindow buffers");
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
return NULL;
|
|
}
|
|
|
|
mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeued);
|
|
|
|
for (i = 0; i < mBufferCount; i++ ) {
|
|
buffer_handle_t *handle;
|
|
int stride; // dummy variable to get stride
|
|
// TODO(XXX): Do we need to keep stride information in camera hal?
|
|
|
|
err = mBufferSource->dequeue_buffer(mBufferSource, &handle, &stride);
|
|
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
goto fail;
|
|
}
|
|
|
|
CAMHAL_LOGDB("got handle %p", handle);
|
|
mBuffers[i].opaque = (void *)handle;
|
|
mBuffers[i].type = CAMERA_BUFFER_ANW;
|
|
mBuffers[i].format = mPixelFormat;
|
|
mFramesWithCameraAdapterMap.add(handle, i);
|
|
|
|
bytes = CameraHal::calculateBufferSize(format, width, height);
|
|
}
|
|
|
|
for( i = 0; i < mBufferCount-undequeued; i++ ) {
|
|
void *y_uv[2];
|
|
android::Rect bounds(width, height);
|
|
|
|
buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque;
|
|
mBufferSource->lock_buffer(mBufferSource, handle);
|
|
mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
|
|
mBuffers[i].mapped = y_uv[0];
|
|
}
|
|
|
|
// return the rest of the buffers back to ANativeWindow
|
|
for(i = (mBufferCount-undequeued); i >= 0 && i < mBufferCount; i++) {
|
|
buffer_handle_t *handle = (buffer_handle_t *) mBuffers[i].opaque;
|
|
void *y_uv[2];
|
|
android::Rect bounds(width, height);
|
|
|
|
mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
|
|
mBuffers[i].mapped = y_uv[0];
|
|
mapper.unlock(*handle);
|
|
|
|
err = mBufferSource->cancel_buffer(mBufferSource, handle);
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("cancel_buffer failed: %s (%d)", strerror(-err), -err);
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
goto fail;
|
|
}
|
|
mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[i].opaque);
|
|
}
|
|
|
|
mFrameWidth = width;
|
|
mFrameHeight = height;
|
|
mBufferSourceDirection = BUFFER_SOURCE_TAP_OUT;
|
|
|
|
return mBuffers;
|
|
|
|
fail:
|
|
// need to cancel buffers if any were dequeued
|
|
for (int start = 0; start < i && i > 0; start++) {
|
|
int err = mBufferSource->cancel_buffer(mBufferSource,
|
|
(buffer_handle_t *) mBuffers[start].opaque);
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("cancelBuffer failed w/ error 0x%08x", err);
|
|
break;
|
|
}
|
|
mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) mBuffers[start].opaque);
|
|
}
|
|
|
|
freeBufferList(mBuffers);
|
|
|
|
CAMHAL_LOGEA("Error occurred, performing cleanup");
|
|
|
|
if (NULL != mErrorNotifier.get()) {
|
|
mErrorNotifier->errorNotify(-ENOMEM);
|
|
}
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
return NULL;
|
|
|
|
}
|
|
|
|
CameraBuffer *BufferSourceAdapter::getBuffers(bool reset) {
|
|
int undequeued = 0;
|
|
status_t err;
|
|
android::Mutex::Autolock lock(mLock);
|
|
|
|
if (!mBufferSource || !mBuffers) {
|
|
CAMHAL_LOGE("Adapter is not set up properly: "
|
|
"mBufferSource:%p mBuffers:%p",
|
|
mBufferSource, mBuffers);
|
|
goto fail;
|
|
}
|
|
|
|
// CameraHal is indicating to us that the state of the mBuffer
|
|
// might have changed. We might need to check the state of the
|
|
// buffer list and pass a new one depending on the state of our
|
|
// surface
|
|
if (reset) {
|
|
const int lnumBufs = mBufferCount;
|
|
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
|
|
android::Rect bounds(mFrameWidth, mFrameHeight);
|
|
void *y_uv[2];
|
|
CameraBuffer * newBuffers = NULL;
|
|
unsigned int index = 0;
|
|
android::KeyedVector<void*, int> missingIndices;
|
|
|
|
newBuffers = new CameraBuffer [lnumBufs];
|
|
memset (newBuffers, 0, sizeof(CameraBuffer) * lnumBufs);
|
|
|
|
// Use this vector to figure out missing indices
|
|
for (int i = 0; i < mBufferCount; i++) {
|
|
missingIndices.add(mBuffers[i].opaque, i);
|
|
}
|
|
|
|
// assign buffers that we have already dequeued
|
|
for (index = 0; index < mFramesWithCameraAdapterMap.size(); index++) {
|
|
int value = mFramesWithCameraAdapterMap.valueAt(index);
|
|
newBuffers[index].opaque = mBuffers[value].opaque;
|
|
newBuffers[index].type = mBuffers[value].type;
|
|
newBuffers[index].format = mBuffers[value].format;
|
|
newBuffers[index].mapped = mBuffers[value].mapped;
|
|
mFramesWithCameraAdapterMap.replaceValueAt(index, index);
|
|
missingIndices.removeItem(newBuffers[index].opaque);
|
|
}
|
|
|
|
mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeued);
|
|
|
|
// dequeue the rest of the buffers
|
|
for (index; index < (unsigned int)(mBufferCount-undequeued); index++) {
|
|
buffer_handle_t *handle;
|
|
int stride; // dummy variable to get stride
|
|
|
|
err = mBufferSource->dequeue_buffer(mBufferSource, &handle, &stride);
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
goto fail;
|
|
}
|
|
newBuffers[index].opaque = (void *)handle;
|
|
newBuffers[index].type = CAMERA_BUFFER_ANW;
|
|
newBuffers[index].format = mPixelFormat;
|
|
mFramesWithCameraAdapterMap.add(handle, index);
|
|
|
|
mBufferSource->lock_buffer(mBufferSource, handle);
|
|
mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
|
|
newBuffers[index].mapped = y_uv[0];
|
|
CAMHAL_LOGDB("got handle %p", handle);
|
|
|
|
missingIndices.removeItem(newBuffers[index].opaque);
|
|
}
|
|
|
|
// now we need to figure out which buffers aren't dequeued
|
|
// which are in mBuffers but not newBuffers yet
|
|
if ((mBufferCount - index) != missingIndices.size()) {
|
|
CAMHAL_LOGD("Hrmm somethings gone awry. We are missing a different number"
|
|
" of buffers than we can fill");
|
|
}
|
|
for (unsigned int i = 0; i < missingIndices.size(); i++) {
|
|
int j = missingIndices.valueAt(i);
|
|
|
|
CAMHAL_LOGD("Filling at %d", j);
|
|
newBuffers[index].opaque = mBuffers[j].opaque;
|
|
newBuffers[index].type = mBuffers[j].type;
|
|
newBuffers[index].format = mBuffers[j].format;
|
|
newBuffers[index].mapped = mBuffers[j].mapped;
|
|
}
|
|
|
|
delete [] mBuffers;
|
|
mBuffers = newBuffers;
|
|
}
|
|
|
|
return mBuffers;
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
unsigned int BufferSourceAdapter::getSize() {
|
|
android::Mutex::Autolock lock(mLock);
|
|
return CameraHal::calculateBufferSize(mPixelFormat, mFrameWidth, mFrameHeight);
|
|
}
|
|
|
|
int BufferSourceAdapter::getBufferCount() {
|
|
int count = -1;
|
|
|
|
android::Mutex::Autolock lock(mLock);
|
|
if (mBufferSource) extendedOps()->get_buffer_count(mBufferSource, &count);
|
|
return count;
|
|
}
|
|
|
|
CameraBuffer* BufferSourceAdapter::getBufferList(int *num) {
|
|
LOG_FUNCTION_NAME;
|
|
status_t err;
|
|
const int lnumBufs = 1;
|
|
int formatSource;
|
|
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
|
|
buffer_handle_t *handle;
|
|
|
|
// TODO(XXX): Only supporting one input buffer at a time right now
|
|
*num = 1;
|
|
mBuffers = new CameraBuffer [lnumBufs];
|
|
memset (mBuffers, 0, sizeof(CameraBuffer) * lnumBufs);
|
|
|
|
if ( NULL == mBufferSource ) {
|
|
return NULL;
|
|
}
|
|
|
|
err = extendedOps()->update_and_get_buffer(mBufferSource, &handle, &mBuffers[0].stride);
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("update and get buffer failed: %s (%d)", strerror(-err), -err);
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
goto fail;
|
|
}
|
|
|
|
CAMHAL_LOGD("got handle %p", handle);
|
|
mBuffers[0].opaque = (void *)handle;
|
|
mBuffers[0].type = CAMERA_BUFFER_ANW;
|
|
mFramesWithCameraAdapterMap.add(handle, 0);
|
|
|
|
err = extendedOps()->get_buffer_dimension(mBufferSource, &mBuffers[0].width, &mBuffers[0].height);
|
|
err = extendedOps()->get_buffer_format(mBufferSource, &formatSource);
|
|
|
|
int t, l, r, b, w, h;
|
|
err = extendedOps()->get_crop(mBufferSource, &l, &t, &r, &b);
|
|
err = extendedOps()->get_current_size(mBufferSource, &w, &h);
|
|
|
|
// lock buffer
|
|
{
|
|
void *y_uv[2];
|
|
android::Rect bounds(mBuffers[0].width, mBuffers[0].height);
|
|
mapper.lock(*handle, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
|
|
mBuffers[0].mapped = y_uv[0];
|
|
}
|
|
|
|
mFrameWidth = mBuffers[0].width;
|
|
mFrameHeight = mBuffers[0].height;
|
|
mPixelFormat = getFormatFromANW(formatSource);
|
|
|
|
mBuffers[0].format = mPixelFormat;
|
|
mBuffers[0].actual_size = CameraHal::calculateBufferSize(mPixelFormat, w, h);
|
|
mBuffers[0].offset = t * w + l * CameraHal::getBPP(mPixelFormat);
|
|
mBufferSourceDirection = BUFFER_SOURCE_TAP_IN;
|
|
|
|
return mBuffers;
|
|
|
|
fail:
|
|
// need to cancel buffers if any were dequeued
|
|
freeBufferList(mBuffers);
|
|
|
|
if (NULL != mErrorNotifier.get()) {
|
|
mErrorNotifier->errorNotify(-ENOMEM);
|
|
}
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t * BufferSourceAdapter::getOffsets()
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int BufferSourceAdapter::minUndequeueableBuffers(int& undequeueable) {
|
|
LOG_FUNCTION_NAME;
|
|
int ret = NO_ERROR;
|
|
|
|
if(!mBufferSource)
|
|
{
|
|
ret = INVALID_OPERATION;
|
|
goto end;
|
|
}
|
|
|
|
ret = mBufferSource->get_min_undequeued_buffer_count(mBufferSource, &undequeueable);
|
|
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!");
|
|
mBufferSource = NULL;
|
|
}
|
|
return -ret;
|
|
}
|
|
|
|
end:
|
|
return ret;
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
}
|
|
|
|
int BufferSourceAdapter::maxQueueableBuffers(unsigned int& queueable)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
int ret = NO_ERROR;
|
|
int undequeued = 0;
|
|
|
|
if(mBufferCount == 0) {
|
|
ret = INVALID_OPERATION;
|
|
goto end;
|
|
}
|
|
|
|
ret = minUndequeueableBuffers(undequeued);
|
|
if (ret != NO_ERROR) {
|
|
goto end;
|
|
}
|
|
|
|
queueable = mBufferCount - undequeued;
|
|
|
|
end:
|
|
return ret;
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
}
|
|
|
|
int BufferSourceAdapter::getFd()
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
LOG_FUNCTION_NAME_EXIT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
status_t BufferSourceAdapter::returnBuffersToWindow()
|
|
{
|
|
status_t ret = NO_ERROR;
|
|
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
|
|
|
|
//Give the buffers back to display here - sort of free it
|
|
if (mBufferSource) {
|
|
for(unsigned int i = 0; i < mFramesWithCameraAdapterMap.size(); i++) {
|
|
int value = mFramesWithCameraAdapterMap.valueAt(i);
|
|
buffer_handle_t *handle = (buffer_handle_t *) mBuffers[value].opaque;
|
|
|
|
// if buffer index is out of bounds skip
|
|
if ((value < 0) || (value >= mBufferCount)) {
|
|
CAMHAL_LOGEA("Potential out bounds access to handle...skipping");
|
|
continue;
|
|
}
|
|
|
|
// unlock buffer before giving it up
|
|
mapper.unlock(*handle);
|
|
|
|
ret = mBufferSource->cancel_buffer(mBufferSource, handle);
|
|
if ( ENODEV == ret ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
return -ret;
|
|
} else if ( NO_ERROR != ret ) {
|
|
CAMHAL_LOGEB("cancel_buffer() failed: %s (%d)",
|
|
strerror(-ret),
|
|
-ret);
|
|
return -ret;
|
|
}
|
|
}
|
|
} else {
|
|
CAMHAL_LOGE("mBufferSource is NULL");
|
|
}
|
|
|
|
///Clear the frames with camera adapter map
|
|
mFramesWithCameraAdapterMap.clear();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int BufferSourceAdapter::freeBufferList(CameraBuffer * buflist)
|
|
{
|
|
LOG_FUNCTION_NAME;
|
|
|
|
status_t ret = NO_ERROR;
|
|
|
|
if ( mBuffers != buflist ) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
android::AutoMutex lock(mLock);
|
|
|
|
if (mBufferSourceDirection == BUFFER_SOURCE_TAP_OUT) returnBuffersToWindow();
|
|
|
|
if( mBuffers != NULL)
|
|
{
|
|
delete [] mBuffers;
|
|
mBuffers = NULL;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
bool BufferSourceAdapter::supportsExternalBuffering()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void BufferSourceAdapter::addFrame(CameraFrame* frame)
|
|
{
|
|
if (mQueueFrame.get()) {
|
|
mQueueFrame->addFrame(frame);
|
|
}
|
|
}
|
|
|
|
void BufferSourceAdapter::handleFrameCallback(CameraFrame* frame)
|
|
{
|
|
status_t ret = NO_ERROR;
|
|
buffer_handle_t *handle = NULL;
|
|
int i;
|
|
uint32_t x, y;
|
|
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
|
|
|
|
android::AutoMutex lock(mLock);
|
|
|
|
if (!mBuffers || !frame->mBuffer) {
|
|
CAMHAL_LOGEA("Adapter sent BufferSourceAdapter a NULL frame?");
|
|
return;
|
|
}
|
|
|
|
for ( i = 0; i < mBufferCount; i++ ) {
|
|
if (frame->mBuffer == &mBuffers[i]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= mBufferCount) {
|
|
CAMHAL_LOGD("Can't find frame in buffer list");
|
|
if (frame->mFrameType != CameraFrame::REPROCESS_INPUT_FRAME) {
|
|
mFrameProvider->returnFrame(frame->mBuffer,
|
|
static_cast<CameraFrame::FrameType>(frame->mFrameType));
|
|
}
|
|
return;
|
|
}
|
|
|
|
handle = (buffer_handle_t *) mBuffers[i].opaque;
|
|
|
|
// Handle input buffers
|
|
// TODO(XXX): Move handling of input buffers out of here if
|
|
// it becomes more complex
|
|
if (frame->mFrameType == CameraFrame::REPROCESS_INPUT_FRAME) {
|
|
CAMHAL_LOGD("Unlock %p (buffer #%d)", handle, i);
|
|
mapper.unlock(*handle);
|
|
return;
|
|
}
|
|
|
|
CameraHal::getXYFromOffset(&x, &y, frame->mOffset, frame->mAlignment, mPixelFormat);
|
|
CAMHAL_LOGVB("offset = %u left = %d top = %d right = %d bottom = %d",
|
|
frame->mOffset, x, y, x + frame->mWidth, y + frame->mHeight);
|
|
ret = mBufferSource->set_crop(mBufferSource, x, y, x + frame->mWidth, y + frame->mHeight);
|
|
if (NO_ERROR != ret) {
|
|
CAMHAL_LOGE("mBufferSource->set_crop returned error %d", ret);
|
|
goto fail;
|
|
}
|
|
|
|
if ( NULL != frame->mMetaData.get() ) {
|
|
camera_memory_t *extMeta = frame->mMetaData->getExtendedMetadata();
|
|
if ( NULL != extMeta ) {
|
|
camera_metadata_t *metaData = static_cast<camera_metadata_t *> (extMeta->data);
|
|
metaData->timestamp = frame->mTimestamp;
|
|
ret = extendedOps()->set_metadata(mBufferSource, extMeta);
|
|
if (ret != 0) {
|
|
CAMHAL_LOGE("Surface::set_metadata returned error %d", ret);
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
// unlock buffer before enqueueing
|
|
mapper.unlock(*handle);
|
|
|
|
ret = mBufferSource->enqueue_buffer(mBufferSource, handle);
|
|
if (ret != 0) {
|
|
CAMHAL_LOGE("Surface::queueBuffer returned error %d", ret);
|
|
goto fail;
|
|
}
|
|
|
|
mFramesWithCameraAdapterMap.removeItem((buffer_handle_t *) frame->mBuffer->opaque);
|
|
|
|
return;
|
|
|
|
fail:
|
|
mFramesWithCameraAdapterMap.clear();
|
|
mBufferSource = NULL;
|
|
mReturnFrame->requestExit();
|
|
mQueueFrame->requestExit();
|
|
}
|
|
|
|
|
|
bool BufferSourceAdapter::handleFrameReturn()
|
|
{
|
|
status_t err;
|
|
buffer_handle_t *buf;
|
|
int i = 0;
|
|
int stride; // dummy variable to get stride
|
|
CameraFrame::FrameType type;
|
|
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
|
|
void *y_uv[2];
|
|
android::Rect bounds(mFrameWidth, mFrameHeight);
|
|
|
|
android::AutoMutex lock(mLock);
|
|
|
|
if ( (NULL == mBufferSource) || (NULL == mBuffers) ) {
|
|
return false;
|
|
}
|
|
|
|
err = mBufferSource->dequeue_buffer(mBufferSource, &buf, &stride);
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
|
|
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
err = mBufferSource->lock_buffer(mBufferSource, buf);
|
|
if (err != 0) {
|
|
CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err);
|
|
|
|
if ( ENODEV == err ) {
|
|
CAMHAL_LOGEA("Preview surface abandoned!");
|
|
mBufferSource = NULL;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
mapper.lock(*buf, CAMHAL_GRALLOC_USAGE, bounds, y_uv);
|
|
|
|
for(i = 0; i < mBufferCount; i++) {
|
|
if (mBuffers[i].opaque == buf)
|
|
break;
|
|
}
|
|
|
|
if (i >= mBufferCount) {
|
|
CAMHAL_LOGEB("Failed to find handle %p", buf);
|
|
}
|
|
|
|
mFramesWithCameraAdapterMap.add((buffer_handle_t *) mBuffers[i].opaque, i);
|
|
|
|
CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount - 1);
|
|
|
|
mFrameProvider->returnFrame(&mBuffers[i], formatToOutputFrameType(mPixelFormat));
|
|
return true;
|
|
}
|
|
|
|
void BufferSourceAdapter::frameCallback(CameraFrame* caFrame)
|
|
{
|
|
if ((NULL != caFrame) && (NULL != caFrame->mCookie)) {
|
|
BufferSourceAdapter *da = (BufferSourceAdapter*) caFrame->mCookie;
|
|
da->addFrame(caFrame);
|
|
} else {
|
|
CAMHAL_LOGEB("Invalid Cookie in Camera Frame = %p, Cookie = %p",
|
|
caFrame, caFrame ? caFrame->mCookie : NULL);
|
|
}
|
|
}
|
|
|
|
/*--------------------BufferSourceAdapter Class ENDS here-----------------------------*/
|
|
|
|
} // namespace Camera
|
|
} // namespace Ti
|
|
|
|
#endif
|