blob: cb9e8e8da95e2a02c8ab317a42ec6d1fa0990c39 [file] [log] [blame]
/*
* 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 <utils/Log.h>
#include "SecHardwareRenderer.h"
#include <media/stagefright/MediaDebug.h>
#include <surfaceflinger/ISurface.h>
#include <ui/Overlay.h>
#include <hardware/hardware.h>
#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<ISurface> &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<OverlayRef> 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