Update software AVC decoder to no longer require the kWantsNALFragments hack.
Change-Id: I7f1882530a891a57d0cd76cbbd7084ee31c59bd1
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
index aa2a3d1..24c361e 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<int32_t>(malloc(size));
}
@@ -154,9 +156,7 @@
}
}
- sp<MetaData> params = new MetaData;
- params->setInt32(kKeyWantsNALFragments, true);
- mSource->start(params.get());
+ mSource->start();
mAnchorTimeUs = 0;
mNumSamplesOutput = 0;
@@ -167,9 +167,10 @@
}
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 @@
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 @@
}
}
- 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<uint8_t *>(inPtr), mInputBuffer->range_length(),
+ const_cast<uint8_t *>(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<uint8_t *>(inPtr),
- mInputBuffer->range_length());
+ mHandle, const_cast<uint8_t *>(fragPtr),
+ fragSize);
if (res != AVCDEC_SUCCESS) {
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- return UNKNOWN_ERROR;
+ break;
}
AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject;
@@ -324,47 +342,53 @@
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<uint8_t *>(inPtr),
- mInputBuffer->range_length());
-
- mInputBuffer->release();
- mInputBuffer = NULL;
+ mHandle, const_cast<uint8_t *>(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<uint8_t *>(inPtr),
- mInputBuffer->range_length());
+ mHandle, const_cast<uint8_t *>(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 @@
// 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<uint8_t *>(inPtr),
- mInputBuffer->range_length());
-
- mInputBuffer->release();
- mInputBuffer = NULL;
+ mHandle, const_cast<uint8_t *>(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 @@
}
}
- 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