Squashed commit of the following:
commit 35cc68814a9537c31fde146e171e7b0bbdfe211e Author: Andreas Huber <andih@google.com> Date: Mon Aug 16 08:48:42 2010 -0700 Only enable support for yuv to yuv conversion on passion, where it's available, use the slower yuv->rgb565 path everywhere else. commit d8ac5a8814103e60d11d2acf61997fc31a1dc58d Author: Andreas Huber <andih@google.com> Date: Fri Aug 13 13:56:44 2010 -0700 The software renderer takes over all rendering, converting from yuv to yuv if possible and rgb565 otherwise. commit 684972074b74318bdcb826ed9b5b0864d2d2e273 Author: Andreas Huber <andih@google.com> Date: Fri Aug 13 09:34:35 2010 -0700 A first shot at supporting the new rendering APIs. Change-Id: Iea9b32856da46950501f1a700f616b5feac710fd
This commit is contained in:
@@ -25,6 +25,7 @@ namespace android {
|
||||
|
||||
class Parcel;
|
||||
class ISurface;
|
||||
class Surface;
|
||||
|
||||
class IMediaPlayer: public IInterface
|
||||
{
|
||||
@@ -33,7 +34,8 @@ public:
|
||||
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
virtual status_t setVideoSurface(const sp<ISurface>& surface) = 0;
|
||||
virtual status_t setVideoISurface(const sp<ISurface>& surface) = 0;
|
||||
virtual status_t setVideoSurface(const sp<Surface>& surface) = 0;
|
||||
virtual status_t prepareAsync() = 0;
|
||||
virtual status_t start() = 0;
|
||||
virtual status_t stop() = 0;
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace android {
|
||||
|
||||
class Parcel;
|
||||
class ISurface;
|
||||
class Surface;
|
||||
|
||||
template<typename T> class SortedVector;
|
||||
|
||||
@@ -104,7 +105,8 @@ public:
|
||||
const KeyedVector<String8, String8> *headers = NULL) = 0;
|
||||
|
||||
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
|
||||
virtual status_t setVideoSurface(const sp<ISurface>& surface) = 0;
|
||||
virtual status_t setVideoISurface(const sp<ISurface>& surface) = 0;
|
||||
virtual status_t setVideoSurface(const sp<Surface>& surface) = 0;
|
||||
virtual status_t prepare() = 0;
|
||||
virtual status_t prepareAsync() = 0;
|
||||
virtual status_t start() = 0;
|
||||
|
||||
@@ -43,7 +43,8 @@ public:
|
||||
const char *url, const KeyedVector<String8, String8> *headers);
|
||||
|
||||
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
|
||||
virtual status_t setVideoSurface(const sp<ISurface>& surface);
|
||||
virtual status_t setVideoISurface(const sp<ISurface>& surface);
|
||||
virtual status_t setVideoSurface(const sp<Surface>& surface);
|
||||
virtual status_t prepare();
|
||||
virtual status_t prepareAsync();
|
||||
virtual status_t start();
|
||||
|
||||
@@ -178,6 +178,7 @@ private:
|
||||
// MediaPlayer needs access to ISurface for display
|
||||
friend class MediaPlayer;
|
||||
friend class IOMX;
|
||||
friend class SoftwareRenderer;
|
||||
// this is just to be able to write some unit tests
|
||||
friend class Test;
|
||||
|
||||
|
||||
@@ -22,12 +22,14 @@
|
||||
|
||||
#include <media/IMediaPlayer.h>
|
||||
#include <surfaceflinger/ISurface.h>
|
||||
#include <surfaceflinger/Surface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
enum {
|
||||
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
|
||||
SET_VIDEO_SURFACE,
|
||||
SET_VIDEO_ISURFACE,
|
||||
PREPARE_ASYNC,
|
||||
START,
|
||||
STOP,
|
||||
@@ -65,11 +67,20 @@ public:
|
||||
remote()->transact(DISCONNECT, data, &reply);
|
||||
}
|
||||
|
||||
status_t setVideoSurface(const sp<ISurface>& surface)
|
||||
status_t setVideoISurface(const sp<ISurface>& surface)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(surface->asBinder());
|
||||
remote()->transact(SET_VIDEO_ISURFACE, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
status_t setVideoSurface(const sp<Surface>& surface)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
|
||||
Surface::writeToParcel(surface, &data);
|
||||
remote()->transact(SET_VIDEO_SURFACE, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
@@ -256,9 +267,15 @@ status_t BnMediaPlayer::onTransact(
|
||||
disconnect();
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case SET_VIDEO_SURFACE: {
|
||||
case SET_VIDEO_ISURFACE: {
|
||||
CHECK_INTERFACE(IMediaPlayer, data, reply);
|
||||
sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
|
||||
reply->writeInt32(setVideoISurface(surface));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case SET_VIDEO_SURFACE: {
|
||||
CHECK_INTERFACE(IMediaPlayer, data, reply);
|
||||
sp<Surface> surface = Surface::readFromParcel(data);
|
||||
reply->writeInt32(setVideoSurface(surface));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
@@ -206,10 +206,15 @@ status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
|
||||
LOGV("setVideoSurface");
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (mPlayer == 0) return NO_INIT;
|
||||
if (surface != NULL)
|
||||
return mPlayer->setVideoSurface(surface->getISurface());
|
||||
else
|
||||
return mPlayer->setVideoSurface(NULL);
|
||||
|
||||
status_t err = mPlayer->setVideoISurface(
|
||||
surface == NULL ? NULL : surface->getISurface());
|
||||
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return mPlayer->setVideoSurface(surface);
|
||||
}
|
||||
|
||||
// must call with lock held
|
||||
|
||||
@@ -889,7 +889,15 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
status_t MediaPlayerService::Client::setVideoSurface(const sp<ISurface>& surface)
|
||||
status_t MediaPlayerService::Client::setVideoISurface(const sp<ISurface>& surface)
|
||||
{
|
||||
LOGV("[%d] setVideoISurface(%p)", mConnId, surface.get());
|
||||
sp<MediaPlayerBase> p = getPlayer();
|
||||
if (p == 0) return UNKNOWN_ERROR;
|
||||
return p->setVideoISurface(surface);
|
||||
}
|
||||
|
||||
status_t MediaPlayerService::Client::setVideoSurface(const sp<Surface>& surface)
|
||||
{
|
||||
LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get());
|
||||
sp<MediaPlayerBase> p = getPlayer();
|
||||
|
||||
@@ -204,7 +204,8 @@ private:
|
||||
|
||||
// IMediaPlayer interface
|
||||
virtual void disconnect();
|
||||
virtual status_t setVideoSurface(const sp<ISurface>& surface);
|
||||
virtual status_t setVideoISurface(const sp<ISurface>& surface);
|
||||
virtual status_t setVideoSurface(const sp<Surface>& surface);
|
||||
virtual status_t prepareAsync();
|
||||
virtual status_t start();
|
||||
virtual status_t stop();
|
||||
|
||||
@@ -35,7 +35,8 @@ public:
|
||||
const char* path, const KeyedVector<String8, String8> *headers);
|
||||
|
||||
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
|
||||
virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
|
||||
virtual status_t setVideoISurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
|
||||
virtual status_t setVideoSurface(const sp<Surface>& surface) { return UNKNOWN_ERROR; }
|
||||
virtual status_t prepare();
|
||||
virtual status_t prepareAsync();
|
||||
virtual status_t start();
|
||||
|
||||
@@ -44,13 +44,20 @@ status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length
|
||||
return mPlayer->setDataSource(dup(fd), offset, length);
|
||||
}
|
||||
|
||||
status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
|
||||
LOGV("setVideoSurface");
|
||||
status_t StagefrightPlayer::setVideoISurface(const sp<ISurface> &surface) {
|
||||
LOGV("setVideoISurface");
|
||||
|
||||
mPlayer->setISurface(surface);
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t StagefrightPlayer::setVideoSurface(const sp<Surface> &surface) {
|
||||
LOGV("setVideoSurface");
|
||||
|
||||
mPlayer->setSurface(surface);
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t StagefrightPlayer::prepare() {
|
||||
return mPlayer->prepare();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ public:
|
||||
const char *url, const KeyedVector<String8, String8> *headers);
|
||||
|
||||
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
|
||||
virtual status_t setVideoSurface(const sp<ISurface> &surface);
|
||||
virtual status_t setVideoISurface(const sp<ISurface> &surface);
|
||||
virtual status_t setVideoSurface(const sp<Surface> &surface);
|
||||
virtual status_t prepare();
|
||||
virtual status_t prepareAsync();
|
||||
virtual status_t start();
|
||||
|
||||
@@ -75,7 +75,10 @@ class TestPlayerStub : public MediaPlayerInterface {
|
||||
|
||||
|
||||
// All the methods below wrap the mPlayer instance.
|
||||
virtual status_t setVideoSurface(const android::sp<android::ISurface>& s) {
|
||||
virtual status_t setVideoISurface(const android::sp<android::ISurface>& s) {
|
||||
return mPlayer->setVideoISurface(s);
|
||||
}
|
||||
virtual status_t setVideoSurface(const android::sp<android::Surface>& s) {
|
||||
return mPlayer->setVideoSurface(s);
|
||||
}
|
||||
virtual status_t prepare() {return mPlayer->prepare();}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#include <media/stagefright/MetaData.h>
|
||||
#include <media/stagefright/OMXCodec.h>
|
||||
|
||||
#include <surfaceflinger/ISurface.h>
|
||||
#include <surfaceflinger/Surface.h>
|
||||
|
||||
#include <media/stagefright/foundation/ALooper.h>
|
||||
|
||||
@@ -97,13 +97,14 @@ struct AwesomeLocalRenderer : public AwesomeRenderer {
|
||||
bool previewOnly,
|
||||
const char *componentName,
|
||||
OMX_COLOR_FORMATTYPE colorFormat,
|
||||
const sp<ISurface> &surface,
|
||||
const sp<ISurface> &isurface,
|
||||
const sp<Surface> &surface,
|
||||
size_t displayWidth, size_t displayHeight,
|
||||
size_t decodedWidth, size_t decodedHeight)
|
||||
: mTarget(NULL),
|
||||
mLibHandle(NULL) {
|
||||
init(previewOnly, componentName,
|
||||
colorFormat, surface, displayWidth,
|
||||
colorFormat, isurface, surface, displayWidth,
|
||||
displayHeight, decodedWidth, decodedHeight);
|
||||
}
|
||||
|
||||
@@ -135,7 +136,8 @@ private:
|
||||
bool previewOnly,
|
||||
const char *componentName,
|
||||
OMX_COLOR_FORMATTYPE colorFormat,
|
||||
const sp<ISurface> &surface,
|
||||
const sp<ISurface> &isurface,
|
||||
const sp<Surface> &surface,
|
||||
size_t displayWidth, size_t displayHeight,
|
||||
size_t decodedWidth, size_t decodedHeight);
|
||||
|
||||
@@ -147,7 +149,8 @@ void AwesomeLocalRenderer::init(
|
||||
bool previewOnly,
|
||||
const char *componentName,
|
||||
OMX_COLOR_FORMATTYPE colorFormat,
|
||||
const sp<ISurface> &surface,
|
||||
const sp<ISurface> &isurface,
|
||||
const sp<Surface> &surface,
|
||||
size_t displayWidth, size_t displayHeight,
|
||||
size_t decodedWidth, size_t decodedHeight) {
|
||||
if (!previewOnly) {
|
||||
@@ -173,7 +176,7 @@ void AwesomeLocalRenderer::init(
|
||||
|
||||
if (func) {
|
||||
mTarget =
|
||||
(*func)(surface, componentName, colorFormat,
|
||||
(*func)(isurface, componentName, colorFormat,
|
||||
displayWidth, displayHeight,
|
||||
decodedWidth, decodedHeight);
|
||||
}
|
||||
@@ -619,8 +622,18 @@ status_t AwesomePlayer::play_l() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
void AwesomePlayer::notifyVideoSize_l() {
|
||||
sp<MetaData> meta = mVideoSource->getFormat();
|
||||
|
||||
int32_t decodedWidth, decodedHeight;
|
||||
CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
|
||||
CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
|
||||
|
||||
notifyListener_l(MEDIA_SET_VIDEO_SIZE, decodedWidth, decodedHeight);
|
||||
}
|
||||
|
||||
void AwesomePlayer::initRenderer_l() {
|
||||
if (mISurface != NULL) {
|
||||
if (mSurface != NULL || mISurface != NULL) {
|
||||
sp<MetaData> meta = mVideoSource->getFormat();
|
||||
|
||||
int32_t format;
|
||||
@@ -637,7 +650,18 @@ void AwesomePlayer::initRenderer_l() {
|
||||
// before creating a new one.
|
||||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
if (!strncmp("OMX.", component, 4)) {
|
||||
if (mSurface != NULL) {
|
||||
// Other decoders are instantiated locally and as a consequence
|
||||
// allocate their buffers in local address space.
|
||||
mVideoRenderer = new AwesomeLocalRenderer(
|
||||
false, // previewOnly
|
||||
component,
|
||||
(OMX_COLOR_FORMATTYPE)format,
|
||||
mISurface,
|
||||
mSurface,
|
||||
mVideoWidth, mVideoHeight,
|
||||
decodedWidth, decodedHeight);
|
||||
} else {
|
||||
// Our OMX codecs allocate buffers on the media_server side
|
||||
// therefore they require a remote IOMXRenderer that knows how
|
||||
// to display them.
|
||||
@@ -647,16 +671,6 @@ void AwesomePlayer::initRenderer_l() {
|
||||
(OMX_COLOR_FORMATTYPE)format,
|
||||
decodedWidth, decodedHeight,
|
||||
mVideoWidth, mVideoHeight));
|
||||
} else {
|
||||
// Other decoders are instantiated locally and as a consequence
|
||||
// allocate their buffers in local address space.
|
||||
mVideoRenderer = new AwesomeLocalRenderer(
|
||||
false, // previewOnly
|
||||
component,
|
||||
(OMX_COLOR_FORMATTYPE)format,
|
||||
mISurface,
|
||||
mVideoWidth, mVideoHeight,
|
||||
decodedWidth, decodedHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,6 +709,12 @@ void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
|
||||
mISurface = isurface;
|
||||
}
|
||||
|
||||
void AwesomePlayer::setSurface(const sp<Surface> &surface) {
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
mSurface = surface;
|
||||
}
|
||||
|
||||
void AwesomePlayer::setAudioSink(
|
||||
const sp<MediaPlayerBase::AudioSink> &audioSink) {
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
@@ -937,6 +957,8 @@ void AwesomePlayer::onVideoEvent() {
|
||||
if (err == INFO_FORMAT_CHANGED) {
|
||||
LOGV("VideoSource signalled format change.");
|
||||
|
||||
notifyVideoSize_l();
|
||||
|
||||
if (mVideoRenderer != NULL) {
|
||||
mVideoRendererIsPreview = false;
|
||||
initRenderer_l();
|
||||
@@ -1422,10 +1444,10 @@ void AwesomePlayer::onPrepareAsyncEvent() {
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mIsAsyncPrepare) {
|
||||
if (mVideoWidth < 0 || mVideoHeight < 0) {
|
||||
if (mVideoSource == NULL) {
|
||||
notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
|
||||
} else {
|
||||
notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
|
||||
notifyVideoSize_l();
|
||||
}
|
||||
|
||||
notifyListener_l(MEDIA_PREPARED);
|
||||
@@ -1540,13 +1562,14 @@ status_t AwesomePlayer::resume() {
|
||||
|
||||
mFlags = state->mFlags & (LOOPING | AT_EOS);
|
||||
|
||||
if (state->mLastVideoFrame && mISurface != NULL) {
|
||||
if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
|
||||
mVideoRenderer =
|
||||
new AwesomeLocalRenderer(
|
||||
true, // previewOnly
|
||||
"",
|
||||
(OMX_COLOR_FORMATTYPE)state->mColorFormat,
|
||||
mISurface,
|
||||
mSurface,
|
||||
state->mVideoWidth,
|
||||
state->mVideoHeight,
|
||||
state->mDecodedWidth,
|
||||
|
||||
@@ -17,6 +17,11 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libsurfaceflinger_client\
|
||||
libcamera_client
|
||||
|
||||
# ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
|
||||
ifeq ($(TARGET_PRODUCT),passion)
|
||||
LOCAL_CFLAGS += -DHAS_YCBCR420_SP_ADRENO
|
||||
endif
|
||||
|
||||
LOCAL_MODULE:= libstagefright_color_conversion
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
@@ -22,65 +22,169 @@
|
||||
#include <binder/MemoryHeapBase.h>
|
||||
#include <binder/MemoryHeapPmem.h>
|
||||
#include <media/stagefright/MediaDebug.h>
|
||||
#include <surfaceflinger/ISurface.h>
|
||||
#include <surfaceflinger/Surface.h>
|
||||
#include <ui/android_native_buffer.h>
|
||||
#include <ui/GraphicBufferMapper.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
SoftwareRenderer::SoftwareRenderer(
|
||||
OMX_COLOR_FORMATTYPE colorFormat,
|
||||
const sp<ISurface> &surface,
|
||||
const sp<Surface> &surface,
|
||||
size_t displayWidth, size_t displayHeight,
|
||||
size_t decodedWidth, size_t decodedHeight)
|
||||
: mColorFormat(colorFormat),
|
||||
mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
|
||||
mISurface(surface),
|
||||
mConverter(NULL),
|
||||
mYUVMode(None),
|
||||
mSurface(surface),
|
||||
mDisplayWidth(displayWidth),
|
||||
mDisplayHeight(displayHeight),
|
||||
mDecodedWidth(decodedWidth),
|
||||
mDecodedHeight(decodedHeight),
|
||||
mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
|
||||
mIndex(0) {
|
||||
mMemoryHeap = new MemoryHeapBase("/dev/pmem_adsp", 2 * mFrameSize);
|
||||
if (mMemoryHeap->heapID() < 0) {
|
||||
LOGI("Creating physical memory heap failed, reverting to regular heap.");
|
||||
mMemoryHeap = new MemoryHeapBase(2 * mFrameSize);
|
||||
} else {
|
||||
sp<MemoryHeapPmem> pmemHeap = new MemoryHeapPmem(mMemoryHeap);
|
||||
pmemHeap->slap();
|
||||
mMemoryHeap = pmemHeap;
|
||||
mDecodedHeight(decodedHeight) {
|
||||
LOGI("input format = %d", mColorFormat);
|
||||
LOGI("display = %d x %d, decoded = %d x %d",
|
||||
mDisplayWidth, mDisplayHeight, mDecodedWidth, mDecodedHeight);
|
||||
|
||||
int halFormat;
|
||||
switch (mColorFormat) {
|
||||
#if HAS_YCBCR420_SP_ADRENO
|
||||
case OMX_COLOR_FormatYUV420Planar:
|
||||
{
|
||||
halFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO;
|
||||
mYUVMode = YUV420ToYUV420sp;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x7fa30c00:
|
||||
{
|
||||
halFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO;
|
||||
mYUVMode = YUV420spToYUV420sp;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
halFormat = HAL_PIXEL_FORMAT_RGB_565;
|
||||
|
||||
mConverter = new ColorConverter(
|
||||
mColorFormat, OMX_COLOR_Format16bitRGB565);
|
||||
CHECK(mConverter->isValid());
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK(mISurface.get() != NULL);
|
||||
CHECK(mSurface.get() != NULL);
|
||||
CHECK(mDecodedWidth > 0);
|
||||
CHECK(mDecodedHeight > 0);
|
||||
CHECK(mMemoryHeap->heapID() >= 0);
|
||||
CHECK(mConverter.isValid());
|
||||
CHECK(mConverter == NULL || mConverter->isValid());
|
||||
|
||||
ISurface::BufferHeap bufferHeap(
|
||||
mDisplayWidth, mDisplayHeight,
|
||||
mDecodedWidth, mDecodedHeight,
|
||||
PIXEL_FORMAT_RGB_565,
|
||||
mMemoryHeap);
|
||||
CHECK_EQ(0,
|
||||
native_window_set_usage(
|
||||
mSurface.get(),
|
||||
GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
|
||||
| GRALLOC_USAGE_HW_TEXTURE));
|
||||
|
||||
status_t err = mISurface->registerBuffers(bufferHeap);
|
||||
CHECK_EQ(err, OK);
|
||||
CHECK_EQ(0, native_window_set_buffer_count(mSurface.get(), 2));
|
||||
|
||||
// Width must be multiple of 32???
|
||||
CHECK_EQ(0, native_window_set_buffers_geometry(
|
||||
mSurface.get(), mDecodedWidth, mDecodedHeight,
|
||||
halFormat));
|
||||
}
|
||||
|
||||
SoftwareRenderer::~SoftwareRenderer() {
|
||||
mISurface->unregisterBuffers();
|
||||
delete mConverter;
|
||||
mConverter = NULL;
|
||||
}
|
||||
|
||||
static inline size_t ALIGN(size_t x, size_t alignment) {
|
||||
return (x + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
void SoftwareRenderer::render(
|
||||
const void *data, size_t size, void *platformPrivate) {
|
||||
size_t offset = mIndex * mFrameSize;
|
||||
void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
|
||||
android_native_buffer_t *buf;
|
||||
CHECK_EQ(0, mSurface->dequeueBuffer(mSurface.get(), &buf));
|
||||
CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
|
||||
|
||||
mConverter.convert(
|
||||
mDecodedWidth, mDecodedHeight,
|
||||
data, 0, dst, 2 * mDecodedWidth);
|
||||
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
|
||||
|
||||
mISurface->postBuffer(offset);
|
||||
mIndex = 1 - mIndex;
|
||||
Rect bounds(mDecodedWidth, mDecodedHeight);
|
||||
|
||||
void *dst;
|
||||
CHECK_EQ(0, mapper.lock(
|
||||
buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
|
||||
|
||||
if (mConverter) {
|
||||
mConverter->convert(
|
||||
mDecodedWidth, mDecodedHeight,
|
||||
data, 0, dst, buf->stride * 2);
|
||||
} else if (mYUVMode == YUV420spToYUV420sp) {
|
||||
// Input and output are both YUV420sp, but the alignment requirements
|
||||
// are different.
|
||||
size_t srcYStride = mDecodedWidth;
|
||||
const uint8_t *srcY = (const uint8_t *)data;
|
||||
uint8_t *dstY = (uint8_t *)dst;
|
||||
for (size_t i = 0; i < mDecodedHeight; ++i) {
|
||||
memcpy(dstY, srcY, mDecodedWidth);
|
||||
srcY += srcYStride;
|
||||
dstY += buf->stride;
|
||||
}
|
||||
|
||||
size_t srcUVStride = (mDecodedWidth + 1) & ~1;
|
||||
size_t dstUVStride = ALIGN(mDecodedWidth / 2, 32) * 2;
|
||||
|
||||
const uint8_t *srcUV = (const uint8_t *)data
|
||||
+ mDecodedHeight * mDecodedWidth;
|
||||
|
||||
size_t dstUVOffset = ALIGN(ALIGN(mDecodedHeight, 32) * buf->stride, 4096);
|
||||
uint8_t *dstUV = (uint8_t *)dst + dstUVOffset;
|
||||
|
||||
for (size_t i = 0; i < (mDecodedHeight + 1) / 2; ++i) {
|
||||
memcpy(dstUV, srcUV, (mDecodedWidth + 1) & ~1);
|
||||
srcUV += srcUVStride;
|
||||
dstUV += dstUVStride;
|
||||
}
|
||||
} else if (mYUVMode == YUV420ToYUV420sp) {
|
||||
// Input is YUV420 planar, output is YUV420sp, adhere to proper
|
||||
// alignment requirements.
|
||||
size_t srcYStride = mDecodedWidth;
|
||||
const uint8_t *srcY = (const uint8_t *)data;
|
||||
uint8_t *dstY = (uint8_t *)dst;
|
||||
for (size_t i = 0; i < mDecodedHeight; ++i) {
|
||||
memcpy(dstY, srcY, mDecodedWidth);
|
||||
srcY += srcYStride;
|
||||
dstY += buf->stride;
|
||||
}
|
||||
|
||||
size_t srcUVStride = (mDecodedWidth + 1) / 2;
|
||||
size_t dstUVStride = ALIGN(mDecodedWidth / 2, 32) * 2;
|
||||
|
||||
const uint8_t *srcU = (const uint8_t *)data
|
||||
+ mDecodedHeight * mDecodedWidth;
|
||||
|
||||
const uint8_t *srcV =
|
||||
srcU + ((mDecodedWidth + 1) / 2) * ((mDecodedHeight + 1) / 2);
|
||||
|
||||
size_t dstUVOffset = ALIGN(ALIGN(mDecodedHeight, 32) * buf->stride, 4096);
|
||||
uint8_t *dstUV = (uint8_t *)dst + dstUVOffset;
|
||||
|
||||
for (size_t i = 0; i < (mDecodedHeight + 1) / 2; ++i) {
|
||||
for (size_t j = 0; j < (mDecodedWidth + 1) / 2; ++j) {
|
||||
dstUV[2 * j + 1] = srcU[j];
|
||||
dstUV[2 * j] = srcV[j];
|
||||
}
|
||||
srcU += srcUVStride;
|
||||
srcV += srcUVStride;
|
||||
dstUV += dstUVStride;
|
||||
}
|
||||
} else {
|
||||
memcpy(dst, data, size);
|
||||
}
|
||||
|
||||
CHECK_EQ(0, mapper.unlock(buf->handle));
|
||||
|
||||
CHECK_EQ(0, mSurface->queueBuffer(mSurface.get(), buf));
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -76,6 +76,7 @@ struct AwesomePlayer {
|
||||
bool isPlaying() const;
|
||||
|
||||
void setISurface(const sp<ISurface> &isurface);
|
||||
void setSurface(const sp<Surface> &surface);
|
||||
void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
|
||||
status_t setLooping(bool shouldLoop);
|
||||
|
||||
@@ -117,6 +118,7 @@ private:
|
||||
wp<MediaPlayerBase> mListener;
|
||||
|
||||
sp<ISurface> mISurface;
|
||||
sp<Surface> mSurface;
|
||||
sp<MediaPlayerBase::AudioSink> mAudioSink;
|
||||
|
||||
SystemTimeSource mSystemTimeSource;
|
||||
@@ -219,6 +221,7 @@ private:
|
||||
status_t seekTo_l(int64_t timeUs);
|
||||
status_t pause_l();
|
||||
void initRenderer_l();
|
||||
void notifyVideoSize_l();
|
||||
void seekAudioIfNecessary_l();
|
||||
|
||||
void cancelPlayerEvents(bool keepBufferingGoing = false);
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
class ISurface;
|
||||
class Surface;
|
||||
class MemoryHeapBase;
|
||||
|
||||
class SoftwareRenderer : public VideoRenderer {
|
||||
public:
|
||||
SoftwareRenderer(
|
||||
OMX_COLOR_FORMATTYPE colorFormat,
|
||||
const sp<ISurface> &surface,
|
||||
const sp<Surface> &surface,
|
||||
size_t displayWidth, size_t displayHeight,
|
||||
size_t decodedWidth, size_t decodedHeight);
|
||||
|
||||
@@ -41,14 +41,18 @@ public:
|
||||
const void *data, size_t size, void *platformPrivate);
|
||||
|
||||
private:
|
||||
enum YUVMode {
|
||||
None,
|
||||
YUV420ToYUV420sp,
|
||||
YUV420spToYUV420sp,
|
||||
};
|
||||
|
||||
OMX_COLOR_FORMATTYPE mColorFormat;
|
||||
ColorConverter mConverter;
|
||||
sp<ISurface> mISurface;
|
||||
ColorConverter *mConverter;
|
||||
YUVMode mYUVMode;
|
||||
sp<Surface> mSurface;
|
||||
size_t mDisplayWidth, mDisplayHeight;
|
||||
size_t mDecodedWidth, mDecodedHeight;
|
||||
size_t mFrameSize;
|
||||
sp<MemoryHeapBase> mMemoryHeap;
|
||||
int mIndex;
|
||||
|
||||
SoftwareRenderer(const SoftwareRenderer &);
|
||||
SoftwareRenderer &operator=(const SoftwareRenderer &);
|
||||
|
||||
@@ -495,12 +495,17 @@ sp<IOMXRenderer> OMX::createRenderer(
|
||||
}
|
||||
|
||||
if (!impl) {
|
||||
#if 0
|
||||
LOGW("Using software renderer.");
|
||||
impl = new SoftwareRenderer(
|
||||
colorFormat,
|
||||
surface,
|
||||
displayWidth, displayHeight,
|
||||
encodedWidth, encodedHeight);
|
||||
#else
|
||||
CHECK(!"Should not be here.");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
return new OMXRenderer(impl);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
using android::INVALID_OPERATION;
|
||||
using android::ISurface;
|
||||
using android::Surface;
|
||||
using android::MediaPlayerBase;
|
||||
using android::OK;
|
||||
using android::Parcel;
|
||||
@@ -67,7 +68,8 @@ class Player: public MediaPlayerBase
|
||||
}
|
||||
|
||||
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
|
||||
virtual status_t setVideoSurface(const sp<ISurface>& surface) {return OK;}
|
||||
virtual status_t setVideoISurface(const sp<ISurface>& surface) {return OK;}
|
||||
virtual status_t setVideoSurface(const sp<Surface>& surface) {return OK;}
|
||||
virtual status_t prepare() {return OK;}
|
||||
virtual status_t prepareAsync() {return OK;}
|
||||
virtual status_t start() {return OK;}
|
||||
|
||||
@@ -22,7 +22,7 @@ LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
|
||||
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
|
||||
|
||||
ifeq ($(TARGET_BOARD_PLATFORM), omap3)
|
||||
LOCAL_CFLAGS += -DNO_RGBX_8888
|
||||
LOCAL_CFLAGS += -DNO_RGBX_8888 -DHAS_PUSH_BUFFERS
|
||||
endif
|
||||
|
||||
# need "-lrt" on Linux simulator to pick up clock_gettime
|
||||
|
||||
@@ -165,7 +165,7 @@ void SurfaceFlinger::bootFinished()
|
||||
{
|
||||
const nsecs_t now = systemTime();
|
||||
const nsecs_t duration = now - mBootTime;
|
||||
LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
|
||||
LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
|
||||
mBootFinished = true;
|
||||
property_set("ctl.stop", "bootanim");
|
||||
}
|
||||
@@ -201,10 +201,10 @@ status_t SurfaceFlinger::readyToRun()
|
||||
mServerHeap = new MemoryHeapBase(4096,
|
||||
MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
|
||||
LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
|
||||
|
||||
|
||||
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
|
||||
LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
|
||||
|
||||
|
||||
new(mServerCblk) surface_flinger_cblk_t;
|
||||
|
||||
// initialize primary screen
|
||||
@@ -233,7 +233,7 @@ status_t SurfaceFlinger::readyToRun()
|
||||
|
||||
// Initialize OpenGL|ES
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glShadeModel(GL_FLAT);
|
||||
@@ -267,7 +267,7 @@ status_t SurfaceFlinger::readyToRun()
|
||||
|
||||
// start boot animation
|
||||
property_set("ctl.start", "bootanim");
|
||||
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -662,7 +662,7 @@ void SurfaceFlinger::computeVisibleRegions(
|
||||
|
||||
// Update aboveOpaqueLayers for next (lower) layer
|
||||
aboveOpaqueLayers.orSelf(opaqueRegion);
|
||||
|
||||
|
||||
// Store the visible region is screen space
|
||||
layer->setVisibleRegion(visibleRegion);
|
||||
layer->setCoveredRegion(coveredRegion);
|
||||
@@ -781,8 +781,8 @@ void SurfaceFlinger::handleRepaint()
|
||||
glLoadIdentity();
|
||||
|
||||
uint32_t flags = hw.getFlags();
|
||||
if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
|
||||
(flags & DisplayHardware::BUFFER_PRESERVED))
|
||||
if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
|
||||
(flags & DisplayHardware::BUFFER_PRESERVED))
|
||||
{
|
||||
// we can redraw only what's dirty, but since SWAP_RECTANGLE only
|
||||
// takes a rectangle, we must make sure to update that whole
|
||||
@@ -1129,7 +1129,7 @@ void SurfaceFlinger::closeGlobalTransaction()
|
||||
if (android_atomic_dec(&mTransactionCount) == 1) {
|
||||
signalEvent();
|
||||
|
||||
// if there is a transaction with a resize, wait for it to
|
||||
// if there is a transaction with a resize, wait for it to
|
||||
// take effect before returning.
|
||||
Mutex::Autolock _l(mStateLock);
|
||||
while (mResizeTransationPending) {
|
||||
@@ -1173,7 +1173,7 @@ status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int SurfaceFlinger::setOrientation(DisplayID dpy,
|
||||
int SurfaceFlinger::setOrientation(DisplayID dpy,
|
||||
int orientation, uint32_t flags)
|
||||
{
|
||||
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
|
||||
@@ -1206,14 +1206,17 @@ sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid,
|
||||
int(w), int(h));
|
||||
return surfaceHandle;
|
||||
}
|
||||
|
||||
|
||||
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
|
||||
sp<Layer> normalLayer;
|
||||
switch (flags & eFXSurfaceMask) {
|
||||
case eFXSurfaceNormal:
|
||||
#if HAS_PUSH_BUFFERS
|
||||
if (UNLIKELY(flags & ePushBuffers)) {
|
||||
layer = createPushBuffersSurface(client, d, w, h, flags);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
normalLayer = createNormalSurface(client, d, w, h, flags, format);
|
||||
layer = normalLayer;
|
||||
}
|
||||
@@ -1232,7 +1235,7 @@ sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid,
|
||||
ssize_t token = addClientLayer(client, layer);
|
||||
|
||||
surfaceHandle = layer->getSurface();
|
||||
if (surfaceHandle != 0) {
|
||||
if (surfaceHandle != 0) {
|
||||
params->token = token;
|
||||
params->identity = surfaceHandle->getIdentity();
|
||||
params->width = w;
|
||||
@@ -1316,7 +1319,7 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
|
||||
/*
|
||||
* called by the window manager, when a surface should be marked for
|
||||
* destruction.
|
||||
*
|
||||
*
|
||||
* The surface is removed from the current and drawing lists, but placed
|
||||
* in the purgatory queue, so it's not destroyed right-away (we need
|
||||
* to wait for all client's references to go away first).
|
||||
@@ -1337,7 +1340,7 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid)
|
||||
status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
|
||||
{
|
||||
// called by ~ISurface() when all references are gone
|
||||
|
||||
|
||||
class MessageDestroySurface : public MessageBase {
|
||||
SurfaceFlinger* flinger;
|
||||
sp<LayerBaseClient> layer;
|
||||
@@ -1350,9 +1353,9 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
|
||||
layer.clear(); // clear it outside of the lock;
|
||||
Mutex::Autolock _l(flinger->mStateLock);
|
||||
/*
|
||||
* remove the layer from the current list -- chances are that it's
|
||||
* not in the list anyway, because it should have been removed
|
||||
* already upon request of the client (eg: window manager).
|
||||
* remove the layer from the current list -- chances are that it's
|
||||
* not in the list anyway, because it should have been removed
|
||||
* already upon request of the client (eg: window manager).
|
||||
* However, a buggy client could have not done that.
|
||||
* Since we know we don't have any more clients, we don't need
|
||||
* to use the purgatory.
|
||||
@@ -1467,7 +1470,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
|
||||
}
|
||||
const bool locked(retry >= 0);
|
||||
if (!locked) {
|
||||
snprintf(buffer, SIZE,
|
||||
snprintf(buffer, SIZE,
|
||||
"SurfaceFlinger appears to be unresponsive, "
|
||||
"dumping anyways (no locks held)\n");
|
||||
result.append(buffer);
|
||||
|
||||
Reference in New Issue
Block a user