/*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
*
* 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 <inttypes.h>
#include <media/hardware/HardwareAPI.h>
#include <system/graphics.h>
#include <nativebase/nativebase.h>
#include "isv_bufmanager.h"
#ifndef TARGET_VPP_USE_GEN
#include "hal_public.h"
#include <sync/sync.h>
#endif
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "isv-omxil"
using namespace android;
#define GRALLOC_SUB_BUFFER_MAX 3
#define RANDOM_BUFFER_SIZE 200
static char random_buf[RANDOM_BUFFER_SIZE];
ISVBuffer::~ISVBuffer() {
if (mWorker != NULL) {
ALOGV("%s: mSurface %d", __func__, mSurface);
mWorker->freeSurface(&mSurface);
}
}
status_t ISVBuffer::initBufferInfo(uint32_t hackFormat)
{
if (mType == ISV_BUFFER_METADATA) {
VideoDecoderOutputMetaData *metaData =
reinterpret_cast<VideoDecoderOutputMetaData*>(mBuffer);
if (metaData->eType != kMetadataBufferTypeGrallocSource) {
ALOGE("%s: unsupported meta data format eType = %d", __func__, metaData->eType);
return UNKNOWN_ERROR;
}
if (mGrallocHandle != 0) {
if ((unsigned long)metaData->pHandle != mGrallocHandle) {
if (STATUS_OK != mWorker->freeSurface(&mSurface)) {
ALOGE("%s: free surface %d failed.", __func__, mSurface);
return UNKNOWN_ERROR;
}
} else
return OK;
}
mGrallocHandle = (unsigned long)metaData->pHandle;
} else {
if (mSurface != -1)
return OK;
mGrallocHandle = mBuffer;
}
int32_t err = 0;
#ifdef TARGET_VPP_USE_GEN
if (!mpGralloc) {
err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (hw_module_t const**)&mpGralloc);
if (0 != err)
return UNKNOWN_ERROR;
}
ufo_buffer_details_t info;
memset(&info, 0, sizeof(ufo_buffer_details_t));
err = mpGralloc->perform(mpGralloc, INTEL_UFO_GRALLOC_MODULE_PERFORM_GET_BO_INFO, mGrallocHandle, &info);
if (0 != err) {
ALOGE("%s: can't get graphic buffer info", __func__);
}
mWidth = info.width;
mHeight = info.height;
mStride = info.pitch;
mColorFormat = info.format;
#else
if (!mpGralloc) {
err = gralloc_open_img(&mpGralloc);
if (0 != err)
return UNKNOWN_ERROR;
}
IMG_native_handle_t* grallocHandle = (IMG_native_handle_t*)mGrallocHandle;
mStride = grallocHandle->aiStride[0];
mSurfaceHeight = grallocHandle->iHeight;
mColorFormat = (hackFormat != 0) ? hackFormat : grallocHandle->iFormat;
#endif
if (mWorker == NULL) {
ALOGE("%s: mWorker == NULL!!", __func__);
return UNKNOWN_ERROR;
}
if (STATUS_OK != mWorker->allocSurface(&mWidth, &mHeight, mStride, mColorFormat, mGrallocHandle, &mSurface)) {
ALOGE("%s: alloc surface failed, mGrallocHandle %lu", __func__, mGrallocHandle);
return UNKNOWN_ERROR;
}
ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG,
"%s: mWidth %d, mHeight %d, mStride %d, mColorFormat %d, "
"mGrallocHandle %p, mSurface %d",
__func__, mWidth, mHeight, mStride, mColorFormat,
reinterpret_cast<void*>(mGrallocHandle), mSurface);
return OK;
}
status_t ISVBuffer::clearIfNeed()
{
#ifndef TARGET_VPP_USE_GEN
static bool bRandomBufferInit = false;
if (!bRandomBufferInit) {
time_t my_time;
srand((unsigned)time(&my_time));
for (int32_t i = 0; i < RANDOM_BUFFER_SIZE; i++)
random_buf[i] = (char)(((double)rand()/(double)RAND_MAX) * 255.0);
bRandomBufferInit = true;
}
if ((mFlags & ISV_BUFFER_NEED_CLEAR) && mpGralloc) {
int32_t usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
void *vaddr[GRALLOC_SUB_BUFFER_MAX];
const gralloc1_rect_t r = {
.width = (int32_t)mStride,
.height = (int32_t)mSurfaceHeight
};
int err, releaseFence = -1;
err = gralloc_lock_async_img(mpGralloc, (buffer_handle_t)mGrallocHandle, usage, &r, &vaddr[0], -1);
if (0 != err) {
ALOGE("%s: get graphic buffer ptr failed", __func__);
return UNKNOWN_ERROR;
}
int32_t buffer_size = mStride * mSurfaceHeight * 3 / 2;
char* ptr = (char*)vaddr[0];
for (int32_t i = 0; i < buffer_size/RANDOM_BUFFER_SIZE; i++) {
memcpy(ptr, random_buf, sizeof(random_buf));
ptr += sizeof(random_buf);
}
gralloc_unlock_async_img(mpGralloc, (buffer_handle_t)mGrallocHandle, &releaseFence);
if (releaseFence >= 0) {
sync_wait(releaseFence, -1);
close(releaseFence);
}
ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: clear isv buffer %p finished, buffer size %d", __func__, this, buffer_size);
mFlags &= ~ISV_BUFFER_NEED_CLEAR;
}
#endif
return OK;
}
status_t ISVBufferManager::setBufferCount(int32_t size)
{
Mutex::Autolock autoLock(mBufferLock);
#if 0
if (!mBuffers.isEmpty()) {
ALOGE("%s: the buffer queue should be empty before we set its size", __func__);
return STATUS_ERROR;
}
#endif
mBuffers.setCapacity(size);
return OK;
}
status_t ISVBufferManager::freeBuffer(unsigned long handle)
{
Mutex::Autolock autoLock(mBufferLock);
for (uint32_t i = 0; i < mBuffers.size(); i++) {
ISVBuffer* isvBuffer = mBuffers.itemAt(i);
if (isvBuffer->getHandle() == handle) {
delete isvBuffer;
mBuffers.removeAt(i);
ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG, "%s: remove handle 0x%08lx, and then mBuffers.size() %d", __func__,
handle, mBuffers.size());
return OK;
}
}
ALOGW("%s: can't find buffer %lu", __func__, handle);
return UNKNOWN_ERROR;
}
status_t ISVBufferManager::useBuffer(unsigned long handle)
{
Mutex::Autolock autoLock(mBufferLock);
if (handle == 0 || mBuffers.size() >= mBuffers.capacity())
return BAD_VALUE;
for (uint32_t i = 0; i < mBuffers.size(); i++) {
ISVBuffer* isvBuffer = mBuffers.itemAt(i);
if (isvBuffer->getHandle() == handle) {
ALOGE("%s: this buffer 0x%08lx has already been registered", __func__, handle);
return UNKNOWN_ERROR;
}
}
ISVBuffer* isvBuffer = new ISVBuffer(mWorker, handle,
mMetaDataMode ? ISVBuffer::ISV_BUFFER_METADATA : ISVBuffer::ISV_BUFFER_GRALLOC,
mNeedClearBuffers ? ISVBuffer::ISV_BUFFER_NEED_CLEAR : 0);
ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG,
"%s: add handle 0x%08lx, and then mBuffers.size() %d", __func__,
handle, mBuffers.size());
mBuffers.push_back(isvBuffer);
return OK;
}
status_t ISVBufferManager::useBuffer(const sp<ANativeWindowBuffer> nativeBuffer)
{
Mutex::Autolock autoLock(mBufferLock);
if (nativeBuffer == NULL || mBuffers.size() >= mBuffers.capacity())
return BAD_VALUE;
for (uint32_t i = 0; i < mBuffers.size(); i++) {
ISVBuffer* isvBuffer = mBuffers.itemAt(i);
if (isvBuffer->getHandle() == (unsigned long)nativeBuffer->handle) {
ALOGE(
"%s: this buffer 0x%08" PRIxPTR " has already been registered",
__func__, reinterpret_cast<uintptr_t>(nativeBuffer->handle));
return UNKNOWN_ERROR;
}
}
ISVBuffer* isvBuffer = new ISVBuffer(mWorker,
(unsigned long)nativeBuffer->handle, (unsigned long)nativeBuffer->handle,
nativeBuffer->width, nativeBuffer->height,
nativeBuffer->stride, nativeBuffer->format,
mMetaDataMode ? ISVBuffer::ISV_BUFFER_METADATA : ISVBuffer::ISV_BUFFER_GRALLOC,
mNeedClearBuffers ? ISVBuffer::ISV_BUFFER_NEED_CLEAR : 0);
ALOGD_IF(ISV_BUFFER_MANAGER_DEBUG,
"%s: add handle 0x%08" PRIxPTR ", and then mBuffers.size() %d",
__func__, reinterpret_cast<uintptr_t>(nativeBuffer->handle),
mBuffers.size());
mBuffers.push_back(isvBuffer);
return OK;
}
ISVBuffer* ISVBufferManager::mapBuffer(unsigned long handle)
{
Mutex::Autolock autoLock(mBufferLock);
for (uint32_t i = 0; i < mBuffers.size(); i++) {
ISVBuffer* isvBuffer = mBuffers.itemAt(i);
if (isvBuffer->getHandle() == handle)
return isvBuffer;
}
return NULL;
}
status_t ISVBufferManager::setBuffersFlag(uint32_t flag)
{
Mutex::Autolock autoLock(mBufferLock);
if (flag & ISVBuffer::ISV_BUFFER_NEED_CLEAR) {
if (mBuffers.size() == 0)
mNeedClearBuffers = true;
else {
for (uint32_t i = 0; i < mBuffers.size(); i++) {
ISVBuffer* isvBuffer = mBuffers.itemAt(i);
isvBuffer->setFlag(ISVBuffer::ISV_BUFFER_NEED_CLEAR);
}
}
}
return OK;
}