Merge "mkv supports more video codec types"
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index a399940..f8aa784 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -958,6 +958,59 @@
////////////////////////////////////////////////////////////////////////////////
+// trans all FOURCC to lower char
+static uint32_t FourCCtoLower(uint32_t fourcc) {
+ uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
+ uint8_t ch_2 = tolower((fourcc >> 16) & 0xff);
+ uint8_t ch_3 = tolower((fourcc >> 8) & 0xff);
+ uint8_t ch_4 = tolower((fourcc) & 0xff);
+ uint32_t fourcc_out = ch_1 << 24 | ch_2 << 16 | ch_3 << 8 | ch_4;
+
+ return fourcc_out;
+}
+
+static const char *MKVFourCC2MIME(uint32_t fourcc) {
+ ALOGV("MKVFourCC2MIME fourcc 0x%8.8x", fourcc);
+ uint32_t lowerFourcc = FourCCtoLower(fourcc);
+ switch (lowerFourcc) {
+ case FOURCC("mp4v"):
+ return MEDIA_MIMETYPE_VIDEO_MPEG4;
+
+ case FOURCC("s263"):
+ case FOURCC("h263"):
+ return MEDIA_MIMETYPE_VIDEO_H263;
+
+ case FOURCC("avc1"):
+ case FOURCC("h264"):
+ return MEDIA_MIMETYPE_VIDEO_AVC;
+
+ case FOURCC("mpg2"):
+ return MEDIA_MIMETYPE_VIDEO_MPEG2;
+
+ case FOURCC("xvid"):
+ return MEDIA_MIMETYPE_VIDEO_XVID;
+
+ case FOURCC("divx"):
+ case FOURCC("dx50"):
+ return MEDIA_MIMETYPE_VIDEO_DIVX;
+
+ case FOURCC("div3"):
+ case FOURCC("div4"):
+ return MEDIA_MIMETYPE_VIDEO_DIVX3;
+
+ case FOURCC("mjpg"):
+ case FOURCC("mppg"):
+ return MEDIA_MIMETYPE_VIDEO_MJPEG;
+
+ default:
+ char fourccString[5];
+ MakeFourCCString(fourcc, fourccString);
+ ALOGW("mkv unsupport fourcc %s", fourccString);
+ return "";
+ }
+}
+
+
MatroskaExtractor::MatroskaExtractor(DataSourceHelper *source)
: mDataSource(source),
mReader(new DataSourceBaseReader(mDataSource)),
@@ -1308,6 +1361,89 @@
return OK;
}
+status_t MatroskaExtractor::synthesizeMPEG2(TrackInfo *trackInfo, size_t index) {
+ ALOGV("synthesizeMPEG2");
+ BlockIterator iter(this, trackInfo->mTrackNum, index);
+ if (iter.eos()) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block *block = iter.block();
+ if (block->GetFrameCount() <= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block::Frame &frame = block->GetFrame(0);
+ auto tmpData = heapbuffer<unsigned char>(frame.len);
+ long n = frame.Read(mReader, tmpData.get());
+ if (n != 0) {
+ return ERROR_MALFORMED;
+ }
+
+ size_t header_start = 0;
+ size_t header_lenth = 0;
+ for (header_start = 0; header_start < frame.len - 4; header_start++) {
+ if (ntohl(0x000001b3) == *(uint32_t*)((uint8_t*)tmpData.get() + header_start)) {
+ break;
+ }
+ }
+ bool isComplete_csd = false;
+ for (header_lenth = 0; header_lenth < frame.len - 4 - header_start; header_lenth++) {
+ if (ntohl(0x000001b8) == *(uint32_t*)((uint8_t*)tmpData.get()
+ + header_start + header_lenth)) {
+ isComplete_csd = true;
+ break;
+ }
+ }
+ if (!isComplete_csd) {
+ ALOGE("can't parse complete csd for MPEG2!");
+ return ERROR_MALFORMED;
+ }
+ addESDSFromCodecPrivate(trackInfo->mMeta, false,
+ (uint8_t*)(tmpData.get()) + header_start, header_lenth);
+
+ return OK;
+
+}
+
+status_t MatroskaExtractor::synthesizeMPEG4(TrackInfo *trackInfo, size_t index) {
+ ALOGV("synthesizeMPEG4");
+ BlockIterator iter(this, trackInfo->mTrackNum, index);
+ if (iter.eos()) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block *block = iter.block();
+ if (block->GetFrameCount() <= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block::Frame &frame = block->GetFrame(0);
+ auto tmpData = heapbuffer<unsigned char>(frame.len);
+ long n = frame.Read(mReader, tmpData.get());
+ if (n != 0) {
+ return ERROR_MALFORMED;
+ }
+
+ size_t vosend;
+ bool isComplete_csd = false;
+ for (vosend = 0; (long)vosend < frame.len - 4; vosend++) {
+ if (ntohl(0x000001b6) == *(uint32_t*)((uint8_t*)tmpData.get() + vosend)) {
+ isComplete_csd = true;
+ break; // Send VOS until VOP
+ }
+ }
+ if (!isComplete_csd) {
+ ALOGE("can't parse complete csd for MPEG4!");
+ return ERROR_MALFORMED;
+ }
+ addESDSFromCodecPrivate(trackInfo->mMeta, false, tmpData.get(), vosend);
+
+ return OK;
+
+}
+
+
static inline bool isValidInt32ColourValue(long long value) {
return value != mkvparser::Colour::kValueNotPresent
&& value >= INT32_MIN
@@ -1490,6 +1626,8 @@
status_t err = OK;
int32_t nalSize = -1;
+ bool isSetCsdFrom1stFrame = false;
+
switch (track->GetType()) {
case VIDEO_TRACK:
{
@@ -1516,15 +1654,15 @@
continue;
}
} else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
if (codecPrivateSize > 0) {
- AMediaFormat_setString(meta,
- AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
addESDSFromCodecPrivate(
meta, false, codecPrivate, codecPrivateSize);
} else {
ALOGW("%s is detected, but does not have configuration.",
codecID);
- continue;
+ isSetCsdFrom1stFrame = true;
}
} else if (!strcmp("V_VP8", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP8);
@@ -1538,6 +1676,49 @@
}
} else if (!strcmp("V_AV1", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ } else if (!strcmp("V_MPEG2", codecID) || !strcmp("V_MPEG1", codecID)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
+ MEDIA_MIMETYPE_VIDEO_MPEG2);
+ if (codecPrivate != NULL) {
+ addESDSFromCodecPrivate(meta, false, codecPrivate, codecPrivateSize);
+ } else {
+ ALOGW("No specific codec private data, find it from the first frame");
+ isSetCsdFrom1stFrame = true;
+ }
+ } else if (!strcmp("V_MJPEG", codecID)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
+ MEDIA_MIMETYPE_VIDEO_MJPEG);
+ } else if (!strcmp("V_MS/VFW/FOURCC", codecID)) {
+ if (NULL == codecPrivate ||codecPrivateSize < 20) {
+ ALOGE("V_MS/VFW/FOURCC has no valid private data(%p),codecPrivateSize:%zu",
+ codecPrivate, codecPrivateSize);
+ continue;
+ } else {
+ uint32_t fourcc = *(uint32_t *)(codecPrivate + 16);
+ fourcc = ntohl(fourcc);
+ const char* mime = MKVFourCC2MIME(fourcc);
+ ALOGV("V_MS/VFW/FOURCC type is %s", mime);
+ if (!strncasecmp("video/", mime, 6)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
+ } else {
+ ALOGE("V_MS/VFW/FOURCC continue,unsupport video type=%s,fourcc=0x%08x.",
+ mime, fourcc);
+ continue;
+ }
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_XVID) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DIVX) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DIVX3) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
+ isSetCsdFrom1stFrame = true;
+ } else {
+ ALOGW("FourCC have unsupport codec, type=%s,fourcc=0x%08x.",
+ mime, fourcc);
+ continue;
+ }
+ }
} else {
ALOGW("%s is not supported.", codecID);
continue;
@@ -1681,13 +1862,35 @@
initTrackInfo(track, meta, trackInfo);
trackInfo->mNalLengthSize = nalSize;
- if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
+ const char *mimetype = "";
+ AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mimetype);
+
+ if ((!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_AVC) && isSetCsdFrom1stFrame)) {
// Attempt to recover from AVC track without codec private data
err = synthesizeAVCC(trackInfo, n);
if (err != OK) {
mTracks.pop();
}
+ } else if ((!strcmp("V_MPEG2", codecID) && codecPrivateSize == 0) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG2) && isSetCsdFrom1stFrame)) {
+ // Attempt to recover from MPEG2 track without codec private data
+ err = synthesizeMPEG2(trackInfo, n);
+ if (err != OK) {
+ mTracks.pop();
+ }
+ } else if ((!strcmp("V_MPEG4/ISO/ASP", codecID) && codecPrivateSize == 0) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG4) && isSetCsdFrom1stFrame) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_XVID) && isSetCsdFrom1stFrame) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_DIVX) && isSetCsdFrom1stFrame) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_DIVX3) && isSetCsdFrom1stFrame)) {
+ // Attempt to recover from MPEG4 track without codec private data
+ err = synthesizeMPEG4(trackInfo, n);
+ if (err != OK) {
+ mTracks.pop();
+ }
}
+
}
}
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 3871bdf..d53d9e3 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -95,6 +95,8 @@
int64_t mSeekPreRollNs;
status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
+ status_t synthesizeMPEG2(TrackInfo *trackInfo, size_t index);
+ status_t synthesizeMPEG4(TrackInfo *trackInfo, size_t index);
status_t initTrackInfo(
const mkvparser::Track *track,
AMediaFormat *meta,
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 9d1ec1f..52b2765 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -32,6 +32,10 @@
const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX3 = "video/divx3";
+const char *MEDIA_MIMETYPE_VIDEO_XVID = "video/xvid";
+const char *MEDIA_MIMETYPE_VIDEO_MJPEG = "video/x-motion-jpeg";
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index e68852d..007a09b 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -34,6 +34,10 @@
extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX3;
+extern const char *MEDIA_MIMETYPE_VIDEO_XVID;
+extern const char *MEDIA_MIMETYPE_VIDEO_MJPEG;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;