Merge "parse alac in MPEG4Extractor" am: 5692c9a727 am: b86da7f196
am: 1bc4a8634b

Change-Id: Ia175da5504a20c77ad855f9912521e7ec424c508
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 524d02f..7323f43 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -56,6 +56,8 @@
 #define UINT32_MAX       (4294967295U)
 #endif
 
+#define ALAC_SPECIFIC_INFO_SIZE (36)
+
 namespace android {
 
 enum {
@@ -334,6 +336,8 @@
         case FOURCC('t', 'w', 'o', 's'):
         case FOURCC('s', 'o', 'w', 't'):
             return MEDIA_MIMETYPE_AUDIO_RAW;
+        case FOURCC('a', 'l', 'a', 'c'):
+            return MEDIA_MIMETYPE_AUDIO_ALAC;
 
         default:
             ALOGW("Unknown fourcc: %c%c%c%c",
@@ -1124,6 +1128,43 @@
                 mLastTrack->meta.setInt32(kKeyChannelCount, num_channels);
                 mLastTrack->meta.setInt32(kKeySampleRate, sample_rate);
             }
+
+            // If format type is 'alac', it is necessary to get the parameters
+            // from a alac atom spreading behind the frma atom.
+            // See 'external/alac/ALACMagicCookieDescription.txt'.
+            if (original_fourcc == FOURCC('a', 'l', 'a', 'c')) {
+                // Store ALAC magic cookie (decoder needs it).
+                uint8_t alacInfo[12];
+                data_offset = *offset;
+                if (mDataSource->readAt(
+                        data_offset, alacInfo, sizeof(alacInfo)) < (ssize_t)sizeof(alacInfo)) {
+                    return ERROR_IO;
+                }
+                uint32_t size = U32_AT(&alacInfo[0]);
+                if ((size != ALAC_SPECIFIC_INFO_SIZE) ||
+                        (U32_AT(&alacInfo[4]) != FOURCC('a', 'l', 'a', 'c')) ||
+                        (U32_AT(&alacInfo[8]) != 0)) {
+                    return ERROR_MALFORMED;
+                }
+
+                data_offset += sizeof(alacInfo);
+                uint8_t cookie[size - sizeof(alacInfo)];
+                if (mDataSource->readAt(
+                        data_offset, cookie, sizeof(cookie)) < (ssize_t)sizeof(cookie)) {
+                    return ERROR_IO;
+                }
+
+                uint8_t bitsPerSample = cookie[5];
+                mLastTrack->meta.setInt32(kKeyBitsPerSample, bitsPerSample);
+                mLastTrack->meta.setInt32(kKeyChannelCount, cookie[9]);
+                mLastTrack->meta.setInt32(kKeySampleRate, U32_AT(&cookie[20]));
+                mLastTrack->meta.setData(
+                    kKeyAlacMagicCookie, MetaData::TYPE_NONE, cookie, sizeof(cookie));
+
+                // Add the size of ALAC Specific Info (36 bytes) and terminator
+                // atom (8 bytes).
+                *offset += (size + 8);
+            }
             break;
         }
 
@@ -1492,6 +1533,7 @@
         case FOURCC('s', 'a', 'w', 'b'):
         case FOURCC('t', 'w', 'o', 's'):
         case FOURCC('s', 'o', 'w', 't'):
+        case FOURCC('a', 'l', 'a', 'c'):
         {
             if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a')
                     && depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) {
@@ -1574,6 +1616,40 @@
             mLastTrack->meta.setInt32(kKeyChannelCount, num_channels);
             mLastTrack->meta.setInt32(kKeySampleRate, sample_rate);
 
+            if (chunk_type == FOURCC('a', 'l', 'a', 'c')) {
+
+                // See 'external/alac/ALACMagicCookieDescription.txt for the detail'.
+                // Store ALAC magic cookie (decoder needs it).
+                uint8_t alacInfo[12];
+                data_offset += sizeof(buffer);
+                if (mDataSource->readAt(
+                        data_offset, alacInfo, sizeof(alacInfo)) < (ssize_t)sizeof(alacInfo)) {
+                    return ERROR_IO;
+                }
+                uint32_t size = U32_AT(&alacInfo[0]);
+                if ((size != ALAC_SPECIFIC_INFO_SIZE) ||
+                        (U32_AT(&alacInfo[4]) != FOURCC('a', 'l', 'a', 'c')) ||
+                        (U32_AT(&alacInfo[8]) != 0)) {
+                    return ERROR_MALFORMED;
+                }
+                data_offset += sizeof(alacInfo);
+                uint8_t cookie[size - sizeof(alacInfo)];
+                if (mDataSource->readAt(
+                        data_offset, cookie, sizeof(cookie)) < (ssize_t)sizeof(cookie)) {
+                    return ERROR_IO;
+                }
+
+                uint8_t bitsPerSample = cookie[5];
+                mLastTrack->meta.setInt32(kKeyBitsPerSample, bitsPerSample);
+                mLastTrack->meta.setInt32(kKeyChannelCount, cookie[9]);
+                mLastTrack->meta.setInt32(kKeySampleRate, U32_AT(&cookie[20]));
+                mLastTrack->meta.setData(
+                        kKeyAlacMagicCookie, MetaData::TYPE_NONE, cookie, sizeof(cookie));
+                data_offset += sizeof(cookie);
+                *offset = data_offset;
+                CHECK_EQ(*offset, stop_offset);
+            }
+
             while (*offset < stop_offset) {
                 status_t err = parseChunk(offset, depth + 1);
                 if (err != OK) {
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 28b8c2b..eea7cfc 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -221,6 +221,9 @@
     kKeyExifSize         = 'exsz', // int64_t, Exif data size
     kKeyIsExif           = 'exif', // bool (int32_t) buffer contains exif data block
     kKeyPcmBigEndian     = 'pcmb', // bool (int32_t)
+
+    // Key for ALAC Magic Cookie
+    kKeyAlacMagicCookie  = 'almc', // raw data
 };
 
 enum {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 30c4695..3956520 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1204,6 +1204,17 @@
         msg->setBuffer("csd-0", buffer);
 
         parseVp9ProfileLevelFromCsd(buffer, msg);
+    } else if (meta->findData(kKeyAlacMagicCookie, &type, &data, &size)) {
+        ALOGV("convertMetaDataToMessage found kKeyAlacMagicCookie of size %zu\n", size);
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        if (buffer.get() == NULL || buffer->base() == NULL) {
+            return NO_MEMORY;
+        }
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     }
 
     // TODO expose "crypto-key"/kKeyCryptoKey through public api
@@ -1621,6 +1632,8 @@
             if (msg->findBuffer("csd-1", &csd1)) {
                 meta->setData(kKeyVorbisBooks, 0, csd1->data(), csd1->size());
             }
+        } else if (mime == MEDIA_MIMETYPE_AUDIO_ALAC) {
+            meta->setData(kKeyAlacMagicCookie, 0, csd0->data(), csd0->size());
         }
     } else if (mime == MEDIA_MIMETYPE_VIDEO_AVC && msg->findBuffer("csd-avc", &csd0)) {
         meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
@@ -1710,6 +1723,7 @@
     { MEDIA_MIMETYPE_AUDIO_EAC3,        AUDIO_FORMAT_E_AC3},
     { MEDIA_MIMETYPE_AUDIO_AC4,         AUDIO_FORMAT_AC4},
     { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
+    { MEDIA_MIMETYPE_AUDIO_ALAC,        AUDIO_FORMAT_ALAC },
     { 0, AUDIO_FORMAT_INVALID }
 };
 
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 28bb10a..f93ae65 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -52,6 +52,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
 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_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 b165bcb..523378e 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -54,6 +54,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
 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_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;