From 940203809590378e7f24b5d1e4684945a0660fcb Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 12 May 2010 16:30:12 -0700 Subject: [PATCH] Update software AVC decoder to no longer require the kWantsNALFragments hack. Change-Id: I7f1882530a891a57d0cd76cbbd7084ee31c59bd1 --- .../codecs/avc/dec/AVCDecoder.cpp | 147 +++++++++++------- 1 file changed, 88 insertions(+), 59 deletions(-) diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp index aa2a3d146f277..24c361ed345de 100644 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -34,6 +34,8 @@ namespace android { +static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 }; + static int32_t Malloc(void *userData, int32_t size, int32_t attrs) { return reinterpret_cast(malloc(size)); } @@ -154,9 +156,7 @@ status_t AVCDecoder::start(MetaData *) { } } - sp params = new MetaData; - params->setInt32(kKeyWantsNALFragments, true); - mSource->start(params.get()); + mSource->start(); mAnchorTimeUs = 0; mNumSamplesOutput = 0; @@ -167,9 +167,10 @@ status_t AVCDecoder::start(MetaData *) { } void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) { - MediaBuffer *buffer = new MediaBuffer(size); - memcpy(buffer->data(), data, size); - buffer->set_range(0, size); + MediaBuffer *buffer = new MediaBuffer(size + 4); + memcpy(buffer->data(), kStartCode, 4); + memcpy((uint8_t *)buffer->data() + 4, data, size); + buffer->set_range(0, size + 4); mCodecSpecificData.push(buffer); } @@ -200,6 +201,29 @@ sp AVCDecoder::getFormat() { return mFormat; } +static void findNALFragment( + const MediaBuffer *buffer, const uint8_t **fragPtr, size_t *fragSize) { + const uint8_t *data = + (const uint8_t *)buffer->data() + buffer->range_offset(); + + size_t size = buffer->range_length(); + + CHECK(size >= 4); + CHECK(!memcmp(kStartCode, data, 4)); + + size_t offset = 4; + while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) { + ++offset; + } + + *fragPtr = &data[4]; + if (offset + 3 >= size) { + *fragSize = size - 4; + } else { + *fragSize = offset - 4; + } +} + status_t AVCDecoder::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; @@ -254,37 +278,31 @@ status_t AVCDecoder::read( } } - const uint8_t *inPtr = - (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); + const uint8_t *fragPtr; + size_t fragSize; + findNALFragment(mInputBuffer, &fragPtr, &fragSize); + + bool releaseFragment = true; + status_t err = UNKNOWN_ERROR; int nalType; int nalRefIdc; AVCDec_Status res = PVAVCDecGetNALType( - const_cast(inPtr), mInputBuffer->range_length(), + const_cast(fragPtr), fragSize, &nalType, &nalRefIdc); if (res != AVCDEC_SUCCESS) { LOGE("cannot determine nal type"); - - mInputBuffer->release(); - mInputBuffer = NULL; - - return UNKNOWN_ERROR; - } - - switch (nalType) { + } else switch (nalType) { case AVC_NALTYPE_SPS: { res = PVAVCDecSeqParamSet( - mHandle, const_cast(inPtr), - mInputBuffer->range_length()); + mHandle, const_cast(fragPtr), + fragSize); if (res != AVCDEC_SUCCESS) { - mInputBuffer->release(); - mInputBuffer = NULL; - - return UNKNOWN_ERROR; + break; } AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject; @@ -324,47 +342,53 @@ status_t AVCDecoder::read( int32_t aligned_width = (crop_right - crop_left + 1 + 15) & ~15; int32_t aligned_height = (crop_bottom - crop_top + 1 + 15) & ~15; - mFormat->setInt32(kKeyWidth, aligned_width); - mFormat->setInt32(kKeyHeight, aligned_height); - mInputBuffer->release(); - mInputBuffer = NULL; + int32_t oldWidth, oldHeight; + CHECK(mFormat->findInt32(kKeyWidth, &oldWidth)); + CHECK(mFormat->findInt32(kKeyHeight, &oldHeight)); - return INFO_FORMAT_CHANGED; + if (oldWidth != aligned_width || oldHeight != aligned_height) { + mFormat->setInt32(kKeyWidth, aligned_width); + mFormat->setInt32(kKeyHeight, aligned_height); + + err = INFO_FORMAT_CHANGED; + } else { + *out = new MediaBuffer(0); + err = OK; + } + break; } case AVC_NALTYPE_PPS: { res = PVAVCDecPicParamSet( - mHandle, const_cast(inPtr), - mInputBuffer->range_length()); - - mInputBuffer->release(); - mInputBuffer = NULL; + mHandle, const_cast(fragPtr), + fragSize); if (res != AVCDEC_SUCCESS) { - return UNKNOWN_ERROR; + break; } *out = new MediaBuffer(0); - return OK; + err = OK; + break; } case AVC_NALTYPE_SLICE: case AVC_NALTYPE_IDR: { res = PVAVCDecodeSlice( - mHandle, const_cast(inPtr), - mInputBuffer->range_length()); + mHandle, const_cast(fragPtr), + fragSize); if (res == AVCDEC_PICTURE_OUTPUT_READY) { int32_t index; int32_t Release; AVCFrameIO Output; Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; - CHECK_EQ(PVAVCDecGetOutput( - mHandle, &index, &Release, &Output), + + CHECK_EQ(PVAVCDecGetOutput(mHandle, &index, &Release, &Output), AVCDEC_SUCCESS); CHECK(index >= 0); @@ -376,48 +400,44 @@ status_t AVCDecoder::read( // Do _not_ release input buffer yet. - return OK; + releaseFragment = false; + err = OK; + break; } - mInputBuffer->release(); - mInputBuffer = NULL; - if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) { *out = new MediaBuffer(0); - return OK; + err = OK; } else { LOGV("failed to decode frame (res = %d)", res); - return UNKNOWN_ERROR; } + break; } case AVC_NALTYPE_SEI: { res = PVAVCDecSEI( - mHandle, const_cast(inPtr), - mInputBuffer->range_length()); - - mInputBuffer->release(); - mInputBuffer = NULL; + mHandle, const_cast(fragPtr), + fragSize); if (res != AVCDEC_SUCCESS) { - return UNKNOWN_ERROR; + break; } *out = new MediaBuffer(0); - return OK; + err = OK; + break; } case AVC_NALTYPE_AUD: + case AVC_NALTYPE_FILL: { - mInputBuffer->release(); - mInputBuffer = NULL; - *out = new MediaBuffer(0); - return OK; + err = OK; + break; } default: @@ -428,10 +448,19 @@ status_t AVCDecoder::read( } } - mInputBuffer->release(); - mInputBuffer = NULL; + if (releaseFragment) { + size_t offset = mInputBuffer->range_offset(); + if (fragSize + 4 == mInputBuffer->range_length()) { + mInputBuffer->release(); + mInputBuffer = NULL; + } else { + mInputBuffer->set_range( + offset + fragSize + 4, + mInputBuffer->range_length() - fragSize - 4); + } + } - return UNKNOWN_ERROR; + return err; } // static