Squashed commit of the following:

commit 374ea382ee3a9e3ce17e4c6357fc40d02e362810
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 28 09:54:13 2009 -0700

    PV's OMX implementation now uses (spec-compliant) microseconds instead of milliseconds in buffer timestamps.

commit 8d02f8ab5d7b022ad4ad34db2a9bdeea6ce2acfe
Author: Andreas Huber <andih@google.com>
Date:   Mon Jul 27 14:24:26 2009 -0700

    Support for using an overlay for video playback on TI hardware.

    Appears to be currently constrained to CbYCrY 16-bit colorspace.

commit d17f321cb4b15c1fea378f33a7ef5998f23dd0fc
Author: Andreas Huber <andih@google.com>
Date:   Mon Jul 27 09:45:38 2009 -0700

    Added '--audio-only' commandline option to stagefright tool.

commit d8beef6be5c668c46451446d87e622933371cd75
Author: Andreas Huber <andih@google.com>
Date:   Fri Jul 24 13:35:00 2009 -0700

    Generalize the various workarounds for OMX nodes with their own unique interpretation of the spec.

commit c7dfd53eeadf8ed5a39bf2b19b014dcd62f3324d
Author: Andreas Huber <andih@google.com>
Date:   Thu Jul 23 16:06:36 2009 -0700

    Fixed erroneous TI AAC decoder behaviour wrt shutdown.

    The AAC decoder appears to not return out buffers on an Executing->Idle transition, implemented a workaround that does a flush on all ports followed by the Executing->Idle. Oh, and flush with OMX_ALL doesn't properly work either. Fun.

commit d6377282e75060881336578f166f9c7feacf3f8f
Author: Andreas Huber <andih@google.com>
Date:   Thu Jul 23 14:06:50 2009 -0700

    Apparently the "channels" parameter in AudioTrack's constructor no longer counts channels but is a bitmask of enabled destinations, update the code accordingly.

commit ff698c79e851a2e57d362e9c3a09828af4048087
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 16:54:44 2009 -0700

    Fix MPEG4 decoding using TI's hardware decoder that I broke earlier...

commit 2ef78bb87cd856eb7f0b3d7dd68782a8650c12bf
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 15:43:18 2009 -0700

    Now that the qcom decoder properly advertises its own custom colorspace, update dependent code to reflect this fact.

commit bbaec96910727080fd7c8a6907c04facb9f5220f
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 14:32:03 2009 -0700

    Finishing up previous, incomplete change.

commit 76f14a1ae816b6f434771f8d12bdad81196f351e
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 14:25:17 2009 -0700

    The TI video decoder now properly decoder AVC/H.264 content.

commit e106130d8c100d5c94603e43864a7a93cca10252
Author: Andreas Huber <andih@google.com>
Date:   Wed Jul 22 08:56:04 2009 -0700

    Experimental support for the TI H.264 decoder, various modifications to OMXDecoder, non-functional still.

commit 241c3062dec3447db1a1ee74558cb4b9098fc404
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 21 12:13:09 2009 -0700

    Enable TI hardware OMX decoders (except for AVC/H.264 which still has issues).

    This particular set of OMX nodes does not appear to properly return our buffers when sending the "disable" command on a port. Rather it reqires manually flushing that port and _then_ disabling it instead.

commit 1c34506a46e32ce25f2a86f3b4250dcfc037356a
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 21 08:51:35 2009 -0700

    Make it simpler to switch between the stagefright player and PVPlayer.

commit 249c6de05671d403f8dd51f095d49bf190430c9c
Author: Andreas Huber <andih@google.com>
Date:   Mon Jul 20 14:38:15 2009 -0700

    Prepare to use soon-to-be-available hardware decoders in the OMX decoder.
This commit is contained in:
Andreas Huber
2009-07-28 10:03:13 -07:00
parent b3c82efb47
commit 8a432776d0
12 changed files with 775 additions and 171 deletions

View File

@@ -119,7 +119,8 @@ int main(int argc, char **argv) {
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
OMXDecoder *encoder = OMXDecoder::CreateEncoder(&client, enc_meta);
OMXDecoder *encoder =
OMXDecoder::Create(&client, enc_meta, true /* createEncoder */);
encoder->setSource(decoder);
// encoder->setSource(meta, new DummySource(width, height));

View File

@@ -102,6 +102,7 @@ static int64_t getNowUs() {
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
bool audioOnly = false;
if (argc > 1 && !strcmp(argv[1], "--list")) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -121,6 +122,10 @@ int main(int argc, char **argv) {
}
return 0;
} else if (argc > 1 && !strcmp(argv[1], "--audio")) {
audioOnly = true;
++argv;
--argc;
}
#if 0
@@ -149,7 +154,11 @@ int main(int argc, char **argv) {
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
if (!strncasecmp(mime, "video/", 6)) {
if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
break;
}
if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
break;
}
}

View File

@@ -26,6 +26,8 @@
#include <utils/List.h>
#include <utils/threads.h>
#include <OMX_Video.h>
namespace android {
class OMXMediaBuffer;
@@ -35,10 +37,8 @@ class OMXDecoder : public MediaSource,
public MediaBufferObserver {
public:
static OMXDecoder *Create(
OMXClient *client, const sp<MetaData> &data);
static OMXDecoder *CreateEncoder(
OMXClient *client, const sp<MetaData> &data);
OMXClient *client, const sp<MetaData> &data,
bool createEncoder = false);
virtual ~OMXDecoder();
@@ -68,10 +68,22 @@ private:
};
enum PortStatus {
kPortStatusActive = 0,
kPortStatusDisabled = 1,
kPortStatusShutdown = 2,
kPortStatusFlushing = 3
kPortStatusActive = 0,
kPortStatusDisabled = 1,
kPortStatusShutdown = 2,
kPortStatusFlushing = 3,
kPortStatusFlushingToDisabled = 4,
kPortStatusFlushingToShutdown = 5,
};
enum Quirks {
kWantsRawNALFrames = 1,
kDoesntReturnBuffersOnDisable = 2,
kDoesntFlushOnExecutingToIdle = 4,
kDoesntProperlyFlushAllPortsAtOnce = 8,
kRequiresAllocateBufferOnInputPorts = 16,
kRequiresAllocateBufferOnOutputPorts = 32,
kRequiresLoadedToIdleAfterAllocation = 64
};
OMXClient *mClient;
@@ -79,6 +91,8 @@ private:
IOMX::node_id mNode;
char *mComponentName;
bool mIsMP3;
bool mIsAVC;
uint32_t mQuirks;
MediaSource *mSource;
sp<MetaData> mOutputFormat;
@@ -116,7 +130,8 @@ private:
bool mReachedEndOfInput;
OMXDecoder(OMXClient *client, IOMX::node_id node,
const char *mime, const char *codec);
const char *mime, const char *codec,
uint32_t quirks);
void setPortStatus(OMX_U32 port_index, PortStatus status);
PortStatus getPortStatus(OMX_U32 port_index) const;
@@ -125,7 +140,13 @@ private:
void setAMRFormat();
void setAACFormat();
void setVideoOutputFormat(OMX_U32 width, OMX_U32 height);
status_t setVideoPortFormatType(
OMX_U32 portIndex,
OMX_VIDEO_CODINGTYPE compressionFormat,
OMX_COLOR_FORMATTYPE colorFormat);
void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
void setup();
void dumpPortDefinition(OMX_U32 port_index);
@@ -144,6 +165,7 @@ private:
void freeInputBuffer(IOMX::buffer_id buffer);
void freeOutputBuffer(IOMX::buffer_id buffer);
void freePortBuffers(OMX_U32 port_index);
void postStart();
void postEmptyBufferDone(IOMX::buffer_id buffer);

View File

@@ -0,0 +1,58 @@
/*
* 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 TI_HARDWARE_RENDERER_H_
#define TI_HARDWARE_RENDERER_H_
#include <media/stagefright/VideoRenderer.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
namespace android {
class ISurface;
class Overlay;
class TIHardwareRenderer : public VideoRenderer {
public:
TIHardwareRenderer(
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
virtual ~TIHardwareRenderer();
virtual void render(
const void *data, size_t size, void *platformPrivate);
private:
sp<ISurface> mISurface;
size_t mDisplayWidth, mDisplayHeight;
size_t mDecodedWidth, mDecodedHeight;
size_t mFrameSize;
sp<Overlay> mOverlay;
Vector<void *> mOverlayAddresses;
size_t mIndex;
TIHardwareRenderer(const TIHardwareRenderer &);
TIHardwareRenderer &operator=(const TIHardwareRenderer &);
};
} // namespace android
#endif // TI_HARDWARE_RENDERER_H_

View File

@@ -59,6 +59,8 @@
#include <media/PVPlayer.h>
#include "TestPlayerStub.h"
//#undef USE_STAGEFRIGHT
#if USE_STAGEFRIGHT
#include "StagefrightPlayer.h"
#endif

View File

@@ -26,6 +26,7 @@ LOCAL_SRC_FILES:= \
SurfaceRenderer.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
TIHardwareRenderer.cpp \
Utils.cpp \
AudioPlayer.cpp \
ESDS.cpp \

View File

@@ -87,7 +87,10 @@ void AudioPlayer::start() {
} else {
mAudioTrack = new AudioTrack(
AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
numChannels, 8192, 0, &AudioCallback, this, 0);
(numChannels == 2)
? AudioSystem::CHANNEL_OUT_STEREO
: AudioSystem::CHANNEL_OUT_MONO,
8192, 0, &AudioCallback, this, 0);
assert(mAudioTrack->initCheck() == OK);
@@ -217,8 +220,10 @@ void AudioPlayer::fillBuffer(void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
mPositionTimeRealUs =
((mNumFramesPlayed + size_done / 4) * 1000000) / mSampleRate; // XXX
((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
/ mSampleRate;
}
if (mInputBuffer->range_length() == 0) {

View File

@@ -73,8 +73,6 @@ static bool get_mp3_frame_size(
if (bitrate_index == 0 || bitrate_index == 0x0f) {
// Disallow "free" bitrate.
LOGE("We disallow 'free' bitrate for now.");
return false;
}

View File

@@ -73,6 +73,8 @@ private:
bool mNeedsNALFraming;
uint8_t *mSrcBuffer;
MPEG4Source(const MPEG4Source &);
MPEG4Source &operator=(const MPEG4Source &);
};
@@ -743,7 +745,8 @@ MPEG4Source::MPEG4Source(
mBuffer(NULL),
mBufferOffset(0),
mBufferSizeRemaining(0),
mNeedsNALFraming(false) {
mNeedsNALFraming(false),
mSrcBuffer(NULL) {
const char *mime;
bool success = mFormat->findCString(kKeyMIMEType, &mime);
assert(success);
@@ -777,8 +780,13 @@ status_t MPEG4Source::start(MetaData *params) {
status_t err = mSampleTable->getMaxSampleSize(&max_size);
assert(err == OK);
// Add padding for de-framing of AVC content just in case.
mGroup->add_buffer(new MediaBuffer(max_size + 2));
// Assume that a given buffer only contains at most 10 fragments,
// each fragment originally prefixed with a 2 byte length will
// have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
// and thus will grow by 2 bytes per fragment.
mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
mSrcBuffer = new uint8_t[max_size];
mStarted = true;
@@ -793,6 +801,9 @@ status_t MPEG4Source::stop() {
mBuffer = NULL;
}
delete[] mSrcBuffer;
mSrcBuffer = NULL;
delete mGroup;
mGroup = NULL;
@@ -832,33 +843,31 @@ status_t MPEG4Source::read(
// fall through
}
if (mBuffer == NULL) {
off_t offset;
size_t size;
status_t err = mSampleTable->getSampleOffsetAndSize(
mCurrentSampleIndex, &offset, &size);
off_t offset;
size_t size;
status_t err = mSampleTable->getSampleOffsetAndSize(
mCurrentSampleIndex, &offset, &size);
if (err != OK) {
return err;
}
if (err != OK) {
return err;
}
uint32_t dts;
err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
uint32_t dts;
err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
if (err != OK) {
return err;
}
if (err != OK) {
return err;
}
err = mGroup->acquire_buffer(&mBuffer);
if (err != OK) {
assert(mBuffer == NULL);
return err;
}
assert(mBuffer->size() + 2 >= size);
err = mGroup->acquire_buffer(&mBuffer);
if (err != OK) {
assert(mBuffer == NULL);
return err;
}
if (!mIsAVC || !mNeedsNALFraming) {
ssize_t num_bytes_read =
mDataSource->read_at(offset, (uint8_t *)mBuffer->data() + 2, size);
mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
@@ -867,50 +876,62 @@ status_t MPEG4Source::read(
return err;
}
mBuffer->set_range(2, size);
mBuffer->set_range(0, size);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
++mCurrentSampleIndex;
mBufferOffset = 2;
mBufferSizeRemaining = size;
}
if (!mIsAVC) {
*out = mBuffer;
mBuffer = NULL;
return OK;
}
uint8_t *data = (uint8_t *)mBuffer->data() + mBufferOffset;
assert(mBufferSizeRemaining >= 2);
ssize_t num_bytes_read =
mDataSource->read_at(offset, mSrcBuffer, size);
size_t nal_length = (data[0] << 8) | data[1];
assert(mBufferSizeRemaining >= 2 + nal_length);
if (mNeedsNALFraming) {
// Insert marker.
data[-2] = data[-1] = data[0] = 0;
data[1] = 1;
mBuffer->set_range(mBufferOffset - 2, nal_length + 4);
} else {
mBuffer->set_range(mBufferOffset + 2, nal_length);
}
mBufferOffset += nal_length + 2;
mBufferSizeRemaining -= nal_length + 2;
if (mBufferSizeRemaining > 0) {
*out = mBuffer->clone();
} else {
*out = mBuffer;
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
mBuffer = NULL;
return err;
}
uint8_t *dstData = (uint8_t *)mBuffer->data();
size_t srcOffset = 0;
size_t dstOffset = 0;
while (srcOffset < size) {
assert(srcOffset + 1 < size);
size_t nalLength =
(mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
assert(srcOffset + 1 + nalLength < size);
srcOffset += 2;
if (nalLength == 0) {
continue;
}
assert(dstOffset + 4 <= mBuffer->size());
dstData[dstOffset++] = 0;
dstData[dstOffset++] = 0;
dstData[dstOffset++] = 0;
dstData[dstOffset++] = 1;
memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
srcOffset += nalLength;
dstOffset += nalLength;
}
mBuffer->set_range(0, dstOffset);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
++mCurrentSampleIndex;
*out = mBuffer;
mBuffer = NULL;
return OK;
}

View File

@@ -40,6 +40,7 @@
#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>
@@ -311,6 +312,9 @@ void MediaPlayerImpl::videoEntry() {
{
Mutex::Autolock autoLock(mLock);
mVideoPosition = pts_us;
LOGV("now_video = %.2f secs (%lld ms)",
pts_us / 1E6, (pts_us + 500) / 1000);
}
if (seeking && mAudioPlayer != NULL) {
@@ -344,6 +348,7 @@ void MediaPlayerImpl::displayOrDiscardFrame(
if (mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
mTimeSourceDeltaUs = realtime_us - mediatime_us;
LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
}
int64_t now_us = mTimeSource->getRealTimeUs();
@@ -436,6 +441,7 @@ void MediaPlayerImpl::init() {
}
void MediaPlayerImpl::setAudioSource(MediaSource *source) {
LOGI("setAudioSource");
mAudioSource = source;
sp<MetaData> meta = source->getFormat();
@@ -646,17 +652,28 @@ void MediaPlayerImpl::populateISurface() {
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
assert(success);
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
if (mSurface.get() != NULL) {
LOGW("Using SurfaceRenderer.");
mRenderer =
new SurfaceRenderer(
mSurface, mVideoWidth, mVideoHeight,
decodedWidth, decodedHeight);
} else if (format == OMX_COLOR_FormatYUV420Planar
&& !strncasecmp(component, "OMX.qcom.video.decoder.", 23)) {
} 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(

View File

@@ -20,6 +20,7 @@
#undef NDEBUG
#include <assert.h>
#include <ctype.h>
#include <OMX_Component.h>
@@ -54,14 +55,20 @@ struct CodecInfo {
};
static const CodecInfo kDecoderInfo[] = {
{ "audio/mpeg", "OMX.TI.MP3.decode" },
{ "audio/mpeg", "OMX.PV.mp3dec" },
{ "audio/3gpp", "OMX.TI.AMR.decode" },
{ "audio/3gpp", "OMX.PV.amrdec" },
{ "audio/mp4a-latm", "OMX.TI.AAC.decode" },
{ "audio/mp4a-latm", "OMX.PV.aacdec" },
{ "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
{ "video/mp4v-es", "OMX.TI.Video.Decoder" },
{ "video/mp4v-es", "OMX.PV.mpeg4dec" },
{ "video/3gpp", "OMX.qcom.video.decoder.h263" },
{ "video/3gpp", "OMX.TI.Video.Decoder" },
{ "video/3gpp", "OMX.PV.h263dec" },
{ "video/avc", "OMX.qcom.video.decoder.avc" },
{ "video/avc", "OMX.TI.Video.Decoder" },
{ "video/avc", "OMX.PV.avcdec" },
};
@@ -92,7 +99,9 @@ static const char *GetCodec(const CodecInfo *info, size_t numInfos,
}
// static
OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
OMXDecoder *OMXDecoder::Create(
OMXClient *client, const sp<MetaData> &meta,
bool createEncoder) {
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
assert(success);
@@ -102,9 +111,15 @@ OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
const char *codec = NULL;
IOMX::node_id node = 0;
for (int index = 0;; ++index) {
codec = GetCodec(
kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
mime, index);
if (createEncoder) {
codec = GetCodec(
kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
mime, index);
} else {
codec = GetCodec(
kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
mime, index);
}
if (!codec) {
return NULL;
@@ -118,7 +133,29 @@ OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
}
}
OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec);
uint32_t quirks = 0;
if (!strcmp(codec, "OMX.PV.avcdec")) {
quirks |= kWantsRawNALFrames;
}
if (!strcmp(codec, "OMX.TI.AAC.decode")
|| !strcmp(codec, "OMX.TI.MP3.decode")) {
quirks |= kDoesntReturnBuffersOnDisable;
}
if (!strcmp(codec, "OMX.TI.AAC.decode")) {
quirks |= kDoesntFlushOnExecutingToIdle;
quirks |= kDoesntProperlyFlushAllPortsAtOnce;
}
if (!strncmp(codec, "OMX.qcom.video.encoder.", 23)) {
quirks |= kRequiresAllocateBufferOnInputPorts;
}
if (!strncmp(codec, "OMX.qcom.video.decoder.", 23)) {
quirks |= kRequiresAllocateBufferOnOutputPorts;
}
if (!strncmp(codec, "OMX.qcom.video.", 15)) {
quirks |= kRequiresLoadedToIdleAfterAllocation;
}
OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
uint32_t type;
const void *data;
@@ -169,52 +206,22 @@ OMXDecoder *OMXDecoder::Create(OMXClient *client, const sp<MetaData> &meta) {
return decoder;
}
// static
OMXDecoder *OMXDecoder::CreateEncoder(
OMXClient *client, const sp<MetaData> &meta) {
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
assert(success);
sp<IOMX> omx = client->interface();
const char *codec = NULL;
IOMX::node_id node = 0;
for (int index = 0;; ++index) {
codec = GetCodec(
kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
mime, index);
if (!codec) {
return NULL;
}
LOGI("Attempting to allocate OMX node '%s'", codec);
status_t err = omx->allocate_node(codec, &node);
if (err == OK) {
break;
}
}
OMXDecoder *encoder = new OMXDecoder(client, node, mime, codec);
return encoder;
}
OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
const char *mime, const char *codec)
const char *mime, const char *codec,
uint32_t quirks)
: mClient(client),
mOMX(mClient->interface()),
mNode(node),
mComponentName(strdup(codec)),
mIsMP3(!strcasecmp(mime, "audio/mpeg")),
mIsAVC(!strcasecmp(mime, "video/avc")),
mQuirks(quirks),
mSource(NULL),
mCodecSpecificDataIterator(mCodecSpecificData.begin()),
mState(OMX_StateLoaded),
mPortStatusMask(kPortStatusActive << 2 | kPortStatusActive),
mShutdownInitiated(false),
mDealer(new MemoryDealer(3 * 1024 * 1024)),
mDealer(new MemoryDealer(5 * 1024 * 1024)),
mSeeking(false),
mStarted(false),
mErrorCondition(OK),
@@ -261,7 +268,7 @@ status_t OMXDecoder::start(MetaData *) {
// mDealer->dump("Decoder Dealer");
sp<MetaData> params = new MetaData;
if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
params->setInt32(kKeyNeedsNALFraming, true);
}
@@ -297,7 +304,7 @@ status_t OMXDecoder::stop() {
}
int attempt = 1;
while (mState != OMX_StateLoaded && attempt < 10) {
while (mState != OMX_StateLoaded && attempt < 20) {
usleep(100000);
++attempt;
@@ -366,7 +373,11 @@ status_t OMXDecoder::read(
mOutputBuffers.erase(mOutputBuffers.begin());
}
status_t err = mOMX->send_command(mNode, OMX_CommandFlush, -1);
// XXX One of TI's decoders appears to ignore a flush if it doesn't
// currently hold on to any buffers on the port in question and
// never sends the completion event... FIXME
status_t err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
assert(err == OK);
// Once flushing is completed buffers will again be scheduled to be
@@ -472,9 +483,121 @@ void OMXDecoder::setAACFormat() {
assert(err == NO_ERROR);
}
void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
status_t OMXDecoder::setVideoPortFormatType(
OMX_U32 portIndex,
OMX_VIDEO_CODINGTYPE compressionFormat,
OMX_COLOR_FORMATTYPE colorFormat) {
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
format.nSize = sizeof(format);
format.nVersion.s.nVersionMajor = 1;
format.nVersion.s.nVersionMinor = 1;
format.nPortIndex = portIndex;
format.nIndex = 0;
bool found = false;
OMX_U32 index = 0;
for (;;) {
format.nIndex = index;
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
if (err != OK) {
return err;
}
// The following assertion is violated by TI's video decoder.
// assert(format.nIndex == index);
if (format.eCompressionFormat == compressionFormat
&& format.eColorFormat == colorFormat) {
found = true;
break;
}
++index;
}
if (!found) {
return UNKNOWN_ERROR;
}
status_t err = mOMX->set_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
return err;
}
#if 1
void OMXDecoder::setVideoOutputFormat(
const char *mime, OMX_U32 width, OMX_U32 height) {
LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
#if 1
// Enabling this code appears to be the right thing(tm), but,...
// the TI decoder then loses the ability to output YUV420 and only outputs
// YCbYCr (16bit)
if (!strcasecmp("video/avc", mime)) {
OMX_PARAM_COMPONENTROLETYPE role;
role.nSize = sizeof(role);
role.nVersion.s.nVersionMajor = 1;
role.nVersion.s.nVersionMinor = 1;
strncpy((char *)role.cRole, "video_decoder.avc",
OMX_MAX_STRINGNAME_SIZE - 1);
role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
status_t err = mOMX->set_parameter(
mNode, OMX_IndexParamStandardComponentRole,
&role, sizeof(role));
assert(err == OK);
}
#endif
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
if (!strcasecmp("video/avc", mime)) {
compressionFormat = OMX_VIDEO_CodingAVC;
} else if (!strcasecmp("video/mp4v-es", mime)) {
compressionFormat = OMX_VIDEO_CodingMPEG4;
} else if (!strcasecmp("video/3gpp", mime)) {
compressionFormat = OMX_VIDEO_CodingH263;
} else {
assert(!"Should not be here. Not a supported video mime type.");
}
setVideoPortFormatType(
kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
#if 1
{
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
format.nSize = sizeof(format);
format.nVersion.s.nVersionMajor = 1;
format.nVersion.s.nVersionMinor = 1;
format.nPortIndex = kPortIndexOutput;
format.nIndex = 0;
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
assert(err == OK);
assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
|| format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
|| format.eColorFormat == OMX_COLOR_FormatCbYCrY
|| format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
err = mOMX->set_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
assert(err == OK);
}
#endif
OMX_PARAM_PORTDEFINITIONTYPE def;
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
@@ -502,7 +625,7 @@ void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
// video_def.eCompressionFormat = OMX_VIDEO_CodingAVC;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
err = mOMX->set_parameter(
@@ -522,21 +645,189 @@ void OMXDecoder::setVideoOutputFormat(OMX_U32 width, OMX_U32 height) {
assert(def.eDomain == OMX_PortDomainVideo);
#if 0
def.nBufferSize =
(((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
#endif
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
video_def->nStride = width;
// video_def->nSliceHeight = height;
video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
// video_def->eColorFormat = OMX_COLOR_FormatYUV420Planar;
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == NO_ERROR);
}
#else
static void hexdump(const void *_data, size_t size) {
char line[256];
char tmp[16];
const uint8_t *data = (const uint8_t *)_data;
size_t offset = 0;
while (offset < size) {
sprintf(line, "0x%04x ", offset);
size_t n = size - offset;
if (n > 16) {
n = 16;
}
for (size_t i = 0; i < 16; ++i) {
if (i == 8) {
strcat(line, " ");
}
if (offset + i < size) {
sprintf(tmp, "%02x ", data[offset + i]);
strcat(line, tmp);
} else {
strcat(line, " ");
}
}
strcat(line, " ");
for (size_t i = 0; i < n; ++i) {
if (isprint(data[offset + i])) {
sprintf(tmp, "%c", data[offset + i]);
strcat(line, tmp);
} else {
strcat(line, ".");
}
}
LOGI(line);
offset += 16;
}
}
static void DumpPortDefinitionType(const void *_param) {
OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;
LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);
if (param->eDomain == OMX_PortDomainVideo) {
OMX_VIDEO_PORTDEFINITIONTYPE *video = &param->format.video;
LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
} else {
hexdump(param, param->nSize);
}
}
void OMXDecoder::setVideoOutputFormat(
const char *mime, OMX_U32 width, OMX_U32 height) {
LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
#if 0
// Enabling this code appears to be the right thing(tm), but,...
// the decoder then loses the ability to output YUV420 and only outputs
// YCbYCr (16bit)
{
OMX_PARAM_COMPONENTROLETYPE role;
role.nSize = sizeof(role);
role.nVersion.s.nVersionMajor = 1;
role.nVersion.s.nVersionMinor = 1;
strncpy((char *)role.cRole, "video_decoder.avc",
OMX_MAX_STRINGNAME_SIZE - 1);
role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
status_t err = mOMX->set_parameter(
mNode, OMX_IndexParamStandardComponentRole,
&role, sizeof(role));
assert(err == OK);
}
#endif
setVideoPortFormatType(
kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
#if 1
{
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
format.nSize = sizeof(format);
format.nVersion.s.nVersionMajor = 1;
format.nVersion.s.nVersionMinor = 1;
format.nPortIndex = kPortIndexOutput;
format.nIndex = 0;
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
assert(err == OK);
LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
hexdump(&format, format.nSize);
assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);
assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
|| format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
|| format.eColorFormat == OMX_COLOR_FormatCbYCrY);
err = mOMX->set_parameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
assert(err == OK);
}
#endif
OMX_PORT_PARAM_TYPE ptype;
ptype.nSize = sizeof(ptype);
ptype.nVersion.s.nVersionMajor = 1;
ptype.nVersion.s.nVersionMinor = 1;
status_t err = mOMX->get_parameter(
mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
assert(err == OK);
LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
hexdump(&ptype, ptype.nSize);
OMX_PARAM_PORTDEFINITIONTYPE def;
def.nSize = sizeof(def);
def.nVersion.s.nVersionMajor = 1;
def.nVersion.s.nVersionMinor = 1;
def.nPortIndex = kPortIndexInput;
err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == OK);
LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
DumpPortDefinitionType(&def);
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == OK);
////////////////////////////////////////////////////////////////////////////
def.nPortIndex = kPortIndexOutput;
err = mOMX->get_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == OK);
LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
DumpPortDefinitionType(&def);
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
err = mOMX->set_parameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
assert(err == OK);
}
#endif
void OMXDecoder::setup() {
const sp<MetaData> &meta = mSource->getFormat();
@@ -554,7 +845,7 @@ void OMXDecoder::setup() {
success = success && meta->findInt32(kKeyHeight, &height);
assert(success);
setVideoOutputFormat(width, height);
setVideoOutputFormat(mime, width, height);
}
// dumpPortDefinition(0);
@@ -644,10 +935,7 @@ void OMXDecoder::setup() {
}
void OMXDecoder::onStart() {
bool needs_qcom_hack =
!strncmp(mComponentName, "OMX.qcom.video.", 15);
if (!needs_qcom_hack) {
if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
status_t err =
mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
assert(err == NO_ERROR);
@@ -656,7 +944,7 @@ void OMXDecoder::onStart() {
allocateBuffers(kPortIndexInput);
allocateBuffers(kPortIndexOutput);
if (needs_qcom_hack) {
if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
// XXX this should happen before AllocateBuffers, but qcom's
// h264 vdec disagrees.
status_t err =
@@ -691,13 +979,17 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) {
for (OMX_U32 i = 0; i < num_buffers; ++i) {
sp<IMemory> mem = mDealer->allocate(buffer_size);
if (mem.get() == NULL) {
LOGE("[%s] allocating IMemory of size %ld FAILED.",
mComponentName, buffer_size);
}
assert(mem.get() != NULL);
IOMX::buffer_id buffer;
status_t err;
if (port_index == kPortIndexInput
&& !strncmp(mComponentName, "OMX.qcom.video.encoder.", 23)) {
&& (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
// qcom's H.263 encoder appears to want to allocate its own input
// buffers.
err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
@@ -706,7 +998,7 @@ void OMXDecoder::allocateBuffers(OMX_U32 port_index) {
mComponentName, err);
}
} else if (port_index == kPortIndexOutput
&& !strncmp(mComponentName, "OMX.qcom.video.decoder.", 23)) {
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
#if 1
err = mOMX->allocate_buffer_with_backup(mNode, port_index, mem, &buffer);
#else
@@ -817,18 +1109,59 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) {
case OMX_CommandFlush: {
OMX_U32 port_index = data;
LOGV("Port %ld flush complete.", port_index);
assert(getPortStatus(port_index) == kPortStatusFlushing);
setPortStatus(port_index, kPortStatusActive);
BufferList *buffers = &mBuffers.editItemAt(port_index);
while (!buffers->empty()) {
IOMX::buffer_id buffer = *buffers->begin();
buffers->erase(buffers->begin());
PortStatus status = getPortStatus(port_index);
if (port_index == kPortIndexInput) {
postEmptyBufferDone(buffer);
} else {
postInitialFillBuffer(buffer);
assert(status == kPortStatusFlushing
|| status == kPortStatusFlushingToDisabled
|| status == kPortStatusFlushingToShutdown);
switch (status) {
case kPortStatusFlushing:
{
// This happens when we're flushing before a seek.
setPortStatus(port_index, kPortStatusActive);
BufferList *buffers = &mBuffers.editItemAt(port_index);
while (!buffers->empty()) {
IOMX::buffer_id buffer = *buffers->begin();
buffers->erase(buffers->begin());
if (port_index == kPortIndexInput) {
postEmptyBufferDone(buffer);
} else {
postInitialFillBuffer(buffer);
}
}
break;
}
case kPortStatusFlushingToDisabled:
{
// Port settings have changed and the (buggy) OMX component
// does not properly return buffers on disabling, we need to
// do a flush first and _then_ disable the port in question.
setPortStatus(port_index, kPortStatusDisabled);
status_t err = mOMX->send_command(
mNode, OMX_CommandPortDisable, port_index);
assert(err == OK);
freePortBuffers(port_index);
break;
}
default:
{
assert(status == kPortStatusFlushingToShutdown);
setPortStatus(port_index, kPortStatusShutdown);
if (getPortStatus(kPortIndexInput) == kPortStatusShutdown
&& getPortStatus(kPortIndexOutput) == kPortStatusShutdown) {
status_t err = mOMX->send_command(
mNode, OMX_CommandStateSet, OMX_StateIdle);
assert(err == OK);
}
break;
}
}
break;
@@ -841,10 +1174,22 @@ void OMXDecoder::onEventCmdComplete(OMX_COMMANDTYPE type, OMX_U32 data) {
void OMXDecoder::onEventPortSettingsChanged(OMX_U32 port_index) {
assert(getPortStatus(port_index) == kPortStatusActive);
setPortStatus(port_index, kPortStatusDisabled);
status_t err =
mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
status_t err;
if (mQuirks & kDoesntReturnBuffersOnDisable) {
// Decoder does not properly return our buffers when disabled...
// Need to flush port instead and _then_ disable.
setPortStatus(port_index, kPortStatusFlushingToDisabled);
err = mOMX->send_command(mNode, OMX_CommandFlush, port_index);
} else {
setPortStatus(port_index, kPortStatusDisabled);
err = mOMX->send_command(mNode, OMX_CommandPortDisable, port_index);
}
assert(err == NO_ERROR);
}
@@ -894,19 +1239,8 @@ void OMXDecoder::onStateChanged(OMX_STATETYPE to) {
mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateLoaded);
assert(err == NO_ERROR);
BufferList *ibuffers = &mBuffers.editItemAt(kPortIndexInput);
for (BufferList::iterator it = ibuffers->begin();
it != ibuffers->end(); ++it) {
freeInputBuffer(*it);
}
ibuffers->clear();
BufferList *obuffers = &mBuffers.editItemAt(kPortIndexOutput);
for (BufferList::iterator it = obuffers->begin();
it != obuffers->end(); ++it) {
freeOutputBuffer(*it);
}
obuffers->clear();
freePortBuffers(kPortIndexInput);
freePortBuffers(kPortIndexOutput);
}
}
@@ -925,26 +1259,41 @@ void OMXDecoder::initiateShutdown() {
mShutdownInitiated = true;
status_t err =
mClient->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
assert(err == NO_ERROR);
status_t err;
if (mQuirks & kDoesntFlushOnExecutingToIdle) {
if (mQuirks & kDoesntProperlyFlushAllPortsAtOnce) {
err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexInput);
assert(err == OK);
setPortStatus(kPortIndexInput, kPortStatusShutdown);
setPortStatus(kPortIndexOutput, kPortStatusShutdown);
err = mOMX->send_command(mNode, OMX_CommandFlush, kPortIndexOutput);
} else {
err = mOMX->send_command(mNode, OMX_CommandFlush, OMX_ALL);
}
setPortStatus(kPortIndexInput, kPortStatusFlushingToShutdown);
setPortStatus(kPortIndexOutput, kPortStatusFlushingToShutdown);
} else {
err = mClient->send_command(
mNode, OMX_CommandStateSet, OMX_StateIdle);
setPortStatus(kPortIndexInput, kPortStatusShutdown);
setPortStatus(kPortIndexOutput, kPortStatusShutdown);
}
assert(err == OK);
}
void OMXDecoder::setPortStatus(OMX_U32 port_index, PortStatus status) {
int shift = 2 * port_index;
int shift = 3 * port_index;
mPortStatusMask &= ~(3 << shift);
mPortStatusMask &= ~(7 << shift);
mPortStatusMask |= status << shift;
}
OMXDecoder::PortStatus OMXDecoder::getPortStatus(
OMX_U32 port_index) const {
int shift = 2 * port_index;
int shift = 3 * port_index;
return static_cast<PortStatus>((mPortStatusMask >> shift) & 3);
return static_cast<PortStatus>((mPortStatusMask >> shift) & 7);
}
void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
@@ -964,6 +1313,8 @@ void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
break;
case kPortStatusFlushing:
case kPortStatusFlushingToDisabled:
case kPortStatusFlushingToShutdown:
LOGV("We're currently flushing, enqueue INPUT buffer %p.", buffer);
mBuffers.editItemAt(kPortIndexInput).push_back(buffer);
err = NO_ERROR;
@@ -980,7 +1331,9 @@ void OMXDecoder::onEmptyBufferDone(IOMX::buffer_id buffer) {
void OMXDecoder::onFillBufferDone(const omx_message &msg) {
IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
LOGV("[%s] onFillBufferDone (%p)", mComponentName, buffer);
LOGV("[%s] on%sFillBufferDone (%p, size:%ld)", mComponentName,
msg.type == omx_message::INITIAL_FILL_BUFFER ? "Initial" : "",
buffer, msg.u.extended_buffer_data.range_length);
status_t err;
switch (getPortStatus(kPortIndexOutput)) {
@@ -995,6 +1348,8 @@ void OMXDecoder::onFillBufferDone(const omx_message &msg) {
break;
case kPortStatusFlushing:
case kPortStatusFlushingToDisabled:
case kPortStatusFlushingToShutdown:
LOGV("We're currently flushing, enqueue OUTPUT buffer %p.", buffer);
mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
err = NO_ERROR;
@@ -1035,7 +1390,7 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) {
size_t range_length = 0;
if (!strcmp(mComponentName, "OMX.qcom.video.decoder.avc")) {
if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) {
assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
memcpy(mem->pointer(), kNALStartCode, 4);
@@ -1142,15 +1497,14 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) {
OMX_TICKS timestamp = 0;
if (success) {
// XXX units should be microseconds but PV treats them as milliseconds.
timestamp = ((OMX_S64)units * 1000) / scale;
timestamp = ((OMX_S64)units * 1000000) / scale;
}
input_buffer->release();
input_buffer = NULL;
LOGV("[%s] Calling EmptyBuffer on buffer %p",
mComponentName, buffer);
LOGV("[%s] Calling EmptyBuffer on buffer %p size:%d flags:0x%08lx",
mComponentName, buffer, src_length, flags);
status_t err2 = mClient->emptyBuffer(
mNode, buffer, 0, src_length, flags, timestamp);
@@ -1170,7 +1524,8 @@ void OMXDecoder::onRealFillBufferDone(const omx_message &msg) {
media_buffer->meta_data()->clear();
media_buffer->meta_data()->setInt32(
kKeyTimeUnits, msg.u.extended_buffer_data.timestamp);
kKeyTimeUnits,
(msg.u.extended_buffer_data.timestamp + 500) / 1000);
media_buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
@@ -1198,7 +1553,9 @@ void OMXDecoder::signalBufferReturned(MediaBuffer *_buffer) {
PortStatus outputStatus = getPortStatus(kPortIndexOutput);
if (outputStatus == kPortStatusShutdown
|| outputStatus == kPortStatusFlushing) {
|| outputStatus == kPortStatusFlushing
|| outputStatus == kPortStatusFlushingToDisabled
|| outputStatus == kPortStatusFlushingToShutdown) {
mBuffers.editItemAt(kPortIndexOutput).push_back(buffer);
} else {
LOGV("[%s] Calling FillBuffer on buffer %p.", mComponentName, buffer);
@@ -1326,4 +1683,18 @@ void OMXDecoder::postInitialFillBuffer(IOMX::buffer_id buffer) {
postMessage(msg);
}
void OMXDecoder::freePortBuffers(OMX_U32 port_index) {
BufferList *buffers = &mBuffers.editItemAt(port_index);
while (!buffers->empty()) {
IOMX::buffer_id buffer = *buffers->begin();
buffers->erase(buffers->begin());
if (port_index == kPortIndexInput) {
freeInputBuffer(buffer);
} else {
freeOutputBuffer(buffer);
}
}
}
} // namespace android

View File

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