Merge "mkv support more audio codec" into qt-dev
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index e284cda..a1c81f3 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -150,6 +150,7 @@
         AAC,
         HEVC,
         MP3,
+        PCM,
         OTHER
     };
 
@@ -270,6 +271,8 @@
         mType = AAC;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
         mType = MP3;
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+        mType = PCM;
     }
 }
 
@@ -1054,6 +1057,27 @@
                     AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
         }
 
+        if (mType == PCM) {
+            int32_t bitPerFrame = 16;
+            int32_t bigEndian = 0;
+            AMediaFormat *meta = AMediaFormat_new();
+            if (getFormat(meta) == AMEDIA_OK && meta != NULL) {
+                AMediaFormat_getInt32(meta,
+                                AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &bitPerFrame);
+                AMediaFormat_getInt32(meta,
+                                AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, &bigEndian);
+            }
+            AMediaFormat_delete(meta);
+            if (bigEndian == 1 && bitPerFrame == 16) {
+                // Big-endian -> little-endian
+                uint16_t *dstData = (uint16_t *)frame->data() + frame->range_offset();
+                uint16_t *srcData = (uint16_t *)frame->data() + frame->range_offset();
+                for (size_t i = 0; i < frame->range_length() / 2; i++) {
+                    dstData[i] = ntohs(srcData[i]);
+                }
+            }
+        }
+
         *out = frame;
 
         return AMEDIA_OK;
@@ -1170,6 +1194,51 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+enum WaveID {
+    MKV_RIFF_WAVE_FORMAT_PCM = 0x0001,
+    MKV_RIFF_WAVE_FORMAT_ADPCM_ms = 0x0002,
+    MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav = 0x0011,
+    MKV_RIFF_WAVE_FORMAT_MPEGL12 = 0x0050,
+    MKV_RIFF_WAVE_FORMAT_MPEGL3 = 0x0055,
+    MKV_RIFF_WAVE_FORMAT_WMAV1 = 0x0160,
+    MKV_RIFF_WAVE_FORMAT_WMAV2 = 0x0161,
+};
+
+static const char *MKVWave2MIME(uint16_t id) {
+    switch (id) {
+        case  MKV_RIFF_WAVE_FORMAT_MPEGL12:
+            return MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
+
+        case  MKV_RIFF_WAVE_FORMAT_MPEGL3:
+            return MEDIA_MIMETYPE_AUDIO_MPEG;
+
+        case MKV_RIFF_WAVE_FORMAT_PCM:
+            return MEDIA_MIMETYPE_AUDIO_RAW;
+
+        case MKV_RIFF_WAVE_FORMAT_ADPCM_ms:
+            return MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
+        case MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav:
+            return MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;
+
+        case MKV_RIFF_WAVE_FORMAT_WMAV1:
+        case MKV_RIFF_WAVE_FORMAT_WMAV2:
+            return MEDIA_MIMETYPE_AUDIO_WMA;
+        default:
+            ALOGW("unknown wave %x", id);
+            return "";
+    };
+}
+
+static bool isMkvAudioCsdSizeOK(const char* mime, size_t csdSize) {
+    if ((!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) && csdSize < 50) ||
+        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) && csdSize < 20) ||
+        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA) && csdSize < 28) ||
+        (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) && csdSize < 30)) {
+        return false;
+    }
+    return true;
+}
+
 // trans all FOURCC  to lower char
 static uint32_t FourCCtoLower(uint32_t fourcc) {
     uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
@@ -2036,20 +2105,40 @@
                 } else if (!strcmp("A_FLAC", codecID)) {
                     AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
                     err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("A_MPEG/L2", codecID)) {
+                    AMediaFormat_setString(meta,
+                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+                } else if (!strcmp("A_PCM/INT/LIT", codecID) ||
+                         !strcmp("A_PCM/INT/BIG", codecID)) {
+                    AMediaFormat_setString(meta,
+                            AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+                    int32_t bigEndian = !strcmp("A_PCM/INT/BIG", codecID) ? 1: 0;
+                    AMediaFormat_setInt32(meta,
+                            AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, bigEndian);
                 } else if ((!strcmp("A_MS/ACM", codecID))) {
-                    if ((NULL == codecPrivate) || (codecPrivateSize < 30)) {
+                    if ((NULL == codecPrivate) || (codecPrivateSize < 18)) {
                         ALOGW("unsupported audio: A_MS/ACM has no valid private data: %s, size: %zu",
                                codecPrivate == NULL ? "null" : "non-null", codecPrivateSize);
                         continue;
                     } else {
                         uint16_t ID = *(uint16_t *)codecPrivate;
-                        if (ID == 0x0055) {
-                            AMediaFormat_setString(meta,
-                                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
+                        const char* mime = MKVWave2MIME(ID);
+                        ALOGV("A_MS/ACM type is %s", mime);
+                        if (!strncasecmp("audio/", mime, 6) &&
+                                isMkvAudioCsdSizeOK(mime, codecPrivateSize)) {
+                            AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
                         } else {
-                            ALOGW("A_MS/ACM unsupported type , continue");
+                            ALOGE("A_MS/ACM continue, unsupported audio type=%s, csdSize:%zu",
+                                mime, codecPrivateSize);
                             continue;
                         }
+                        if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA)) {
+                            addESDSFromCodecPrivate(meta, true, codecPrivate, codecPrivateSize);
+                        } else if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) ||
+                                    !strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM)) {
+                            uint32_t blockAlign = *(uint16_t*)(codecPrivate + 12);
+                            addESDSFromCodecPrivate(meta, true, &blockAlign, sizeof(blockAlign));
+                        }
                     }
                 } else {
                     ALOGW("%s is not supported.", codecID);
@@ -2058,6 +2147,7 @@
 
                 AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, atrack->GetSamplingRate());
                 AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, atrack->GetChannels());
+                AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, atrack->GetBitDepth());
                 break;
             }
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index c7b2719..537e4c0 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1756,7 +1756,11 @@
                 size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
                 meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
             }
-        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
+        } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC ||
+                mime == MEDIA_MIMETYPE_VIDEO_MPEG4 ||
+                mime == MEDIA_MIMETYPE_AUDIO_WMA ||
+                mime == MEDIA_MIMETYPE_AUDIO_MS_ADPCM ||
+                mime == MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) {
             std::vector<char> esds(csd0size + 31);
             // The written ESDS is actually for an audio stream, but it's enough
             // for transporting the CSD to muxers.
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 52b2765..a08fed1 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -59,6 +59,10 @@
 const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
 const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
 const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
+const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM = "audio/x-adpcm-ms";
+const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM = "audio/x-adpcm-dvi-ima";
+
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 007a09b..1f9e636 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -61,6 +61,10 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
 extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
 extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
+extern const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
+extern const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;
+
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;