Merge change 9372

* changes:
  The IOMX interface now instantiates IOMXRenderers to hide the details of hardware accelerated blitting.
This commit is contained in:
Android (Google) Code Review
2009-07-31 13:10:51 -07:00
17 changed files with 267 additions and 179 deletions

View File

@ -23,6 +23,7 @@
#include <utils/String8.h>
#include <OMX_Core.h>
#include <OMX_Video.h>
#define IOMX_USES_SOCKETS 0
@ -30,6 +31,8 @@ namespace android {
class IMemory;
class IOMXObserver;
class IOMXRenderer;
class ISurface;
class IOMX : public IInterface {
public:
@ -87,6 +90,13 @@ public:
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp) = 0;
#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) = 0;
};
struct omx_message {
@ -155,6 +165,13 @@ public:
virtual void on_message(const omx_message &msg) = 0;
};
class IOMXRenderer : public IInterface {
public:
DECLARE_META_INTERFACE(OMXRenderer);
virtual void render(IOMX::buffer_id buffer) = 0;
};
////////////////////////////////////////////////////////////////////////////////
class BnOMX : public BnInterface<IOMX> {
@ -171,6 +188,13 @@ public:
uint32_t flags = 0);
};
class BnOMXRenderer : public BnInterface<IOMXRenderer> {
public:
virtual status_t onTransact(
uint32_t code, const Parcel &data, Parcel *reply,
uint32_t flags = 0);
};
} // namespace android
#endif // ANDROID_IOMX_H_

View File

@ -28,6 +28,7 @@
namespace android {
class AudioPlayer;
class IOMXRenderer;
class ISurface;
class MediaExtractor;
class MediaBuffer;
@ -37,7 +38,6 @@ class MetaData;
class OMXDecoder;
class Surface;
class TimeSource;
class VideoRenderer;
class MediaPlayerImpl {
public:
@ -93,7 +93,7 @@ private:
sp<Surface> mSurface;
sp<ISurface> mISurface;
VideoRenderer *mRenderer;
sp<IOMXRenderer> mVideoRenderer;
sp<MediaPlayerBase::AudioSink> mAudioSink;

View File

@ -44,6 +44,7 @@ enum {
kKeyColorFormat = 'colf',
kKeyPlatformPrivate = 'priv',
kKeyDecoderComponent = 'decC',
kKeyBufferID = 'bfID',
};
enum {

View File

@ -1,51 +0,0 @@
/*
* 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 SURFACE_RENDERER_H_
#define SURFACE_RENDERER_H_
#include <media/stagefright/VideoRenderer.h>
#include <utils/RefBase.h>
namespace android {
class Surface;
class SurfaceRenderer : public VideoRenderer {
public:
SurfaceRenderer(
const sp<Surface> &surface,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
virtual ~SurfaceRenderer();
virtual void render(
const void *data, size_t size, void *platformPrivate);
private:
sp<Surface> mSurface;
size_t mDisplayWidth, mDisplayHeight;
size_t mDecodedWidth, mDecodedHeight;
SurfaceRenderer(const SurfaceRenderer &);
SurfaceRenderer &operator=(const SurfaceRenderer &);
};
} // namespace android
#endif // SURFACE_RENDERER_H_

View File

@ -36,6 +36,7 @@ namespace android {
class BufferMapper;
class Rect;
class MediaPlayerImpl;
class Surface;
class SurfaceComposerClient;
struct per_client_cblk_t;
@ -180,6 +181,7 @@ private:
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
friend class Test;
friend class MediaPlayerImpl;
const sp<ISurface>& getISurface() const { return mSurface; }
status_t getBufferLocked(int index);

View File

@ -5,6 +5,7 @@
#include <binder/IMemory.h>
#include <binder/Parcel.h>
#include <media/IOMX.h>
#include <ui/ISurface.h>
namespace android {
@ -23,7 +24,9 @@ enum {
OBSERVE_NODE,
FILL_BUFFER,
EMPTY_BUFFER,
CREATE_RENDERER,
OBSERVER_ON_MSG,
RENDERER_RENDER,
};
static void *readVoidStar(const Parcel *parcel) {
@ -262,6 +265,28 @@ public:
remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
}
#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) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeStrongBinder(surface->asBinder());
data.writeCString(componentName);
data.writeInt32(colorFormat);
data.writeInt32(encodedWidth);
data.writeInt32(encodedHeight);
data.writeInt32(displayWidth);
data.writeInt32(displayHeight);
remote()->transact(CREATE_RENDERER, data, &reply);
return interface_cast<IOMXRenderer>(reply.readStrongBinder());
}
};
IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
@ -513,6 +538,33 @@ status_t BnOMX::onTransact(
}
#endif
case CREATE_RENDERER:
{
CHECK_INTERFACE(IOMX, data, reply);
sp<ISurface> isurface =
interface_cast<ISurface>(data.readStrongBinder());
const char *componentName = data.readCString();
OMX_COLOR_FORMATTYPE colorFormat =
static_cast<OMX_COLOR_FORMATTYPE>(data.readInt32());
size_t encodedWidth = (size_t)data.readInt32();
size_t encodedHeight = (size_t)data.readInt32();
size_t displayWidth = (size_t)data.readInt32();
size_t displayHeight = (size_t)data.readInt32();
sp<IOMXRenderer> renderer =
createRenderer(isurface, componentName, colorFormat,
encodedWidth, encodedHeight,
displayWidth, displayHeight);
reply->writeStrongBinder(renderer->asBinder());
return OK;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
@ -558,4 +610,44 @@ status_t BnOMXObserver::onTransact(
}
}
////////////////////////////////////////////////////////////////////////////////
class BpOMXRenderer : public BpInterface<IOMXRenderer> {
public:
BpOMXRenderer(const sp<IBinder> &impl)
: BpInterface<IOMXRenderer>(impl) {
}
virtual void render(IOMX::buffer_id buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
writeVoidStar(buffer, &data);
// NOTE: Do NOT make this a ONE_WAY call, it must be synchronous
// so that the caller knows when to recycle the buffer.
remote()->transact(RENDERER_RENDER, data, &reply);
}
};
IMPLEMENT_META_INTERFACE(OMXRenderer, "android.hardware.IOMXRenderer");
status_t BnOMXRenderer::onTransact(
uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
switch (code) {
case RENDERER_RENDER:
{
CHECK_INTERFACE(IOMXRenderer, data, reply);
IOMX::buffer_id buffer = readVoidStar(&data);
render(buffer);
return NO_ERROR;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
} // namespace android

View File

@ -19,14 +19,10 @@ LOCAL_SRC_FILES:= \
MediaSource.cpp \
MetaData.cpp \
MmapSource.cpp \
QComHardwareRenderer.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
SoftwareRenderer.cpp \
SurfaceRenderer.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
TIHardwareRenderer.cpp \
Utils.cpp \
AudioPlayer.cpp \
ESDS.cpp \

View File

@ -35,12 +35,8 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXDecoder.h>
#include <media/stagefright/QComHardwareRenderer.h>
#include <media/stagefright/ShoutcastSource.h>
#include <media/stagefright/SoftwareRenderer.h>
#include <media/stagefright/SurfaceRenderer.h>
#include <media/stagefright/TimeSource.h>
#include <media/stagefright/TIHardwareRenderer.h>
#include <ui/PixelFormat.h>
#include <ui/Surface.h>
@ -61,7 +57,6 @@ MediaPlayerImpl::MediaPlayerImpl(const char *uri)
mDuration(0),
mPlaying(false),
mPaused(false),
mRenderer(NULL),
mSeeking(false),
mFrameSize(0),
mUseSoftwareColorConversion(false) {
@ -121,7 +116,6 @@ MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
mDuration(0),
mPlaying(false),
mPaused(false),
mRenderer(NULL),
mSeeking(false),
mFrameSize(0),
mUseSoftwareColorConversion(false) {
@ -379,7 +373,7 @@ void MediaPlayerImpl::displayOrDiscardFrame(
{
Mutex::Autolock autoLock(mLock);
if (mRenderer != NULL) {
if (mVideoRenderer.get() != NULL) {
sendFrameToISurface(buffer);
}
}
@ -652,52 +646,26 @@ void MediaPlayerImpl::populateISurface() {
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
assert(success);
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
const sp<ISurface> &isurface =
mSurface.get() != NULL ? mSurface->getISurface() : mISurface;
if (mSurface.get() != NULL) {
LOGW("Using SurfaceRenderer.");
mRenderer =
new SurfaceRenderer(
mSurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
} else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
&& !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
LOGW("Using QComHardwareRenderer.");
mRenderer =
new QComHardwareRenderer(
mISurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
} else if (format == OMX_COLOR_FormatCbYCrY
&& !strcmp(component, "OMX.TI.Video.Decoder")) {
LOGW("Using TIHardwareRenderer.");
mRenderer =
new TIHardwareRenderer(
mISurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
} else {
LOGW("Using software renderer.");
mRenderer = new SoftwareRenderer(
mISurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
}
mVideoRenderer =
mClient.interface()->createRenderer(
isurface, component,
(OMX_COLOR_FORMATTYPE)format,
decodedWidth, decodedHeight,
mVideoWidth, mVideoHeight);
}
void MediaPlayerImpl::depopulateISurface() {
delete mRenderer;
mRenderer = NULL;
mVideoRenderer.clear();
}
void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
void *platformPrivate;
if (!buffer->meta_data()->findPointer(
kKeyPlatformPrivate, &platformPrivate)) {
platformPrivate = NULL;
void *id;
if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
mVideoRenderer->render((IOMX::buffer_id)id);
}
mRenderer->render(
(const uint8_t *)buffer->data() + buffer->range_offset(),
buffer->range_length(),
platformPrivate);
}
void MediaPlayerImpl::setAudioSink(

View File

@ -154,8 +154,7 @@ OMXDecoder *OMXDecoder::Create(
if (!strncmp(codec, "OMX.qcom.video.", 15)) {
quirks |= kRequiresLoadedToIdleAfterAllocation;
}
if (!strcmp(codec, "OMX.TI.AAC.decode")
|| !strcmp(codec, "OMX.TI.MP3.decode")) {
if (!strcmp(codec, "OMX.TI.MP3.decode")) {
quirks |= kMeasuresTimeInMilliseconds;
}
@ -1551,6 +1550,10 @@ void OMXDecoder::onRealFillBufferDone(const omx_message &msg) {
kKeyPlatformPrivate,
msg.u.extended_buffer_data.platform_private);
media_buffer->meta_data()->setPointer(
kKeyBufferID,
msg.u.extended_buffer_data.buffer);
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) {
mErrorCondition = ERROR_END_OF_STREAM;
}

View File

@ -1,69 +0,0 @@
/*
* 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 "SurfaceRenderer"
#include <utils/Log.h>
#undef NDEBUG
#include <assert.h>
#include <media/stagefright/SurfaceRenderer.h>
#include <ui/Surface.h>
namespace android {
SurfaceRenderer::SurfaceRenderer(
const sp<Surface> &surface,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight)
: mSurface(surface),
mDisplayWidth(displayWidth),
mDisplayHeight(displayHeight),
mDecodedWidth(decodedWidth),
mDecodedHeight(decodedHeight) {
}
SurfaceRenderer::~SurfaceRenderer() {
}
void SurfaceRenderer::render(
const void *data, size_t size, void *platformPrivate) {
Surface::SurfaceInfo info;
status_t err = mSurface->lock(&info);
if (err != OK) {
return;
}
const uint8_t *src = (const uint8_t *)data;
uint8_t *dst = (uint8_t *)info.bits;
for (size_t i = 0; i < mDisplayHeight; ++i) {
memcpy(dst, src, mDisplayWidth);
src += mDecodedWidth;
dst += mDisplayWidth;
}
src += (mDecodedHeight - mDisplayHeight) * mDecodedWidth;
for (size_t i = 0; i < (mDisplayHeight + 1) / 2; ++i) {
memcpy(dst, src, (mDisplayWidth + 1) & ~1);
src += (mDecodedWidth + 1) & ~1;
dst += (mDisplayWidth + 1) & ~1;
}
mSurface->unlockAndPost();
}
} // namespace android

View File

@ -9,13 +9,17 @@ LOCAL_C_INCLUDES := $(PV_INCLUDES)
LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
LOCAL_SRC_FILES:= \
OMX.cpp
OMX.cpp \
QComHardwareRenderer.cpp \
SoftwareRenderer.cpp \
TIHardwareRenderer.cpp
LOCAL_SHARED_LIBRARIES := \
libbinder \
libmedia \
libutils \
libui \
LOCAL_SHARED_LIBRARIES := \
libbinder \
libmedia \
libutils \
libui \
libcutils \
libopencore_common
LOCAL_PRELINK_MODULE:= false

View File

@ -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

View File

@ -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;

View File

@ -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_

View File

@ -61,6 +61,10 @@ SoftwareRenderer::~SoftwareRenderer() {
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;