Merge "Support multiple NAL fragments per .mkv payload"
This commit is contained in:
committed by
Android (Google) Code Review
commit
0044a15eb9
@@ -423,75 +423,89 @@ again:
|
|||||||
MediaBuffer *frame = *mPendingFrames.begin();
|
MediaBuffer *frame = *mPendingFrames.begin();
|
||||||
mPendingFrames.erase(mPendingFrames.begin());
|
mPendingFrames.erase(mPendingFrames.begin());
|
||||||
|
|
||||||
size_t size = frame->range_length();
|
|
||||||
|
|
||||||
if (mType != AVC) {
|
if (mType != AVC) {
|
||||||
*out = frame;
|
*out = frame;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < mNALSizeLen) {
|
// Each input frame contains one or more NAL fragments, each fragment
|
||||||
frame->release();
|
// is prefixed by mNALSizeLen bytes giving the fragment length,
|
||||||
frame = NULL;
|
// followed by a corresponding number of bytes containing the fragment.
|
||||||
|
// We output all these fragments into a single large buffer separated
|
||||||
|
// by startcodes (0x00 0x00 0x00 0x01).
|
||||||
|
|
||||||
return ERROR_MALFORMED;
|
const uint8_t *srcPtr =
|
||||||
|
(const uint8_t *)frame->data() + frame->range_offset();
|
||||||
|
|
||||||
|
size_t srcSize = frame->range_length();
|
||||||
|
|
||||||
|
size_t dstSize = 0;
|
||||||
|
MediaBuffer *buffer = NULL;
|
||||||
|
uint8_t *dstPtr = NULL;
|
||||||
|
|
||||||
|
for (int32_t pass = 0; pass < 2; ++pass) {
|
||||||
|
size_t srcOffset = 0;
|
||||||
|
size_t dstOffset = 0;
|
||||||
|
while (srcOffset + mNALSizeLen <= srcSize) {
|
||||||
|
size_t NALsize;
|
||||||
|
switch (mNALSizeLen) {
|
||||||
|
case 1: NALsize = srcPtr[srcOffset]; break;
|
||||||
|
case 2: NALsize = U16_AT(srcPtr + srcOffset); break;
|
||||||
|
case 3: NALsize = U24_AT(srcPtr + srcOffset); break;
|
||||||
|
case 4: NALsize = U32_AT(srcPtr + srcOffset); break;
|
||||||
|
default:
|
||||||
|
TRESPASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcOffset + mNALSizeLen + NALsize > srcSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == 1) {
|
||||||
|
memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4);
|
||||||
|
|
||||||
|
memcpy(&dstPtr[dstOffset + 4],
|
||||||
|
&srcPtr[srcOffset + mNALSizeLen],
|
||||||
|
NALsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
dstOffset += 4; // 0x00 00 00 01
|
||||||
|
dstOffset += NALsize;
|
||||||
|
|
||||||
|
srcOffset += mNALSizeLen + NALsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcOffset < srcSize) {
|
||||||
|
// There were trailing bytes or not enough data to complete
|
||||||
|
// a fragment.
|
||||||
|
|
||||||
|
frame->release();
|
||||||
|
frame = NULL;
|
||||||
|
|
||||||
|
return ERROR_MALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == 0) {
|
||||||
|
dstSize = dstOffset;
|
||||||
|
|
||||||
|
buffer = new MediaBuffer(dstSize);
|
||||||
|
|
||||||
|
int64_t timeUs;
|
||||||
|
CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
|
||||||
|
int32_t isSync;
|
||||||
|
CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
|
||||||
|
|
||||||
|
buffer->meta_data()->setInt64(kKeyTime, timeUs);
|
||||||
|
buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
|
||||||
|
|
||||||
|
dstPtr = (uint8_t *)buffer->data();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the case of AVC content, each NAL unit is prefixed by
|
|
||||||
// mNALSizeLen bytes of length. We want to prefix the data with
|
|
||||||
// a four-byte 0x00000001 startcode instead of the length prefix.
|
|
||||||
// mNALSizeLen ranges from 1 through 4 bytes, so add an extra
|
|
||||||
// 3 bytes of padding to the buffer start.
|
|
||||||
static const size_t kPadding = 3;
|
|
||||||
|
|
||||||
MediaBuffer *buffer = new MediaBuffer(size + kPadding);
|
|
||||||
|
|
||||||
int64_t timeUs;
|
|
||||||
CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
|
|
||||||
int32_t isSync;
|
|
||||||
CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
|
|
||||||
|
|
||||||
buffer->meta_data()->setInt64(kKeyTime, timeUs);
|
|
||||||
buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
|
|
||||||
|
|
||||||
memcpy((uint8_t *)buffer->data() + kPadding,
|
|
||||||
(const uint8_t *)frame->data() + frame->range_offset(),
|
|
||||||
size);
|
|
||||||
|
|
||||||
buffer->set_range(kPadding, size);
|
|
||||||
|
|
||||||
frame->release();
|
frame->release();
|
||||||
frame = NULL;
|
frame = NULL;
|
||||||
|
|
||||||
uint8_t *data = (uint8_t *)buffer->data();
|
|
||||||
|
|
||||||
size_t NALsize;
|
|
||||||
switch (mNALSizeLen) {
|
|
||||||
case 1: NALsize = data[kPadding]; break;
|
|
||||||
case 2: NALsize = U16_AT(&data[kPadding]); break;
|
|
||||||
case 3: NALsize = U24_AT(&data[kPadding]); break;
|
|
||||||
case 4: NALsize = U32_AT(&data[kPadding]); break;
|
|
||||||
default:
|
|
||||||
TRESPASS();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size < NALsize + mNALSizeLen) {
|
|
||||||
buffer->release();
|
|
||||||
buffer = NULL;
|
|
||||||
|
|
||||||
return ERROR_MALFORMED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size > NALsize + mNALSizeLen) {
|
|
||||||
LOGW("discarding %d bytes of data.", size - NALsize - mNALSizeLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
// actual data starts at &data[kPadding + mNALSizeLen]
|
|
||||||
|
|
||||||
memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4);
|
|
||||||
buffer->set_range(mNALSizeLen - 1, NALsize + 4);
|
|
||||||
|
|
||||||
*out = buffer;
|
*out = buffer;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user