diff options
author | Andreas Huber <andih@google.com> | 2009-07-31 11:52:50 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2009-07-31 12:48:53 -0700 |
commit | 1de13168a9d9f55464dc98748ea28ef785f1048e (patch) | |
tree | 753f84ecd1e109e4c0c2e2d8285c90b777ed9ef5 /media/libstagefright/omx | |
parent | 1b0efec3473134fb7de226f3e1fdade5b3529ad9 (diff) | |
download | frameworks_base-1de13168a9d9f55464dc98748ea28ef785f1048e.zip frameworks_base-1de13168a9d9f55464dc98748ea28ef785f1048e.tar.gz frameworks_base-1de13168a9d9f55464dc98748ea28ef785f1048e.tar.bz2 |
The IOMX interface now instantiates IOMXRenderers to hide the details of hardware accelerated blitting.
Diffstat (limited to 'media/libstagefright/omx')
-rw-r--r-- | media/libstagefright/omx/Android.mk | 18 | ||||
-rw-r--r-- | media/libstagefright/omx/OMX.cpp | 63 | ||||
-rw-r--r-- | media/libstagefright/omx/OMX.h | 7 | ||||
-rw-r--r-- | media/libstagefright/omx/OMXRenderer.h | 44 | ||||
-rw-r--r-- | media/libstagefright/omx/QComHardwareRenderer.cpp | 139 | ||||
-rw-r--r-- | media/libstagefright/omx/SoftwareRenderer.cpp | 177 | ||||
-rw-r--r-- | media/libstagefright/omx/TIHardwareRenderer.cpp | 99 |
7 files changed, 540 insertions, 7 deletions
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index 9c6d475..2e564e9 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -9,13 +9,17 @@ LOCAL_C_INCLUDES := $(PV_INCLUDES) LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY) LOCAL_SRC_FILES:= \ - OMX.cpp - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libmedia \ - libutils \ - libui \ + OMX.cpp \ + QComHardwareRenderer.cpp \ + SoftwareRenderer.cpp \ + TIHardwareRenderer.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libmedia \ + libutils \ + libui \ + libcutils \ libopencore_common LOCAL_PRELINK_MODULE:= false diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index daaa741..062afd4 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -24,9 +24,15 @@ #include <assert.h> #include "OMX.h" +#include "OMXRenderer.h" + #include "pv_omxcore.h" #include <binder/IMemory.h> +#include <media/stagefright/QComHardwareRenderer.h> +#include <media/stagefright/SoftwareRenderer.h> +#include <media/stagefright/TIHardwareRenderer.h> +#include <media/stagefright/VideoRenderer.h> #include <OMX_Component.h> @@ -619,5 +625,62 @@ void OMX::empty_buffer( } #endif +//////////////////////////////////////////////////////////////////////////////// + +sp<IOMXRenderer> OMX::createRenderer( + const sp<ISurface> &surface, + const char *componentName, + OMX_COLOR_FORMATTYPE colorFormat, + size_t encodedWidth, size_t encodedHeight, + size_t displayWidth, size_t displayHeight) { + VideoRenderer *impl = NULL; + + static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; + + if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar + && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) { + LOGW("Using QComHardwareRenderer."); + impl = + new QComHardwareRenderer( + surface, + displayWidth, displayHeight, + encodedWidth, encodedHeight); + } else if (colorFormat == OMX_COLOR_FormatCbYCrY + && !strcmp(componentName, "OMX.TI.Video.Decoder")) { + LOGW("Using TIHardwareRenderer."); + impl = + new TIHardwareRenderer( + surface, + displayWidth, displayHeight, + encodedWidth, encodedHeight); + } else { + LOGW("Using software renderer."); + impl = new SoftwareRenderer( + surface, + displayWidth, displayHeight, + encodedWidth, encodedHeight); + } + + return new OMXRenderer(impl); +} + +OMXRenderer::OMXRenderer(VideoRenderer *impl) + : mImpl(impl) { +} + +OMXRenderer::~OMXRenderer() { + delete mImpl; + mImpl = NULL; +} + +void OMXRenderer::render(IOMX::buffer_id buffer) { + OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; + + mImpl->render( + header->pBuffer + header->nOffset, + header->nFilledLen, + header->pPlatformPrivate); +} + } // namespace android diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h index ed4e5dd..20430bb 100644 --- a/media/libstagefright/omx/OMX.h +++ b/media/libstagefright/omx/OMX.h @@ -79,6 +79,13 @@ public: OMX_U32 flags, OMX_TICKS timestamp); #endif + virtual sp<IOMXRenderer> createRenderer( + const sp<ISurface> &surface, + const char *componentName, + OMX_COLOR_FORMATTYPE colorFormat, + size_t encodedWidth, size_t encodedHeight, + size_t displayWidth, size_t displayHeight); + private: static OMX_CALLBACKTYPE kCallbacks; diff --git a/media/libstagefright/omx/OMXRenderer.h b/media/libstagefright/omx/OMXRenderer.h new file mode 100644 index 0000000..4d194ce --- /dev/null +++ b/media/libstagefright/omx/OMXRenderer.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef OMX_RENDERER_H_ + +#define OMX_RENDERER_H_ + +#include <media/IOMX.h> + +namespace android { + +class VideoRenderer; + +class OMXRenderer : public BnOMXRenderer { +public: + // Assumes ownership of "impl". + OMXRenderer(VideoRenderer *impl); + virtual ~OMXRenderer(); + + virtual void render(IOMX::buffer_id buffer); + +private: + VideoRenderer *mImpl; + + OMXRenderer(const OMXRenderer &); + OMXRenderer &operator=(const OMXRenderer &); +}; + +} // namespace android + +#endif // OMX_RENDERER_H_ diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp new file mode 100644 index 0000000..5a23792 --- /dev/null +++ b/media/libstagefright/omx/QComHardwareRenderer.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009 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. + */ + +#undef NDEBUG +#include <assert.h> + +#include <binder/MemoryHeapBase.h> +#include <binder/MemoryHeapPmem.h> +#include <media/stagefright/QComHardwareRenderer.h> +#include <ui/ISurface.h> + +namespace android { + +//////////////////////////////////////////////////////////////////////////////// + +typedef struct PLATFORM_PRIVATE_ENTRY +{ + /* Entry type */ + uint32_t type; + + /* Pointer to platform specific entry */ + void *entry; + +} PLATFORM_PRIVATE_ENTRY; + +typedef struct PLATFORM_PRIVATE_LIST +{ + /* Number of entries */ + uint32_t nEntries; + + /* Pointer to array of platform specific entries * + * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */ + PLATFORM_PRIVATE_ENTRY *entryList; + +} PLATFORM_PRIVATE_LIST; + +// data structures for tunneling buffers +typedef struct PLATFORM_PRIVATE_PMEM_INFO +{ + /* pmem file descriptor */ + uint32_t pmem_fd; + uint32_t offset; + +} PLATFORM_PRIVATE_PMEM_INFO; + +#define PLATFORM_PRIVATE_PMEM 1 + +QComHardwareRenderer::QComHardwareRenderer( + const sp<ISurface> &surface, + size_t displayWidth, size_t displayHeight, + size_t decodedWidth, size_t decodedHeight) + : mISurface(surface), + mDisplayWidth(displayWidth), + mDisplayHeight(displayHeight), + mDecodedWidth(decodedWidth), + mDecodedHeight(decodedHeight), + mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) { + assert(mISurface.get() != NULL); + assert(mDecodedWidth > 0); + assert(mDecodedHeight > 0); +} + +QComHardwareRenderer::~QComHardwareRenderer() { + mISurface->unregisterBuffers(); +} + +void QComHardwareRenderer::render( + const void *data, size_t size, void *platformPrivate) { + size_t offset; + if (!getOffset(platformPrivate, &offset)) { + return; + } + + mISurface->postBuffer(offset); +} + +bool QComHardwareRenderer::getOffset(void *platformPrivate, size_t *offset) { + *offset = 0; + + PLATFORM_PRIVATE_LIST *list = (PLATFORM_PRIVATE_LIST *)platformPrivate; + for (uint32_t i = 0; i < list->nEntries; ++i) { + if (list->entryList[i].type != PLATFORM_PRIVATE_PMEM) { + continue; + } + + PLATFORM_PRIVATE_PMEM_INFO *info = + (PLATFORM_PRIVATE_PMEM_INFO *)list->entryList[i].entry; + + if (info != NULL) { + if (mMemoryHeap.get() == NULL) { + publishBuffers(info->pmem_fd); + } + + if (mMemoryHeap.get() == NULL) { + return false; + } + + *offset = info->offset; + + return true; + } + } + + return false; +} + +void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) { + sp<MemoryHeapBase> master = + reinterpret_cast<MemoryHeapBase *>(pmem_fd); + + master->setDevice("/dev/pmem"); + + mMemoryHeap = new MemoryHeapPmem(master, 0); + mMemoryHeap->slap(); + + ISurface::BufferHeap bufferHeap( + mDisplayWidth, mDisplayHeight, + mDecodedWidth, mDecodedHeight, + PIXEL_FORMAT_YCbCr_420_SP, + mMemoryHeap); + + status_t err = mISurface->registerBuffers(bufferHeap); + assert(err == OK); +} + +} // namespace android diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp new file mode 100644 index 0000000..5483238 --- /dev/null +++ b/media/libstagefright/omx/SoftwareRenderer.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2009 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 "SoftwareRenderer" +#include <utils/Log.h> + +#undef NDEBUG +#include <assert.h> + +#include <binder/MemoryHeapBase.h> +#include <media/stagefright/SoftwareRenderer.h> +#include <ui/ISurface.h> + +namespace android { + +#define QCOM_YUV 0 + +SoftwareRenderer::SoftwareRenderer( + const sp<ISurface> &surface, + size_t displayWidth, size_t displayHeight, + size_t decodedWidth, size_t decodedHeight) + : mISurface(surface), + mDisplayWidth(displayWidth), + mDisplayHeight(displayHeight), + mDecodedWidth(decodedWidth), + mDecodedHeight(decodedHeight), + mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565 + mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)), + mIndex(0) { + assert(mISurface.get() != NULL); + assert(mDecodedWidth > 0); + assert(mDecodedHeight > 0); + assert(mMemoryHeap->heapID() >= 0); + + ISurface::BufferHeap bufferHeap( + mDisplayWidth, mDisplayHeight, + mDecodedWidth, mDecodedHeight, + PIXEL_FORMAT_RGB_565, + mMemoryHeap); + + status_t err = mISurface->registerBuffers(bufferHeap); + assert(err == OK); +} + +SoftwareRenderer::~SoftwareRenderer() { + mISurface->unregisterBuffers(); +} + +void SoftwareRenderer::render( + const void *data, size_t size, void *platformPrivate) { + if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) { + LOGE("size is %d, expected %d", + size, (mDecodedHeight * mDecodedWidth * 3) / 2); + } + assert(size >= (mDecodedWidth * mDecodedHeight * 3) / 2); + + static const signed kClipMin = -278; + static const signed kClipMax = 535; + static uint8_t kClip[kClipMax - kClipMin + 1]; + static uint8_t *kAdjustedClip = &kClip[-kClipMin]; + + static bool clipInitialized = false; + + if (!clipInitialized) { + for (signed i = kClipMin; i <= kClipMax; ++i) { + kClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i; + } + clipInitialized = true; + } + + size_t offset = mIndex * mFrameSize; + + void *dst = (uint8_t *)mMemoryHeap->getBase() + offset; + + uint32_t *dst_ptr = (uint32_t *)dst; + + const uint8_t *src_y = (const uint8_t *)data; + + const uint8_t *src_u = + (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight; + +#if !QCOM_YUV + const uint8_t *src_v = + (const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2); +#endif + + for (size_t y = 0; y < mDecodedHeight; ++y) { + for (size_t x = 0; x < mDecodedWidth; x += 2) { + // B = 1.164 * (Y - 16) + 2.018 * (U - 128) + // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128) + // R = 1.164 * (Y - 16) + 1.596 * (V - 128) + + // B = 298/256 * (Y - 16) + 517/256 * (U - 128) + // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128) + // R = .................. + 409/256 * (V - 128) + + // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277 + // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172 + // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223 + + // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534 + // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432 + // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481 + + // clip range -278 .. 535 + + signed y1 = (signed)src_y[x] - 16; + signed y2 = (signed)src_y[x + 1] - 16; + +#if QCOM_YUV + signed u = (signed)src_u[x & ~1] - 128; + signed v = (signed)src_u[(x & ~1) + 1] - 128; +#else + signed u = (signed)src_u[x / 2] - 128; + signed v = (signed)src_v[x / 2] - 128; +#endif + + signed u_b = u * 517; + signed u_g = -u * 100; + signed v_g = -v * 208; + signed v_r = v * 409; + + signed tmp1 = y1 * 298; + signed b1 = (tmp1 + u_b) / 256; + signed g1 = (tmp1 + v_g + u_g) / 256; + signed r1 = (tmp1 + v_r) / 256; + + signed tmp2 = y2 * 298; + signed b2 = (tmp2 + u_b) / 256; + signed g2 = (tmp2 + v_g + u_g) / 256; + signed r2 = (tmp2 + v_r) / 256; + + uint32_t rgb1 = + ((kAdjustedClip[r1] >> 3) << 11) + | ((kAdjustedClip[g1] >> 2) << 5) + | (kAdjustedClip[b1] >> 3); + + uint32_t rgb2 = + ((kAdjustedClip[r2] >> 3) << 11) + | ((kAdjustedClip[g2] >> 2) << 5) + | (kAdjustedClip[b2] >> 3); + + dst_ptr[x / 2] = (rgb2 << 16) | rgb1; + } + + src_y += mDecodedWidth; + + if (y & 1) { +#if QCOM_YUV + src_u += mDecodedWidth; +#else + src_u += mDecodedWidth / 2; + src_v += mDecodedWidth / 2; +#endif + } + + dst_ptr += mDecodedWidth / 2; + } + + mISurface->postBuffer(offset); + mIndex = 1 - mIndex; +} + +} // namespace android diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp new file mode 100644 index 0000000..ba42ef4 --- /dev/null +++ b/media/libstagefright/omx/TIHardwareRenderer.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2009 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 "TIHardwareRenderer" +#include <utils/Log.h> + +#undef NDEBUG +#include <assert.h> + +#include <media/stagefright/TIHardwareRenderer.h> +#include <ui/ISurface.h> +#include <ui/Overlay.h> + +namespace android { + +//////////////////////////////////////////////////////////////////////////////// + +TIHardwareRenderer::TIHardwareRenderer( + const sp<ISurface> &surface, + size_t displayWidth, size_t displayHeight, + size_t decodedWidth, size_t decodedHeight) + : mISurface(surface), + mDisplayWidth(displayWidth), + mDisplayHeight(displayHeight), + mDecodedWidth(decodedWidth), + mDecodedHeight(decodedHeight), + mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) { + assert(mISurface.get() != NULL); + assert(mDecodedWidth > 0); + assert(mDecodedHeight > 0); + + sp<OverlayRef> ref = mISurface->createOverlay( + mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I); + + if (ref.get() == NULL) { + LOGE("Unable to create the overlay!"); + return; + } + + mOverlay = new Overlay(ref); + + for (size_t i = 0; i < mOverlay->getBufferCount(); ++i) { + mOverlayAddresses.push(mOverlay->getBufferAddress((void *)i)); + } + mIndex = mOverlayAddresses.size() - 1; +} + +TIHardwareRenderer::~TIHardwareRenderer() { + if (mOverlay.get() != NULL) { + mOverlay->destroy(); + mOverlay.clear(); + + // XXX apparently destroying an overlay is an asynchronous process... + sleep(1); + } +} + +void TIHardwareRenderer::render( + const void *data, size_t size, void *platformPrivate) { + // assert(size == mFrameSize); + + if (mOverlay.get() == NULL) { + return; + } + +#if 0 + overlay_buffer_t buffer; + if (mOverlay->dequeueBuffer(&buffer) == OK) { + void *addr = mOverlay->getBufferAddress(buffer); + + memcpy(addr, data, size); + + mOverlay->queueBuffer(buffer); + } +#else + memcpy(mOverlayAddresses[mIndex], data, size); + mOverlay->queueBuffer((void *)mIndex); + + if (mIndex-- == 0) { + mIndex = mOverlayAddresses.size() - 1; + } +#endif +} + +} // namespace android + |