author | Siva Ramaraju <sramaraju@nvidia.com> | |
Tue, 10 May 2011 05:06:30 +0000 (10:06 +0530) | ||
committer | Varun Colbert <vcolbert@nvidia.com> | |
Sat, 14 May 2011 02:16:41 +0000 (19:16 -0700) |
- support sf mkv parser on GB.
- changes to stabilize mkv playback.
- fix crash issues during playback.
- add divx/mpeg4 and mp3/ac3 support.
- Bug 816058
- Bug 812529
Change-Id: Ib39a744fb054b579455e9d57bd87774e1e9ca681
- changes to stabilize mkv playback.
- fix crash issues during playback.
- add divx/mpeg4 and mp3/ac3 support.
- Bug 816058
- Bug 812529
Change-Id: Ib39a744fb054b579455e9d57bd87774e1e9ca681
12 files changed:
extern const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW;
extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
+extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
kKeyBitRate = 'brte', // int32_t (bps)
kKeyESDS = 'esds', // raw data
kKeyAVCC = 'avcc', // raw data
+ kKeyD263 = 'd263', // raw data
kKeyVorbisInfo = 'vinf', // raw data
kKeyVorbisBooks = 'vboo', // raw data
kKeyWantsNALFragments = 'NALf',
include frameworks/base/media/libstagefright/codecs/common/Config.mk
-NV_MKV_ENABLED := 1
LOCAL_SRC_FILES:= \
AMRExtractor.cpp \
LOCAL_CFLAGS += -Wno-multichar
-LOCAL_CFLAGS += -DNV_MKV_ENABLED=$(NV_MKV_ENABLED)
-
LOCAL_MODULE:= libstagefright
include $(BUILD_SHARED_LIBRARY)
#include "include/ESDS.h"
#include <string.h>
+#include <utils/Log.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ESDS"
namespace android {
}
while (more);
+ *data_offset = offset;
if (*data_size > size) {
return ERROR_MALFORMED;
}
- *data_offset = offset;
-
return OK;
}
status_t err = skipDescriptorHeader(
offset, size, &tag, &sub_offset, &sub_size);
- if (err != OK) {
+ if (err != OK && tag != kTag_DecoderSpecificInfo) {
return err;
}
const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
+const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
return new OggExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
- #if (NV_MKV_ENABLED)
- {
- LOGV("NV_MKV_ENABLED - SuperExtractor Invoked");
- return new SuperExtractor (source);
- }
- #endif
LOGV("SF Matroska Extractor Invoked");
return new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
if (meta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
+ // relax and bypass codec specific info if init check fails
+ // CHECK_EQ(esds.InitCheck(), OK);
+ if (esds.InitCheck() == OK)
+ {
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
&codec_specific_data, &codec_specific_data_size);
-
- addCodecSpecificData(
+ addCodecSpecificData(
codec_specific_data, codec_specific_data_size);
+ }
} else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
// Parse the AVCDecoderConfigurationRecord
const uint8_t *ptr = (const uint8_t *)data;
-
+ if (ptr == NULL || size < 7) {
+ LOGV("Skipcodecdata- kKeyAVCC ERRROR: ptr= %x - size = %d", ptr, size);
+ goto skipcodecdata;
+ }
CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
uint8_t profile = ptr[1];
uint8_t level = ptr[3];
}
}
}
+ skipcodecdata:
int32_t bitRate = 0;
if (mIsEncoder) {
}
-static bool ValidateMkv (const sp<DataSource> &source,
- uint8_t *header, uint32_t readsize)
-{
- uint32_t cnt = 4; // 4 bytes ebml already read
- uint64_t hlen = 0;
- int32_t len_mask = 0x80;
- int32_t size = 1;
- int32_t n = 1;
- uint32_t rdsz = 0;
- bool status = false;
- bool reinitialise = false;
- uint8_t *data = NULL;
- if(!header)
- {
- goto cleanup;
- }
- data = header;
- static const char probe_data[] = "matroska";
- LOGV ("sniffsuper ++ validate mkv");
- hlen = data[cnt++];
- /*Determine length of hdr */
- while (size <= 8 && !(hlen & len_mask)) {
- size++;
- len_mask >>= 1;
- }
- if (size > 8) {
- LOGV ("sniffsuper mkv error- size > 8");
- goto cleanup;
- }
- hlen &= (len_mask - 1);
- while (n++ < size) {
- hlen = (hlen << 8) | data[cnt++];
- }
- LOGV ("sniff super: validate mkv- headerlen = %x", hlen);
- /* check if first read contain the whole header */
- if (readsize < (4 + size + hlen)) {
- // read more data as requried
- rdsz = 4 + size + (uint32_t)hlen;
- LOGV ("sniffsuper: mkv read more data = %d", rdsz);
- data = (uint8_t *) new uint8_t [rdsz];
- if(!data) {
- LOGV ("sniffsuper mkv error:: new alloc data fail");
- goto cleanup;
- }
- reinitialise = true;
- // Goto the beginning of the file
- size_t readcount = source->readAt(0, data, rdsz);
- if (readcount < (size_t)rdsz) {
- LOGV ("sniffsuper mkv error:: n < (ssize_t)rdsz");
- goto cleanup;
- }
- }
- /* Parse through the initial header to check if it contains the
- * document type 'matroska'.
- */
- for (n = 4+size; n <= (int)(4+size+hlen-(sizeof(probe_data)-1)); n++)
- {
- LOGV ("sniffsuper mkv memcmp n = %d", n);
- if (!memcmp(&data[n], probe_data, sizeof(probe_data)-1)) {
- LOGV ("sniffsuper break for loop - matroska identified");
- status = true;
- goto cleanup;
- }
- }
-cleanup:
- if(data && reinitialise)
- {
- LOGV ("sniffsuper: delete data");
- delete [] data;
- }
- LOGV ("sniffsuper -- validate mkv: status = %x", status);
- return status;
-}
-
bool SniffSuper (
const sp<DataSource> &source, String8 *mimeType, float *confidence,
sp<AMessage> *meta)
LOGV ("asf is identified /////");
return true;
}
- else if (!memcmp(header, NVFS_MKV_EBML, 4))
- {
- LOGV ("sniff super: ebml is identified, sniff mkv now");
- if (ValidateMkv (source, header, readsize))
- {
- *mimeType = MEDIA_MIMETYPE_CONTAINER_MATROSKA;
- *confidence = 1.0;
- LOGV ("sniffSuper: mkv identified");
- return true;
- }
- }
return false;
}
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
// Parse the AVCDecoderConfigurationRecord
const uint8_t *ptr = (const uint8_t *)data;
+ if (ptr == NULL || size < 7) {
+ LOGV("AVCDecoder BAD_VALUE: ptr = %x - size = %d", ptr, size);
+ return BAD_VALUE;
+ }
CHECK(size >= 7);
CHECK_EQ(ptr[0], 1); // configurationVersion == 1
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
int32_t vol_size = 0;
if (meta->findData(kKeyESDS, &type, &data, &size)) {
ESDS esds((const uint8_t *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
+ // relax and skip codec specfic info if initcheck fails
+ // CHECK_EQ(esds.InitCheck(), (status_t)OK);
+ if (esds.InitCheck() == (status_t)OK)
+ {
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
&codec_specific_data, &codec_specific_data_size);
- vol_data[0] = (uint8_t *) malloc(codec_specific_data_size);
- memcpy(vol_data[0], codec_specific_data, codec_specific_data_size);
- vol_size = codec_specific_data_size;
+ vol_data[0] = (uint8_t *) malloc(codec_specific_data_size);
+ memcpy(vol_data[0], codec_specific_data, codec_specific_data_size);
+ vol_size = codec_specific_data_size;
+ }
} else {
vol_data[0] = NULL;
vol_size = 0;
}
MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
- CHECK_EQ((int)mode, (int)actualMode);
+ if (mode != actualMode) {
+ PVCleanUpVideoDecoder(mHandle);
+ return UNKNOWN_ERROR;
+ }
PVSetPostProcType((VideoDecControls *) mHandle, 0);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
enum Type {
AVC,
AAC,
+ MP3,
+ AC3,
+ MPEG4,
OTHER
};
CHECK(meta->findData(
kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
- CHECK_GE(avccSize, 5u);
-
- mNALSizeLen = 1 + (avcc[4] & 3);
+ LOGV("avccSize = %d", avccSize);
+ mNALSizeLen = 1;
+ if (avcc && avccSize >= 5){
+ // relax this since failing for some content
+ // CHECK_GE(avccSize, 5u);
+ mNALSizeLen = 1 + (avcc[4] & 3);
+ }
LOGV("mNALSizeLen = %d", mNALSizeLen);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
+ mType = AC3;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ mType = MP3;
+ } else if (!strcasecmp (mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {
+ mType = MPEG4;
}
}
if (eos()) {
break;
}
-
mBlockEntry = mCluster->GetFirst();
}
status_t MatroskaSource::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
-
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+ LOGV( "MKV Seek Mode: %lld", seekTimeUs);
clearPendingFrames();
mBlockIter.seek(seekTimeUs);
}
if (err != OK) {
clearPendingFrames();
-
+ LOGV( "MKV readBlock error %d", __LINE__);
return err;
}
}
if (size < mNALSizeLen) {
frame->release();
frame = NULL;
-
+ LOGV( "MKV error malformed @ %d", __LINE__);
return ERROR_MALFORMED;
}
frame->release();
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);
+ if (mType == AVC)
+ {
+
+ uint8_t *data = (uint8_t *)buffer->data();
+ int32_t StartCodeSize = 4;
+ uint8_t *frameBuffer = data;
+ size_t Offset = 0;
+ static const uint8_t kNalStartCode[4] = {0x00, 0x00, 0x00, 0x01};
+ while(Offset+4 < size)
+ {
+ //LOGV("MKV read: Offset %d Size %d.", Offset, size);
+ data = (uint8_t *)buffer->data() + Offset;
+ 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;
+ LOGV("MKV read: Error_Malformed: mNALSizeLen %d NALsize %d size %d",
+ mNALSizeLen, NALsize, size);
+ return ERROR_MALFORMED;
+ }
+ memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4);
+ Offset += (NALsize + 4);
+ }
}
-
- // 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;
-
return OK;
}
return mTracks.itemAt(index).mMeta;
}
+static void addESDSFromVideoSpecificInfo(
+ const sp<MetaData> &meta, const void *asi, size_t asiSize) {
+ static const uint8_t kStaticESDS[] = {
+ 0x03, 22,
+ 0x00, 0x00, // ES_ID
+ 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+ 0x04, 17,
+ 0x40,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+
+ 0x05,
+ // Video SpecificInfo (with size prefix) follows
+ };
+
+ CHECK(asiSize < 128);
+ size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
+ uint8_t *esds = new uint8_t[esdsSize];
+ memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
+ uint8_t *ptr = esds + sizeof(kStaticESDS);
+ *ptr++ = asiSize;
+ memcpy(ptr, asi, asiSize);
+
+ meta->setData(kKeyESDS, 0, esds, esdsSize);
+
+ delete[] esds;
+ esds = NULL;
+}
static void addESDSFromAudioSpecificInfo(
const sp<MetaData> &meta, const void *asi, size_t asiSize) {
static const uint8_t kStaticESDS[] = {
for (size_t index = 0; index < tracks->GetTracksCount(); ++index) {
const mkvparser::Track *track = tracks->GetTrackByIndex(index);
+ if (track == NULL) {
+ continue;
+ }
const char *const codecID = track->GetCodecId();
LOGV("codec id = %s", codecID);
meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
} else if (!strcmp("V_VP8", codecID)) {
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
+ } else if ((!strcmp ("V_MS/VFW/FOURCC", codecID)) ||
+ (!strcmp ("V_MPEG4/ISO/ASP", codecID))) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ addESDSFromVideoSpecificInfo(
+ meta, codecPrivate, codecPrivateSize);
} else {
continue;
}
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
+ } else if (!strcmp("A_MPEG/L3", codecID)) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ } else if (!strcmp("A_AC3", codecID)) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
} else {
continue;
}
diff --git a/media/libstagefright/matroska/mkvparser.cpp b/media/libstagefright/matroska/mkvparser.cpp
//#include "odbgstream.hpp"\r
//using std::endl;\r
\r
+//#define LOG_NDEBUG 0\r
+#define LOG_TAG "Mkvparser"\r
+#include <utils/Log.h>\r
mkvparser::IMkvReader::~IMkvReader()\r
{\r
}\r
AudioTrack::AudioTrack(Segment* pSegment, const Info& i) :\r
Track(pSegment, i),\r
m_rate(0.0),\r
- m_channels(0),\r
+ m_channels(1),\r
m_bitDepth(-1)\r
{\r
assert(i.type == 2);\r
\r
Track::Settings videoSettings;\r
videoSettings.start = -1;\r
+ videoSettings.size = 0;\r
\r
Track::Settings audioSettings;\r
audioSettings.start = -1;\r
+ audioSettings.size = 0;\r
\r
while (pos < stop)\r
{\r
\r
void Cluster::LoadBlockEntries()\r
{\r
+ LOGV( "++%s[%d]", __FUNCTION__ , __LINE__);\r
if (m_entries)\r
+ {\r
+ LOGV( "m_entries allocated just return: m_entries = %x ",m_entries);\r
return;\r
+ }\r
\r
assert(m_pSegment);\r
assert(m_pos);\r
m_pos *= -1; //relative to segment\r
\r
long long pos = m_pSegment->m_start + m_pos; //absolute\r
+ LOGV( "Cluster Position = %llx", pos);\r
\r
{\r
long len;\r
//First count the number of entries\r
\r
long long idx = pos; //points to start of payload\r
- m_entriesCount = 0;\r
+ size_t entriesCount = 0;\r
\r
while (idx < stop)\r
{\r
idx += len; //consume size\r
\r
if (id == 0x20) //BlockGroup ID\r
- ++m_entriesCount;\r
+ {\r
+ ++entriesCount;\r
+ }\r
else if (id == 0x23) //SimpleBlock ID\r
- ++m_entriesCount;\r
+ {\r
+ ++entriesCount;\r
+ }\r
\r
idx += size; //consume payload\r
assert(idx <= stop);\r
}\r
}\r
-\r
+ m_entriesCount = entriesCount;\r
+ LOGV ( "blockentriesCount = %d", m_entriesCount);\r
assert(idx == stop);\r
assert(m_timecode >= 0);\r
-\r
if (m_entriesCount == 0) //TODO: handle empty clusters\r
return;\r
\r
pos += len; //consume size\r
\r
if (id == 0x20) //BlockGroup ID\r
+ {\r
ParseBlockGroup(pos, size, index++);\r
+ }\r
else if (id == 0x23) //SimpleBlock ID\r
+ {\r
ParseSimpleBlock(pos, size, index++);\r
-\r
+ }\r
pos += size; //consume payload\r
assert(pos <= stop);\r
}\r
}\r
-\r
assert(pos == stop);\r
assert(timecode >= 0);\r
assert(index == m_entriesCount);\r
+ LOGV( "--%s[%d]", __FUNCTION__ , __LINE__);\r
}\r
\r
\r
assert(pSimpleBlock); //TODO\r
\r
m_entries[index] = pSimpleBlock;\r
+ LOGV("ParseSimpleBlock: idx = %d - blockentry = %x", index, m_entries[index]);\r
}\r
\r
\r
++idx;\r
\r
if (idx >= m_entriesCount)\r
- return NULL;\r
+ {\r
+ LOGV("GetNext NULL : idx >= m_entriesCount");\r
+ return NULL;\r
+ }\r
+ LOGV("blockentriescount = %d - idx = %d - nextblockentry = %x",\r
+ m_entriesCount, idx, m_entries[idx]);\r
\r
return m_entries[idx];\r
}\r
{\r
short t;\r
\r
+\r
if (Match(pReader, pos, 0x7B, t))\r
{\r
if (t < 0)\r