summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/matroska
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-11-15 15:10:34 -0800
committerAndreas Huber <andih@google.com>2010-11-15 15:10:34 -0800
commitb10f3669a9b73cd024662c2b70f5155bc0c2cd21 (patch)
tree2f9c7217d92442b4e5e55c31f231a139c55700ad /media/libstagefright/matroska
parentf9c2d3381e0bb174194347b927ef2b36329f3a54 (diff)
downloadframeworks_av-b10f3669a9b73cd024662c2b70f5155bc0c2cd21.zip
frameworks_av-b10f3669a9b73cd024662c2b70f5155bc0c2cd21.tar.gz
frameworks_av-b10f3669a9b73cd024662c2b70f5155bc0c2cd21.tar.bz2
Proper support for variable NALsize lengths of AVC content in .mkv files.
Change-Id: If60cc80998b3231b6aaedc39fc3f5a94f84a5929 related-to-bug: 3197442
Diffstat (limited to 'media/libstagefright/matroska')
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp121
1 files changed, 67 insertions, 54 deletions
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index d16476d..a40c0a3 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -22,13 +22,15 @@
#include "mkvparser.hpp"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
#include <utils/String8.h>
namespace android {
@@ -81,46 +83,6 @@ private:
////////////////////////////////////////////////////////////////////////////////
-#include <ctype.h>
-static void hexdump(const void *_data, size_t size) {
- const uint8_t *data = (const uint8_t *)_data;
- size_t offset = 0;
- while (offset < size) {
- printf("0x%04x ", offset);
-
- size_t n = size - offset;
- if (n > 16) {
- n = 16;
- }
-
- for (size_t i = 0; i < 16; ++i) {
- if (i == 8) {
- printf(" ");
- }
-
- if (offset + i < size) {
- printf("%02x ", data[offset + i]);
- } else {
- printf(" ");
- }
- }
-
- printf(" ");
-
- for (size_t i = 0; i < n; ++i) {
- if (isprint(data[offset + i])) {
- printf("%c", data[offset + i]);
- } else {
- printf(".");
- }
- }
-
- printf("\n");
-
- offset += 16;
- }
-}
-
struct BlockIterator {
BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);
@@ -167,6 +129,7 @@ private:
size_t mTrackIndex;
Type mType;
BlockIterator mBlockIter;
+ size_t mNALSizeLen; // for type AVC
status_t advance();
@@ -180,13 +143,26 @@ MatroskaSource::MatroskaSource(
mTrackIndex(index),
mType(OTHER),
mBlockIter(mExtractor->mSegment,
- mExtractor->mTracks.itemAt(index).mTrackNum) {
+ mExtractor->mTracks.itemAt(index).mTrackNum),
+ mNALSizeLen(0) {
+ sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
+
const char *mime;
- CHECK(mExtractor->mTracks.itemAt(index).mMeta->
- findCString(kKeyMIMEType, &mime));
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
mType = AVC;
+
+ uint32_t dummy;
+ const uint8_t *avcc;
+ size_t avccSize;
+ CHECK(meta->findData(
+ kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
+
+ CHECK_GE(avccSize, 5u);
+
+ mNALSizeLen = 1 + (avcc[4] & 3);
+ LOGV("mNALSizeLen = %d", mNALSizeLen);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
}
@@ -276,6 +252,10 @@ int64_t BlockIterator::blockTimeUs() const {
////////////////////////////////////////////////////////////////////////////////
+static unsigned U24_AT(const uint8_t *ptr) {
+ return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+}
+
status_t MatroskaSource::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
@@ -286,6 +266,7 @@ status_t MatroskaSource::read(
mBlockIter.seek(seekTimeUs);
}
+again:
if (mBlockIter.eos()) {
return ERROR_END_OF_STREAM;
}
@@ -294,38 +275,70 @@ status_t MatroskaSource::read(
size_t size = block->GetSize();
int64_t timeUs = mBlockIter.blockTimeUs();
- MediaBuffer *buffer = new MediaBuffer(size + 2);
+ // 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);
buffer->meta_data()->setInt64(kKeyTime, timeUs);
buffer->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
long res = block->Read(
- mExtractor->mReader, (unsigned char *)buffer->data() + 2);
+ mExtractor->mReader, (unsigned char *)buffer->data() + kPadding);
if (res != 0) {
return ERROR_END_OF_STREAM;
}
- buffer->set_range(2, size);
+ buffer->set_range(kPadding, size);
if (mType == AVC) {
- CHECK(size >= 2);
+ CHECK_GE(size, mNALSizeLen);
uint8_t *data = (uint8_t *)buffer->data();
- unsigned NALsize = data[2] << 8 | data[3];
- CHECK_EQ(size, NALsize + 2);
+ 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();
+ }
- memcpy(data, "\x00\x00\x00\x01", 4);
- buffer->set_range(0, size + 2);
+ CHECK_GE(size, NALsize + mNALSizeLen);
+ 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);
} else if (mType == AAC) {
// There's strange junk at the beginning...
- const uint8_t *data = (const uint8_t *)buffer->data() + 2;
+ const uint8_t *data = (const uint8_t *)buffer->data() + kPadding;
+
+ // hexdump(data, size);
+
size_t offset = 0;
while (offset < size && data[offset] != 0x21) {
++offset;
}
- buffer->set_range(2 + offset, size - offset);
+
+ if (size == offset) {
+ buffer->release();
+
+ mBlockIter.advance();
+ goto again;
+ }
+
+ buffer->set_range(kPadding + offset, size - offset);
}
*out = buffer;