Merge "Parse mp3 encoder padding/delay"
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8b4b8ed..00b8679 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -70,6 +70,8 @@
     kKeyThumbnailTime     = 'thbT',  // int64_t (usecs)
     kKeyTrackID           = 'trID',
     kKeyIsDRM             = 'idrm',  // int32_t (bool)
+    kKeyEncoderDelay      = 'encd',  // int32_t (frames)
+    kKeyEncoderPadding    = 'encp',  // int32_t (frames)
 
     kKeyAlbum             = 'albu',  // cstring
     kKeyArtist            = 'arti',  // cstring
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 69209b5..1886050 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -311,10 +311,18 @@
     mMeta->setInt32(kKeyBitRate, bitrate * 1000);
     mMeta->setInt32(kKeyChannelCount, num_channels);
 
-    mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
+    sp<XINGSeeker> seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
 
-    if (mSeeker == NULL) {
+    if (seeker == NULL) {
         mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
+    } else {
+        mSeeker = seeker;
+        int encd = seeker->getEncoderDelay();
+        int encp = seeker->getEncoderPadding();
+        if (encd != 0 || encp != 0) {
+            mMeta->setInt32(kKeyEncoderDelay, encd);
+            mMeta->setInt32(kKeyEncoderPadding, encp);
+        }
     }
 
     if (mSeeker != NULL) {
@@ -547,6 +555,33 @@
         return meta;
     }
 
+    ID3::Iterator *com = new ID3::Iterator(id3, "COM");
+    if (com->done()) {
+        delete com;
+        com = new ID3::Iterator(id3, "COMM");
+    }
+    while(!com->done()) {
+        String8 commentdesc;
+        String8 commentvalue;
+        com->getString(&commentdesc, &commentvalue);
+        const char * desc = commentdesc.string();
+        const char * value = commentvalue.string();
+
+        // first 3 characters are the language, which we don't care about
+        if(strlen(desc) > 3 && strcmp(desc + 3, "iTunSMPB") == 0) {
+
+            int32_t delay, padding;
+            if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
+                mMeta->setInt32(kKeyEncoderDelay, delay);
+                mMeta->setInt32(kKeyEncoderPadding, padding);
+            }
+            break;
+        }
+        com->next();
+    }
+    delete com;
+    com = NULL;
+
     struct Map {
         int key;
         const char *tag1;
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
index 8c99c76..9c91134 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "XINGSEEKER"
+#include <utils/Log.h>
+
 #include "include/XINGSeeker.h"
 #include "include/avc_utils.h"
 
@@ -24,7 +27,9 @@
 
 XINGSeeker::XINGSeeker()
     : mDurationUs(-1),
-      mSizeBytes(0) {
+      mSizeBytes(0),
+      mEncoderDelay(0),
+      mEncoderPadding(0) {
 }
 
 bool XINGSeeker::getDuration(int64_t *durationUs) {
@@ -76,8 +81,6 @@
 
     seeker->mFirstFramePos = first_frame_pos;
 
-    ALOGI("xingseeker first frame pos: %lld", first_frame_pos);
-
     seeker->mSizeBytes = 0;
     seeker->mTOCValid = false;
     seeker->mDurationUs = 0;
@@ -111,6 +114,8 @@
         else offset += 9;
     }
 
+    int xingbase = offset;
+
     if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
         return NULL;
     }
@@ -161,10 +166,31 @@
         // do something with the quality indicator
         offset += 4;
     }
+
+    if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags
+        return false;
+    }
+
+    ALOGV("nogap preceding: %s, nogap continued in next: %s",
+              (buffer[0] & 0x80) ? "true" : "false",
+              (buffer[0] & 0x40) ? "true" : "false");
 #endif
 
+    if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) {
+        seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4);
+        seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2];
+    }
+
     return seeker;
 }
 
+int32_t XINGSeeker::getEncoderDelay() {
+    return mEncoderDelay;
+}
+
+int32_t XINGSeeker::getEncoderPadding() {
+    return mEncoderPadding;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 2e92926..ca14054 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -463,40 +463,65 @@
     tmp = NULL;
 }
 
-void ID3::Iterator::getString(String8 *id) const {
+// the 2nd argument is used to get the data following the \0 in a comment field
+void ID3::Iterator::getString(String8 *id, String8 *comment) const {
+    getstring(id, false);
+    if (comment != NULL) {
+        getstring(comment, true);
+    }
+}
+
+// comment fields (COM/COMM) contain an initial short descriptor, followed by \0,
+// followed by more data. The data following the \0 can be retrieved by setting
+// "otherdata" to true.
+void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
     id->setTo("");
 
-    if (mFrameData == NULL) {
+    const uint8_t *frameData = mFrameData;
+    if (frameData == NULL) {
         return;
     }
 
+    uint8_t encoding = *frameData;
+
     if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
         if (mOffset == 126 || mOffset == 127) {
             // Special treatment for the track number and genre.
             char tmp[16];
-            sprintf(tmp, "%d", (int)*mFrameData);
+            sprintf(tmp, "%d", (int)*frameData);
 
             id->setTo(tmp);
             return;
         }
 
-        convertISO8859ToString8(mFrameData, mFrameSize, id);
+        convertISO8859ToString8(frameData, mFrameSize, id);
         return;
     }
 
     size_t n = mFrameSize - getHeaderLength() - 1;
+    if (otherdata) {
+        // skip past the encoding, language, and the 0 separator
+        frameData += 4;
+        int32_t i = n - 4;
+        while(--i >= 0 && *++frameData != 0) ;
+        int skipped = (frameData - mFrameData);
+        if (skipped >= n) {
+            return;
+        }
+        n -= skipped;
+    }
 
-    if (*mFrameData == 0x00) {
+    if (encoding == 0x00) {
         // ISO 8859-1
-        convertISO8859ToString8(mFrameData + 1, n, id);
-    } else if (*mFrameData == 0x03) {
+        convertISO8859ToString8(frameData + 1, n, id);
+    } else if (encoding == 0x03) {
         // UTF-8
-        id->setTo((const char *)(mFrameData + 1), n);
-    } else if (*mFrameData == 0x02) {
+        id->setTo((const char *)(frameData + 1), n);
+    } else if (encoding == 0x02) {
         // UTF-16 BE, no byte order mark.
         // API wants number of characters, not number of bytes...
         int len = n / 2;
-        const char16_t *framedata = (const char16_t *) (mFrameData + 1);
+        const char16_t *framedata = (const char16_t *) (frameData + 1);
         char16_t *framedatacopy = NULL;
 #if BYTE_ORDER == LITTLE_ENDIAN
         framedatacopy = new char16_t[len];
@@ -513,7 +538,7 @@
         // UCS-2
         // API wants number of characters, not number of bytes...
         int len = n / 2;
-        const char16_t *framedata = (const char16_t *) (mFrameData + 1);
+        const char16_t *framedata = (const char16_t *) (frameData + 1);
         char16_t *framedatacopy = NULL;
         if (*framedata == 0xfffe) {
             // endianness marker doesn't match host endianness, convert
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 98c82a4..8714008 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -50,7 +50,7 @@
 
         bool done() const;
         void getID(String8 *id) const;
-        void getString(String8 *s) const;
+        void getString(String8 *s, String8 *ss = NULL) const;
         const uint8_t *getData(size_t *length) const;
         void next();
 
@@ -65,6 +65,7 @@
         void findFrame();
 
         size_t getHeaderLength() const;
+        void getstring(String8 *s, bool secondhalf) const;
 
         Iterator(const Iterator &);
         Iterator &operator=(const Iterator &);
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/libstagefright/include/XINGSeeker.h
index 8510979..c408576 100644
--- a/media/libstagefright/include/XINGSeeker.h
+++ b/media/libstagefright/include/XINGSeeker.h
@@ -31,10 +31,15 @@
     virtual bool getDuration(int64_t *durationUs);
     virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
 
+    virtual int32_t getEncoderDelay();
+    virtual int32_t getEncoderPadding();
+
 private:
     int64_t mFirstFramePos;
     int64_t mDurationUs;
     int32_t mSizeBytes;
+    int32_t mEncoderDelay;
+    int32_t mEncoderPadding;
 
     // TOC entries in XING header. Skip the first one since it's always 0.
     unsigned char mTOC[99];