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;