Merge "Update software AVC decoder to no longer require the kWantsNALFragments hack." into kraken

This commit is contained in:
Andreas Huber
2010-05-20 15:01:07 -07:00
committed by Android (Google) Code Review

View File

@@ -34,6 +34,8 @@
namespace android { namespace android {
static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
static int32_t Malloc(void *userData, int32_t size, int32_t attrs) { static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
return reinterpret_cast<int32_t>(malloc(size)); return reinterpret_cast<int32_t>(malloc(size));
} }
@@ -154,9 +156,7 @@ status_t AVCDecoder::start(MetaData *) {
} }
} }
sp<MetaData> params = new MetaData; mSource->start();
params->setInt32(kKeyWantsNALFragments, true);
mSource->start(params.get());
mAnchorTimeUs = 0; mAnchorTimeUs = 0;
mNumSamplesOutput = 0; mNumSamplesOutput = 0;
@@ -167,9 +167,10 @@ status_t AVCDecoder::start(MetaData *) {
} }
void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) { void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) {
MediaBuffer *buffer = new MediaBuffer(size); MediaBuffer *buffer = new MediaBuffer(size + 4);
memcpy(buffer->data(), data, size); memcpy(buffer->data(), kStartCode, 4);
buffer->set_range(0, size); memcpy((uint8_t *)buffer->data() + 4, data, size);
buffer->set_range(0, size + 4);
mCodecSpecificData.push(buffer); mCodecSpecificData.push(buffer);
} }
@@ -200,6 +201,29 @@ sp<MetaData> AVCDecoder::getFormat() {
return mFormat; 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( status_t AVCDecoder::read(
MediaBuffer **out, const ReadOptions *options) { MediaBuffer **out, const ReadOptions *options) {
*out = NULL; *out = NULL;
@@ -254,37 +278,31 @@ status_t AVCDecoder::read(
} }
} }
const uint8_t *inPtr = const uint8_t *fragPtr;
(const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); size_t fragSize;
findNALFragment(mInputBuffer, &fragPtr, &fragSize);
bool releaseFragment = true;
status_t err = UNKNOWN_ERROR;
int nalType; int nalType;
int nalRefIdc; int nalRefIdc;
AVCDec_Status res = AVCDec_Status res =
PVAVCDecGetNALType( PVAVCDecGetNALType(
const_cast<uint8_t *>(inPtr), mInputBuffer->range_length(), const_cast<uint8_t *>(fragPtr), fragSize,
&nalType, &nalRefIdc); &nalType, &nalRefIdc);
if (res != AVCDEC_SUCCESS) { if (res != AVCDEC_SUCCESS) {
LOGE("cannot determine nal type"); LOGE("cannot determine nal type");
} else switch (nalType) {
mInputBuffer->release();
mInputBuffer = NULL;
return UNKNOWN_ERROR;
}
switch (nalType) {
case AVC_NALTYPE_SPS: case AVC_NALTYPE_SPS:
{ {
res = PVAVCDecSeqParamSet( res = PVAVCDecSeqParamSet(
mHandle, const_cast<uint8_t *>(inPtr), mHandle, const_cast<uint8_t *>(fragPtr),
mInputBuffer->range_length()); fragSize);
if (res != AVCDEC_SUCCESS) { if (res != AVCDEC_SUCCESS) {
mInputBuffer->release(); break;
mInputBuffer = NULL;
return UNKNOWN_ERROR;
} }
AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject; 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_width = (crop_right - crop_left + 1 + 15) & ~15;
int32_t aligned_height = (crop_bottom - crop_top + 1 + 15) & ~15; int32_t aligned_height = (crop_bottom - crop_top + 1 + 15) & ~15;
int32_t oldWidth, oldHeight;
CHECK(mFormat->findInt32(kKeyWidth, &oldWidth));
CHECK(mFormat->findInt32(kKeyHeight, &oldHeight));
if (oldWidth != aligned_width || oldHeight != aligned_height) {
mFormat->setInt32(kKeyWidth, aligned_width); mFormat->setInt32(kKeyWidth, aligned_width);
mFormat->setInt32(kKeyHeight, aligned_height); mFormat->setInt32(kKeyHeight, aligned_height);
mInputBuffer->release(); err = INFO_FORMAT_CHANGED;
mInputBuffer = NULL; } else {
*out = new MediaBuffer(0);
return INFO_FORMAT_CHANGED; err = OK;
}
break;
} }
case AVC_NALTYPE_PPS: case AVC_NALTYPE_PPS:
{ {
res = PVAVCDecPicParamSet( res = PVAVCDecPicParamSet(
mHandle, const_cast<uint8_t *>(inPtr), mHandle, const_cast<uint8_t *>(fragPtr),
mInputBuffer->range_length()); fragSize);
mInputBuffer->release();
mInputBuffer = NULL;
if (res != AVCDEC_SUCCESS) { if (res != AVCDEC_SUCCESS) {
return UNKNOWN_ERROR; break;
} }
*out = new MediaBuffer(0); *out = new MediaBuffer(0);
return OK; err = OK;
break;
} }
case AVC_NALTYPE_SLICE: case AVC_NALTYPE_SLICE:
case AVC_NALTYPE_IDR: case AVC_NALTYPE_IDR:
{ {
res = PVAVCDecodeSlice( res = PVAVCDecodeSlice(
mHandle, const_cast<uint8_t *>(inPtr), mHandle, const_cast<uint8_t *>(fragPtr),
mInputBuffer->range_length()); fragSize);
if (res == AVCDEC_PICTURE_OUTPUT_READY) { if (res == AVCDEC_PICTURE_OUTPUT_READY) {
int32_t index; int32_t index;
int32_t Release; int32_t Release;
AVCFrameIO Output; AVCFrameIO Output;
Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; 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); AVCDEC_SUCCESS);
CHECK(index >= 0); CHECK(index >= 0);
@@ -376,48 +400,44 @@ status_t AVCDecoder::read(
// Do _not_ release input buffer yet. // 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) { if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) {
*out = new MediaBuffer(0); *out = new MediaBuffer(0);
return OK; err = OK;
} else { } else {
LOGV("failed to decode frame (res = %d)", res); LOGV("failed to decode frame (res = %d)", res);
return UNKNOWN_ERROR;
} }
break;
} }
case AVC_NALTYPE_SEI: case AVC_NALTYPE_SEI:
{ {
res = PVAVCDecSEI( res = PVAVCDecSEI(
mHandle, const_cast<uint8_t *>(inPtr), mHandle, const_cast<uint8_t *>(fragPtr),
mInputBuffer->range_length()); fragSize);
mInputBuffer->release();
mInputBuffer = NULL;
if (res != AVCDEC_SUCCESS) { if (res != AVCDEC_SUCCESS) {
return UNKNOWN_ERROR; break;
} }
*out = new MediaBuffer(0); *out = new MediaBuffer(0);
return OK; err = OK;
break;
} }
case AVC_NALTYPE_AUD: case AVC_NALTYPE_AUD:
case AVC_NALTYPE_FILL:
{ {
mInputBuffer->release();
mInputBuffer = NULL;
*out = new MediaBuffer(0); *out = new MediaBuffer(0);
return OK; err = OK;
break;
} }
default: default:
@@ -428,10 +448,19 @@ status_t AVCDecoder::read(
} }
} }
if (releaseFragment) {
size_t offset = mInputBuffer->range_offset();
if (fragSize + 4 == mInputBuffer->range_length()) {
mInputBuffer->release(); mInputBuffer->release();
mInputBuffer = NULL; mInputBuffer = NULL;
} else {
mInputBuffer->set_range(
offset + fragSize + 4,
mInputBuffer->range_length() - fragSize - 4);
}
}
return UNKNOWN_ERROR; return err;
} }
// static // static