Merge change 21948 into eclair

* changes:
  The PV AVC software decoder expects each fragment of a NAL unit to be handed to the decoder unframed.
This commit is contained in:
Android (Google) Code Review
2009-08-19 13:54:01 -07:00
7 changed files with 154 additions and 119 deletions

View File

@@ -70,6 +70,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
long numIterationsLeft = gNumRepetitions; long numIterationsLeft = gNumRepetitions;
MediaSource::ReadOptions options; MediaSource::ReadOptions options;
while (numIterationsLeft-- > 0) { while (numIterationsLeft-- > 0) {
MediaBuffer *buffer; MediaBuffer *buffer;

View File

@@ -38,7 +38,7 @@ enum {
kKeyAVCC = 'avcc', kKeyAVCC = 'avcc',
kKeyTimeUnits = '#tim', kKeyTimeUnits = '#tim',
kKeyTimeScale = 'scal', kKeyTimeScale = 'scal',
kKeyNeedsNALFraming = 'NALf', kKeyWantsNALFragments = 'NALf',
kKeyIsSyncFrame = 'sync', kKeyIsSyncFrame = 'sync',
kKeyDuration = 'dura', kKeyDuration = 'dura',
kKeyColorFormat = 'colf', kKeyColorFormat = 'colf',

View File

@@ -79,7 +79,7 @@ private:
enum Quirks { enum Quirks {
kNeedsFlushBeforeDisable = 1, kNeedsFlushBeforeDisable = 1,
kWantsRawNALFrames = 2, kWantsNALFragments = 2,
kRequiresLoadedToIdleAfterAllocation = 4, kRequiresLoadedToIdleAfterAllocation = 4,
kRequiresAllocateBufferOnInputPorts = 8, kRequiresAllocateBufferOnInputPorts = 8,
}; };

View File

@@ -76,7 +76,7 @@ private:
}; };
enum Quirks { enum Quirks {
kWantsRawNALFrames = 1, kWantsNALFragments = 1,
kDoesntReturnBuffersOnDisable = 2, kDoesntReturnBuffersOnDisable = 2,
kDoesntFlushOnExecutingToIdle = 4, kDoesntFlushOnExecutingToIdle = 4,
kDoesntProperlyFlushAllPortsAtOnce = 8, kDoesntProperlyFlushAllPortsAtOnce = 8,

View File

@@ -19,9 +19,6 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#undef NDEBUG
#include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@@ -31,6 +28,7 @@
#include <media/stagefright/MPEG4Extractor.h> #include <media/stagefright/MPEG4Extractor.h>
#include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaSource.h> #include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h> #include <media/stagefright/MetaData.h>
#include <media/stagefright/SampleTable.h> #include <media/stagefright/SampleTable.h>
@@ -70,10 +68,8 @@ private:
MediaBufferGroup *mGroup; MediaBufferGroup *mGroup;
MediaBuffer *mBuffer; MediaBuffer *mBuffer;
size_t mBufferOffset;
size_t mBufferSizeRemaining;
bool mNeedsNALFraming; bool mWantsNALFragments;
uint8_t *mSrcBuffer; uint8_t *mSrcBuffer;
@@ -138,7 +134,7 @@ static const char *const FourCC2MIME(uint32_t fourcc) {
return "video/avc"; return "video/avc";
default: default:
assert(!"should not be here."); CHECK(!"should not be here.");
return NULL; return NULL;
} }
} }
@@ -279,7 +275,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err; return err;
} }
} }
assert(*offset == stop_offset); CHECK_EQ(*offset, stop_offset);
if (chunk_type == FOURCC('m', 'o', 'o', 'v')) { if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
mHaveMetadata = true; mHaveMetadata = true;
@@ -291,7 +287,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
case FOURCC('t', 'k', 'h', 'd'): case FOURCC('t', 'k', 'h', 'd'):
{ {
assert(chunk_data_size >= 4); CHECK(chunk_data_size >= 4);
uint8_t version; uint8_t version;
if (mDataSource->read_at(data_offset, &version, 1) < 1) { if (mDataSource->read_at(data_offset, &version, 1) < 1) {
@@ -444,7 +440,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
} }
uint8_t buffer[8]; uint8_t buffer[8];
assert(chunk_data_size >= (off_t)sizeof(buffer)); CHECK(chunk_data_size >= (off_t)sizeof(buffer));
if (mDataSource->read_at( if (mDataSource->read_at(
data_offset, buffer, 8) < 8) { data_offset, buffer, 8) < 8) {
return ERROR_IO; return ERROR_IO;
@@ -470,7 +466,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err; return err;
} }
} }
assert(*offset == stop_offset); CHECK_EQ(*offset, stop_offset);
break; break;
} }
@@ -518,7 +514,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err; return err;
} }
} }
assert(*offset == stop_offset); CHECK_EQ(*offset, stop_offset);
break; break;
} }
@@ -560,7 +556,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err; return err;
} }
} }
assert(*offset == stop_offset); CHECK_EQ(*offset, stop_offset);
break; break;
} }
@@ -728,16 +724,14 @@ MPEG4Source::MPEG4Source(
mStarted(false), mStarted(false),
mGroup(NULL), mGroup(NULL),
mBuffer(NULL), mBuffer(NULL),
mBufferOffset(0), mWantsNALFragments(false),
mBufferSizeRemaining(0),
mNeedsNALFraming(false),
mSrcBuffer(NULL) { mSrcBuffer(NULL) {
const char *mime; const char *mime;
bool success = mFormat->findCString(kKeyMIMEType, &mime); bool success = mFormat->findCString(kKeyMIMEType, &mime);
assert(success); CHECK(success);
success = mFormat->findInt32(kKeyTimeScale, &mTimescale); success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
assert(success); CHECK(success);
mIsAVC = !strcasecmp(mime, "video/avc"); mIsAVC = !strcasecmp(mime, "video/avc");
} }
@@ -749,21 +743,21 @@ MPEG4Source::~MPEG4Source() {
} }
status_t MPEG4Source::start(MetaData *params) { status_t MPEG4Source::start(MetaData *params) {
assert(!mStarted); CHECK(!mStarted);
int32_t val; int32_t val;
if (mIsAVC && params && params->findInt32(kKeyNeedsNALFraming, &val) if (params && params->findInt32(kKeyWantsNALFragments, &val)
&& val != 0) { && val != 0) {
mNeedsNALFraming = true; mWantsNALFragments = true;
} else { } else {
mNeedsNALFraming = false; mWantsNALFragments = false;
} }
mGroup = new MediaBufferGroup; mGroup = new MediaBufferGroup;
size_t max_size; size_t max_size;
status_t err = mSampleTable->getMaxSampleSize(&max_size); status_t err = mSampleTable->getMaxSampleSize(&max_size);
assert(err == OK); CHECK_EQ(err, OK);
// Assume that a given buffer only contains at most 10 fragments, // Assume that a given buffer only contains at most 10 fragments,
// each fragment originally prefixed with a 2 byte length will // each fragment originally prefixed with a 2 byte length will
@@ -779,7 +773,7 @@ status_t MPEG4Source::start(MetaData *params) {
} }
status_t MPEG4Source::stop() { status_t MPEG4Source::stop() {
assert(mStarted); CHECK(mStarted);
if (mBuffer != NULL) { if (mBuffer != NULL) {
mBuffer->release(); mBuffer->release();
@@ -804,7 +798,7 @@ sp<MetaData> MPEG4Source::getFormat() {
status_t MPEG4Source::read( status_t MPEG4Source::read(
MediaBuffer **out, const ReadOptions *options) { MediaBuffer **out, const ReadOptions *options) {
assert(mStarted); CHECK(mStarted);
*out = NULL; *out = NULL;
@@ -830,6 +824,11 @@ status_t MPEG4Source::read(
off_t offset; off_t offset;
size_t size; size_t size;
uint32_t dts;
bool newBuffer = false;
if (mBuffer == NULL) {
newBuffer = true;
status_t err = mSampleTable->getSampleOffsetAndSize( status_t err = mSampleTable->getSampleOffsetAndSize(
mCurrentSampleIndex, &offset, &size); mCurrentSampleIndex, &offset, &size);
@@ -837,7 +836,6 @@ status_t MPEG4Source::read(
return err; return err;
} }
uint32_t dts;
err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts); err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
if (err != OK) { if (err != OK) {
@@ -846,11 +844,13 @@ status_t MPEG4Source::read(
err = mGroup->acquire_buffer(&mBuffer); err = mGroup->acquire_buffer(&mBuffer);
if (err != OK) { if (err != OK) {
assert(mBuffer == NULL); CHECK_EQ(mBuffer, NULL);
return err; return err;
} }
}
if (!mIsAVC || !mNeedsNALFraming) { if (!mIsAVC || mWantsNALFragments) {
if (newBuffer) {
ssize_t num_bytes_read = ssize_t num_bytes_read =
mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size); mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
@@ -858,7 +858,7 @@ status_t MPEG4Source::read(
mBuffer->release(); mBuffer->release();
mBuffer = NULL; mBuffer = NULL;
return err; return ERROR_IO;
} }
mBuffer->set_range(0, size); mBuffer->set_range(0, size);
@@ -866,13 +866,46 @@ status_t MPEG4Source::read(
mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts); mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale); mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
++mCurrentSampleIndex; ++mCurrentSampleIndex;
}
if (!mIsAVC) {
*out = mBuffer; *out = mBuffer;
mBuffer = NULL; mBuffer = NULL;
return OK; return OK;
} }
// Each NAL unit is split up into its constituent fragments and
// each one of them returned in its own buffer.
CHECK(mBuffer->range_length() >= 2);
const uint8_t *src =
(const uint8_t *)mBuffer->data() + mBuffer->range_offset();
size_t nal_size = U16_AT(src);
CHECK(mBuffer->range_length() >= 2 + nal_size);
MediaBuffer *clone = mBuffer->clone();
clone->set_range(mBuffer->range_offset() + 2, nal_size);
mBuffer->set_range(
mBuffer->range_offset() + 2 + nal_size,
mBuffer->range_length() - 2 - nal_size);
if (mBuffer->range_length() == 0) {
mBuffer->release();
mBuffer = NULL;
}
*out = clone;
return OK;
} else {
// Whole NAL units are returned but each fragment is prefixed by
// the start code (0x00 00 00 01).
ssize_t num_bytes_read = ssize_t num_bytes_read =
mDataSource->read_at(offset, mSrcBuffer, size); mDataSource->read_at(offset, mSrcBuffer, size);
@@ -880,24 +913,24 @@ status_t MPEG4Source::read(
mBuffer->release(); mBuffer->release();
mBuffer = NULL; mBuffer = NULL;
return err; return ERROR_IO;
} }
uint8_t *dstData = (uint8_t *)mBuffer->data(); uint8_t *dstData = (uint8_t *)mBuffer->data();
size_t srcOffset = 0; size_t srcOffset = 0;
size_t dstOffset = 0; size_t dstOffset = 0;
while (srcOffset < size) { while (srcOffset < size) {
assert(srcOffset + 1 < size); CHECK(srcOffset + 1 < size);
size_t nalLength = size_t nalLength =
(mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1]; (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
assert(srcOffset + 1 + nalLength < size); CHECK(srcOffset + 1 + nalLength < size);
srcOffset += 2; srcOffset += 2;
if (nalLength == 0) { if (nalLength == 0) {
continue; continue;
} }
assert(dstOffset + 4 <= mBuffer->size()); CHECK(dstOffset + 4 <= mBuffer->size());
dstData[dstOffset++] = 0; dstData[dstOffset++] = 0;
dstData[dstOffset++] = 0; dstData[dstOffset++] = 0;
@@ -919,6 +952,7 @@ status_t MPEG4Source::read(
return OK; return OK;
} }
}
bool SniffMPEG4( bool SniffMPEG4(
const sp<DataSource> &source, String8 *mimeType, float *confidence) { const sp<DataSource> &source, String8 *mimeType, float *confidence) {

View File

@@ -152,7 +152,7 @@ sp<OMXCodec> OMXCodec::Create(
uint32_t quirks = 0; uint32_t quirks = 0;
if (!strcmp(componentName, "OMX.PV.avcdec")) { if (!strcmp(componentName, "OMX.PV.avcdec")) {
quirks |= kWantsRawNALFrames; quirks |= kWantsNALFragments;
} }
if (!strcmp(componentName, "OMX.TI.MP3.decode")) { if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
quirks |= kNeedsFlushBeforeDisable; quirks |= kNeedsFlushBeforeDisable;
@@ -554,7 +554,7 @@ OMXCodec::OMXCodec(
} }
OMXCodec::~OMXCodec() { OMXCodec::~OMXCodec() {
CHECK_EQ(mState, LOADED); CHECK(mState == LOADED || mState == ERROR);
status_t err = mOMX->observe_node(mNode, NULL); status_t err = mOMX->observe_node(mNode, NULL);
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
@@ -1149,8 +1149,8 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
size_t size = specific->mSize; size_t size = specific->mSize;
if (!strcasecmp(mMIME, "video/avc") if (!strcasecmp("video/avc", mMIME)
&& !(mQuirks & kWantsRawNALFrames)) { && !(mQuirks & kWantsNALFragments)) {
static const uint8_t kNALStartCode[4] = static const uint8_t kNALStartCode[4] =
{ 0x00, 0x00, 0x00, 0x01 }; { 0x00, 0x00, 0x00, 0x01 };
@@ -1462,8 +1462,8 @@ status_t OMXCodec::start(MetaData *) {
} }
sp<MetaData> params = new MetaData; sp<MetaData> params = new MetaData;
if (!strcasecmp(mMIME, "video/avc") && !(mQuirks & kWantsRawNALFrames)) { if (mQuirks & kWantsNALFragments) {
params->setInt32(kKeyNeedsNALFraming, true); params->setInt32(kKeyWantsNALFragments, true);
} }
status_t err = mSource->start(params.get()); status_t err = mSource->start(params.get());

View File

@@ -139,7 +139,7 @@ sp<OMXDecoder> OMXDecoder::Create(
uint32_t quirks = 0; uint32_t quirks = 0;
if (!strcmp(codec, "OMX.PV.avcdec")) { if (!strcmp(codec, "OMX.PV.avcdec")) {
quirks |= kWantsRawNALFrames; quirks |= kWantsNALFragments;
} }
if (!strcmp(codec, "OMX.TI.AAC.decode") if (!strcmp(codec, "OMX.TI.AAC.decode")
|| !strcmp(codec, "OMX.TI.MP3.decode")) { || !strcmp(codec, "OMX.TI.MP3.decode")) {
@@ -274,8 +274,8 @@ status_t OMXDecoder::start(MetaData *) {
// mDealer->dump("Decoder Dealer"); // mDealer->dump("Decoder Dealer");
sp<MetaData> params = new MetaData; sp<MetaData> params = new MetaData;
if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) { if (mQuirks & kWantsNALFragments) {
params->setInt32(kKeyNeedsNALFraming, true); params->setInt32(kKeyWantsNALFragments, true);
} }
status_t err = mSource->start(params.get()); status_t err = mSource->start(params.get());
@@ -1331,7 +1331,7 @@ void OMXDecoder::onRealEmptyBufferDone(IOMX::buffer_id buffer) {
size_t range_length = 0; size_t range_length = 0;
if (mIsAVC && !(mQuirks & kWantsRawNALFrames)) { if (mIsAVC && !(mQuirks & kWantsNALFragments)) {
assert((*mCodecSpecificDataIterator).size + 4 <= mem->size()); assert((*mCodecSpecificDataIterator).size + 4 <= mem->size());
memcpy(mem->pointer(), kNALStartCode, 4); memcpy(mem->pointer(), kNALStartCode, 4);