am eb6e3edc: Merge "Coalesce multiple encoded AAC frames into a single input buffer on this particular OMX codec to increase throughput significantly." into froyo

Merge commit 'eb6e3edc0f21c5c8a574f8086f9622c44c0ff866' into froyo-plus-aosp

* commit 'eb6e3edc0f21c5c8a574f8086f9622c44c0ff866':
  Coalesce multiple encoded AAC frames into a single input buffer on this particular OMX codec to increase throughput significantly.
This commit is contained in:
Andreas Huber
2010-04-02 14:09:11 -07:00
committed by Android Git Automerger
3 changed files with 142 additions and 61 deletions

View File

@ -158,6 +158,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
MediaSource::ReadOptions options; MediaSource::ReadOptions options;
int64_t sumDecodeUs = 0; int64_t sumDecodeUs = 0;
int64_t totalBytes = 0;
while (numIterationsLeft-- > 0) { while (numIterationsLeft-- > 0) {
long numFrames = 0; long numFrames = 0;
@ -188,6 +189,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
} }
sumDecodeUs += delayDecodeUs; sumDecodeUs += delayDecodeUs;
totalBytes += buffer->range_length();
buffer->release(); buffer->release();
buffer = NULL; buffer = NULL;
@ -216,11 +218,20 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
printf("\n"); printf("\n");
int64_t delay = getNowUs() - startTime; int64_t delay = getNowUs() - startTime;
printf("avg. %.2f fps\n", n * 1E6 / delay); if (!strncasecmp("video/", mime, 6)) {
printf("avg. time to decode one buffer %.2f usecs\n", printf("avg. %.2f fps\n", n * 1E6 / delay);
(double)sumDecodeUs / n);
printf("decoded a total of %d frame(s).\n", n); printf("avg. time to decode one buffer %.2f usecs\n",
(double)sumDecodeUs / n);
printf("decoded a total of %d frame(s).\n", n);
} else if (!strncasecmp("audio/", mime, 6)) {
// Frame count makes less sense for audio, as the output buffer
// sizes may be different across decoders.
printf("avg. %.2f KB/sec\n", totalBytes / 1024 * 1E6 / delay);
printf("decoded a total of %lld bytes\n", totalBytes);
}
} }
static void usage(const char *me) { static void usage(const char *me) {

View File

@ -87,16 +87,17 @@ private:
}; };
enum Quirks { enum Quirks {
kNeedsFlushBeforeDisable = 1, kNeedsFlushBeforeDisable = 1,
kWantsNALFragments = 2, kWantsNALFragments = 2,
kRequiresLoadedToIdleAfterAllocation = 4, kRequiresLoadedToIdleAfterAllocation = 4,
kRequiresAllocateBufferOnInputPorts = 8, kRequiresAllocateBufferOnInputPorts = 8,
kRequiresFlushCompleteEmulation = 16, kRequiresFlushCompleteEmulation = 16,
kRequiresAllocateBufferOnOutputPorts = 32, kRequiresAllocateBufferOnOutputPorts = 32,
kRequiresFlushBeforeShutdown = 64, kRequiresFlushBeforeShutdown = 64,
kDefersOutputBufferAllocation = 128, kDefersOutputBufferAllocation = 128,
kDecoderLiesAboutNumberOfChannels = 256, kDecoderLiesAboutNumberOfChannels = 256,
kInputBufferSizesAreBogus = 512, kInputBufferSizesAreBogus = 512,
kSupportsMultipleFramesPerInputBuffer = 1024,
}; };
struct BufferInfo { struct BufferInfo {
@ -137,6 +138,8 @@ private:
bool mOutputPortSettingsHaveChanged; bool mOutputPortSettingsHaveChanged;
int64_t mSeekTimeUs; int64_t mSeekTimeUs;
MediaBuffer *mLeftOverBuffer;
Mutex mLock; Mutex mLock;
Condition mAsyncCompletion; Condition mAsyncCompletion;

View File

@ -103,6 +103,7 @@ static const CodecInfo kDecoderInfo[] = {
{ MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" }, { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" }, { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" }, // { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" }, { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" }, // { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
@ -284,6 +285,7 @@ uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
if (!strcmp(componentName, "OMX.TI.AAC.decode")) { if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
quirks |= kNeedsFlushBeforeDisable; quirks |= kNeedsFlushBeforeDisable;
quirks |= kRequiresFlushCompleteEmulation; quirks |= kRequiresFlushCompleteEmulation;
quirks |= kSupportsMultipleFramesPerInputBuffer;
} }
if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) { if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
quirks |= kRequiresLoadedToIdleAfterAllocation; quirks |= kRequiresLoadedToIdleAfterAllocation;
@ -533,7 +535,28 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
return err; return err;
} }
} }
} else if (!strncasecmp(mMIME, "audio/", 6)) {
if ((mQuirks & kSupportsMultipleFramesPerInputBuffer)
&& !strcmp(mComponentName, "OMX.TI.AAC.decode")) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = kPortIndexInput;
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
const size_t kMinBufferSize = 100 * 1024;
if (def.nBufferSize < kMinBufferSize) {
def.nBufferSize = kMinBufferSize;
}
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
}
} }
if (!strcasecmp(mMIME, MEDIA_MIMETYPE_IMAGE_JPEG) if (!strcasecmp(mMIME, MEDIA_MIMETYPE_IMAGE_JPEG)
&& !strcmp(mComponentName, "OMX.TI.JPEG.decode")) { && !strcmp(mComponentName, "OMX.TI.JPEG.decode")) {
OMX_COLOR_FORMATTYPE format = OMX_COLOR_FORMATTYPE format =
@ -1049,7 +1072,8 @@ OMXCodec::OMXCodec(
mSignalledEOS(false), mSignalledEOS(false),
mNoMoreOutputData(false), mNoMoreOutputData(false),
mOutputPortSettingsHaveChanged(false), mOutputPortSettingsHaveChanged(false),
mSeekTimeUs(-1) { mSeekTimeUs(-1),
mLeftOverBuffer(NULL) {
mPortStatus[kPortIndexInput] = ENABLED; mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED; mPortStatus[kPortIndexOutput] = ENABLED;
@ -1938,66 +1962,104 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
return; return;
} }
MediaBuffer *srcBuffer;
status_t err; status_t err;
if (mSeekTimeUs >= 0) {
MediaSource::ReadOptions options;
options.setSeekTo(mSeekTimeUs);
mSeekTimeUs = -1; bool signalEOS = false;
mBufferFilled.signal(); int64_t timestampUs = 0;
err = mSource->read(&srcBuffer, &options); size_t offset = 0;
} else { int32_t n = 0;
err = mSource->read(&srcBuffer); for (;;) {
MediaBuffer *srcBuffer;
if (mSeekTimeUs >= 0) {
if (mLeftOverBuffer) {
mLeftOverBuffer->release();
mLeftOverBuffer = NULL;
}
MediaSource::ReadOptions options;
options.setSeekTo(mSeekTimeUs);
mSeekTimeUs = -1;
mBufferFilled.signal();
err = mSource->read(&srcBuffer, &options);
} else if (mLeftOverBuffer) {
srcBuffer = mLeftOverBuffer;
mLeftOverBuffer = NULL;
err = OK;
} else {
err = mSource->read(&srcBuffer);
}
if (err != OK) {
signalEOS = true;
mFinalStatus = err;
mSignalledEOS = true;
break;
}
size_t remainingBytes = info->mSize - offset;
if (srcBuffer->range_length() > remainingBytes) {
if (offset == 0) {
CODEC_LOGE(
"Codec's input buffers are too small to accomodate "
"buffer read from source (info->mSize = %d, srcLength = %d)",
info->mSize, srcBuffer->range_length());
srcBuffer->release();
srcBuffer = NULL;
setState(ERROR);
return;
}
mLeftOverBuffer = srcBuffer;
break;
}
memcpy((uint8_t *)info->mData + offset,
(const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
srcBuffer->range_length());
if (offset == 0) {
CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs));
CHECK(timestampUs >= 0);
}
offset += srcBuffer->range_length();
srcBuffer->release();
srcBuffer = NULL;
++n;
if (!(mQuirks & kSupportsMultipleFramesPerInputBuffer)) {
break;
}
}
if (n > 1) {
LOGV("coalesced %d frames into one input buffer", n);
} }
OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME; OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
OMX_TICKS timestampUs = 0;
size_t srcLength = 0;
if (err != OK) { if (signalEOS) {
CODEC_LOGV("signalling end of input stream.");
flags |= OMX_BUFFERFLAG_EOS; flags |= OMX_BUFFERFLAG_EOS;
mFinalStatus = err;
mSignalledEOS = true;
} else { } else {
mNoMoreOutputData = false; mNoMoreOutputData = false;
srcLength = srcBuffer->range_length();
if (info->mSize < srcLength) {
CODEC_LOGE(
"Codec's input buffers are too small to accomodate "
"buffer read from source (info->mSize = %d, srcLength = %d)",
info->mSize, srcLength);
srcBuffer->release();
srcBuffer = NULL;
setState(ERROR);
return;
}
memcpy(info->mData,
(const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
srcLength);
if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d), "
"timestamp %lld us (%.2f secs)",
info->mBuffer, srcLength,
timestampUs, timestampUs / 1E6);
}
} }
if (srcBuffer != NULL) { CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d), "
srcBuffer->release(); "timestamp %lld us (%.2f secs)",
srcBuffer = NULL; info->mBuffer, offset,
} timestampUs, timestampUs / 1E6);
err = mOMX->emptyBuffer( err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, srcLength, mNode, info->mBuffer, 0, offset,
flags, timestampUs); flags, timestampUs);
if (err != OK) { if (err != OK) {
@ -2352,6 +2414,11 @@ status_t OMXCodec::stop() {
} }
} }
if (mLeftOverBuffer) {
mLeftOverBuffer->release();
mLeftOverBuffer = NULL;
}
mSource->stop(); mSource->stop();
CODEC_LOGV("stopped"); CODEC_LOGV("stopped");