/* * Copyright (C) 2010 The Android Open Source Project * * 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 "SecHardwareRenderer" #define LOG_NDEBUG 0 #include #include "SecHardwareRenderer.h" #include #include #include #include #include "v4l2_utils.h" #include "utils/Timers.h" #define CACHEABLE_BUFFERS 0x1 #define USE_ZERO_COPY //#define SEC_DEBUG namespace android { //////////////////////////////////////////////////////////////////////////////// SecHardwareRenderer::SecHardwareRenderer( const sp &surface, size_t displayWidth, size_t displayHeight, size_t decodedWidth, size_t decodedHeight, OMX_COLOR_FORMATTYPE colorFormat, int32_t rotationDegrees, bool fromHardwareDecoder) : mISurface(surface), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight), mDecodedWidth(decodedWidth), mDecodedHeight(decodedHeight), mColorFormat(colorFormat), mInitCheck(NO_INIT), mFrameSize(mDecodedWidth * mDecodedHeight * 2), mIsFirstFrame(true), mCustomFormat(false), mIndex(0) { CHECK(mISurface.get() != NULL); CHECK(mDecodedWidth > 0); CHECK(mDecodedHeight > 0); if (colorFormat != OMX_COLOR_FormatCbYCrY && colorFormat != OMX_COLOR_FormatYUV420Planar && colorFormat != OMX_COLOR_FormatYUV420SemiPlanar) { LOGE("Invalid colorFormat (0x%x)", colorFormat); return; } uint32_t orientation; switch (rotationDegrees) { case 0: orientation = ISurface::BufferHeap::ROT_0; break; case 90: orientation = ISurface::BufferHeap::ROT_90; break; case 180: orientation = ISurface::BufferHeap::ROT_180; break; case 270: orientation = ISurface::BufferHeap::ROT_270; break; default: orientation = ISurface::BufferHeap::ROT_0; break; } sp ref; #if defined (USE_ZERO_COPY) if (fromHardwareDecoder) { ref = mISurface->createOverlay( mDecodedWidth, mDecodedHeight, HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP, orientation); mCustomFormat = true; } #else else { ref = mISurface->createOverlay( mDecodedWidth, mDecodedHeight, HAL_PIXEL_FORMAT_YCbCr_420_P, orientation); } #endif if (ref.get() == NULL) { LOGE("Unable to create the overlay!"); return; } mOverlay = new Overlay(ref); mOverlay->setParameter(CACHEABLE_BUFFERS, 0); mNumBuf = mOverlay->getBufferCount(); if (mCustomFormat) { mFrameSize = 32; mMemoryHeap = new MemoryHeapBase(mNumBuf * mFrameSize); } else { for (size_t i = 0; i < (size_t)mNumBuf; ++i) { void *addr = mOverlay->getBufferAddress((void *)i); mOverlayAddresses.push(addr); } } mInitCheck = OK; } SecHardwareRenderer::~SecHardwareRenderer() { if(mMemoryHeap != NULL) mMemoryHeap.clear(); if (mOverlay.get() != NULL) { mOverlay->destroy(); mOverlay.clear(); } } void SecHardwareRenderer::handleYUV420Planar( const void *data, size_t size) { int FrameSize; uint8_t* pPhyYAddr; uint8_t* pPhyCAddr; int AddrSize; size_t offset; CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2); offset = mIndex * mFrameSize; void *dst = (uint8_t *)mMemoryHeap->getBase() + offset; AddrSize = sizeof(void *); memcpy(&FrameSize, data, sizeof(FrameSize)); memcpy(&pPhyYAddr, data + sizeof(FrameSize), sizeof(pPhyYAddr)); memcpy(&pPhyCAddr, data + sizeof(FrameSize) + (AddrSize * 1), sizeof(pPhyCAddr)); memcpy(dst , &pPhyYAddr, sizeof(pPhyYAddr)); memcpy(dst + sizeof(pPhyYAddr) , &pPhyCAddr, sizeof(pPhyCAddr)); memcpy(dst + sizeof(pPhyYAddr) + sizeof(pPhyCAddr), &mIndex, sizeof(mIndex)); } void SecHardwareRenderer::render( const void *data, size_t size, void *platformPrivate) { if (mOverlay.get() == NULL) { return; } if (mCustomFormat) { /* zero copy solution case */ overlay_buffer_t dst = (uint8_t *)mMemoryHeap->getBase() + mIndex*mFrameSize; if (mColorFormat == OMX_COLOR_FormatYUV420Planar || mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { handleYUV420Planar(data, size); } if (mOverlay->queueBuffer(dst) == ALL_BUFFERS_FLUSHED) { mIsFirstFrame = true; if (mOverlay->queueBuffer((void *)dst) != 0) { return; } } if (++mIndex == mNumBuf) { mIndex = 0; } overlay_buffer_t overlay_buffer; if (!mIsFirstFrame) { status_t err = mOverlay->dequeueBuffer(&overlay_buffer); if (err == ALL_BUFFERS_FLUSHED) { mIsFirstFrame = true; } else { return; } } else { mIsFirstFrame = false; } } else { /* normal frame case */ if (mColorFormat == OMX_COLOR_FormatYUV420Planar) { memcpy(mOverlayAddresses[mIndex], data, size); } if (mOverlay->queueBuffer((void *)mIndex) == ALL_BUFFERS_FLUSHED) { mIsFirstFrame = true; if (mOverlay->queueBuffer((void *)mIndex) != 0) { return; } } if (++mIndex == mNumBuf) { mIndex = 0; } overlay_buffer_t overlay_buffer; if (!mIsFirstFrame) { status_t err = mOverlay->dequeueBuffer(&overlay_buffer); if (err == ALL_BUFFERS_FLUSHED) { mIsFirstFrame = true; } else { return; } } else { mIsFirstFrame = false; } } } } // namespace android