| /* |
| * 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 "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; |
| } |