Skip to content

Commit 2378341

Browse files
committed
Support multiple NAL fragments per .mkv payload
Apparently the payload for an h.264 track in an .mkv file can contain multiple NAL fragments, we used to discard everything after the first one before, now we preserve them all. Change-Id: Ic7187365309f3880a3256982879a45df50db697d related-to-bug: 5337218
1 parent 781ae92 commit 2378341

1 file changed

Lines changed: 61 additions & 47 deletions

File tree

media/libstagefright/matroska/MatroskaExtractor.cpp

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -423,74 +423,88 @@ status_t MatroskaSource::read(
423423
MediaBuffer *frame = *mPendingFrames.begin();
424424
mPendingFrames.erase(mPendingFrames.begin());
425425

426-
size_t size = frame->range_length();
427-
428426
if (mType != AVC) {
429427
*out = frame;
430428

431429
return OK;
432430
}
433431

434-
if (size < mNALSizeLen) {
435-
frame->release();
436-
frame = NULL;
432+
// Each input frame contains one or more NAL fragments, each fragment
433+
// is prefixed by mNALSizeLen bytes giving the fragment length,
434+
// followed by a corresponding number of bytes containing the fragment.
435+
// We output all these fragments into a single large buffer separated
436+
// by startcodes (0x00 0x00 0x00 0x01).
437+
438+
const uint8_t *srcPtr =
439+
(const uint8_t *)frame->data() + frame->range_offset();
440+
441+
size_t srcSize = frame->range_length();
442+
443+
size_t dstSize = 0;
444+
MediaBuffer *buffer = NULL;
445+
uint8_t *dstPtr = NULL;
446+
447+
for (int32_t pass = 0; pass < 2; ++pass) {
448+
size_t srcOffset = 0;
449+
size_t dstOffset = 0;
450+
while (srcOffset + mNALSizeLen <= srcSize) {
451+
size_t NALsize;
452+
switch (mNALSizeLen) {
453+
case 1: NALsize = srcPtr[srcOffset]; break;
454+
case 2: NALsize = U16_AT(srcPtr + srcOffset); break;
455+
case 3: NALsize = U24_AT(srcPtr + srcOffset); break;
456+
case 4: NALsize = U32_AT(srcPtr + srcOffset); break;
457+
default:
458+
TRESPASS();
459+
}
437460

438-
return ERROR_MALFORMED;
439-
}
461+
if (srcOffset + mNALSizeLen + NALsize > srcSize) {
462+
break;
463+
}
440464

441-
// In the case of AVC content, each NAL unit is prefixed by
442-
// mNALSizeLen bytes of length. We want to prefix the data with
443-
// a four-byte 0x00000001 startcode instead of the length prefix.
444-
// mNALSizeLen ranges from 1 through 4 bytes, so add an extra
445-
// 3 bytes of padding to the buffer start.
446-
static const size_t kPadding = 3;
465+
if (pass == 1) {
466+
memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4);
447467

448-
MediaBuffer *buffer = new MediaBuffer(size + kPadding);
468+
memcpy(&dstPtr[dstOffset + 4],
469+
&srcPtr[srcOffset + mNALSizeLen],
470+
NALsize);
471+
}
449472

450-
int64_t timeUs;
451-
CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
452-
int32_t isSync;
453-
CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
473+
dstOffset += 4; // 0x00 00 00 01
474+
dstOffset += NALsize;
454475

455-
buffer->meta_data()->setInt64(kKeyTime, timeUs);
456-
buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
476+
srcOffset += mNALSizeLen + NALsize;
477+
}
457478

458-
memcpy((uint8_t *)buffer->data() + kPadding,
459-
(const uint8_t *)frame->data() + frame->range_offset(),
460-
size);
479+
if (srcOffset < srcSize) {
480+
// There were trailing bytes or not enough data to complete
481+
// a fragment.
461482

462-
buffer->set_range(kPadding, size);
483+
frame->release();
484+
frame = NULL;
463485

464-
frame->release();
465-
frame = NULL;
486+
return ERROR_MALFORMED;
487+
}
466488

467-
uint8_t *data = (uint8_t *)buffer->data();
489+
if (pass == 0) {
490+
dstSize = dstOffset;
468491

469-
size_t NALsize;
470-
switch (mNALSizeLen) {
471-
case 1: NALsize = data[kPadding]; break;
472-
case 2: NALsize = U16_AT(&data[kPadding]); break;
473-
case 3: NALsize = U24_AT(&data[kPadding]); break;
474-
case 4: NALsize = U32_AT(&data[kPadding]); break;
475-
default:
476-
TRESPASS();
477-
}
492+
buffer = new MediaBuffer(dstSize);
478493

479-
if (size < NALsize + mNALSizeLen) {
480-
buffer->release();
481-
buffer = NULL;
494+
int64_t timeUs;
495+
CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
496+
int32_t isSync;
497+
CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
482498

483-
return ERROR_MALFORMED;
484-
}
499+
buffer->meta_data()->setInt64(kKeyTime, timeUs);
500+
buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
485501

486-
if (size > NALsize + mNALSizeLen) {
487-
LOGW("discarding %d bytes of data.", size - NALsize - mNALSizeLen);
502+
dstPtr = (uint8_t *)buffer->data();
503+
}
488504
}
489505

490-
// actual data starts at &data[kPadding + mNALSizeLen]
491-
492-
memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4);
493-
buffer->set_range(mNALSizeLen - 1, NALsize + 4);
506+
frame->release();
507+
frame = NULL;
494508

495509
*out = buffer;
496510

0 commit comments

Comments
 (0)