Merge "Support multiple PPS and SPS in avcC box" into gingerbread
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 9cddab2..92ce068 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -34,6 +34,8 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
 extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
 extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
+extern const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW;
+extern const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW;
 extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 6c6949b..010ded1 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -181,6 +181,11 @@
     status_t setupH263EncoderParameters(const sp<MetaData>& meta);
     status_t setupMPEG4EncoderParameters(const sp<MetaData>& meta);
     status_t setupAVCEncoderParameters(const sp<MetaData>& meta);
+    status_t findTargetColorFormat(
+            const sp<MetaData>& meta, OMX_COLOR_FORMATTYPE *colorFormat);
+
+    status_t isColorFormatSupported(
+            OMX_COLOR_FORMATTYPE colorFormat, int portIndex);
 
     // If profile/level is set in the meta data, its value in the meta
     // data will be used; otherwise, the default value will be used.
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 3cdf48a..0f3e245 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -218,7 +218,7 @@
            return mIEffect->disable();
         }
     }
-    return INVALID_OPERATION;
+    return NO_ERROR;
 }
 
 status_t AudioEffect::command(uint32_t cmdCode,
@@ -231,7 +231,22 @@
         return INVALID_OPERATION;
     }
 
-    return mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
+    status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    status = *(status_t *)replyData;
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    if (cmdCode == EFFECT_CMD_ENABLE) {
+        android_atomic_or(1, &mEnabled);
+    }
+    if (cmdCode == EFFECT_CMD_DISABLE) {
+        android_atomic_and(~1, &mEnabled);
+    }
+    return status;
 }
 
 
@@ -347,7 +362,11 @@
 {
     LOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
     if (mStatus == ALREADY_EXISTS) {
-        mEnabled = enabled;
+        if (enabled) {
+            android_atomic_or(1, &mEnabled);
+        } else {
+            android_atomic_and(~1, &mEnabled);
+        }
         if (mCbf) {
             mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
         }
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 9fc1d27..70af2da 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -263,6 +263,7 @@
 
     buffer->set_range(0, frameSize);
     buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 
     mOffset += frameSize;
     mCurrentTimeUs += 20000;  // Each frame is 20ms
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index fb85287..b8b2f3f 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -79,6 +79,7 @@
         libstagefright_httplive \
         libstagefright_rtsp \
         libstagefright_id3 \
+        libstagefright_g711dec \
 
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_amrnb_common \
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 2248e23..4058fbc 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -683,6 +683,7 @@
     buffer->set_range(0, frame_size);
 
     buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 
     mCurrentPos += frame_size;
     mCurrentTimeUs += frame_size * 8000ll / bitrate;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 7cea629..6af3a7f 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -492,7 +492,6 @@
         case FOURCC('m', 'o', 'o', 'f'):
         case FOURCC('t', 'r', 'a', 'f'):
         case FOURCC('m', 'f', 'r', 'a'):
-        case FOURCC('s', 'k', 'i' ,'p'):
         case FOURCC('u', 'd', 't', 'a'):
         case FOURCC('i', 'l', 's', 't'):
         {
@@ -1552,13 +1551,14 @@
     off_t offset;
     size_t size;
     uint32_t dts;
+    bool isSyncSample;
     bool newBuffer = false;
     if (mBuffer == NULL) {
         newBuffer = true;
 
         status_t err =
             mSampleTable->getMetaDataForSample(
-                    mCurrentSampleIndex, &offset, &size, &dts);
+                    mCurrentSampleIndex, &offset, &size, &dts, &isSyncSample);
 
         if (err != OK) {
             return err;
@@ -1595,6 +1595,10 @@
                         kKeyTargetTime, targetSampleTimeUs);
             }
 
+            if (isSyncSample) {
+                mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+            }
+
             ++mCurrentSampleIndex;
         }
 
@@ -1697,6 +1701,10 @@
                     kKeyTargetTime, targetSampleTimeUs);
         }
 
+        if (isSyncSample) {
+            mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+        }
+
         ++mCurrentSampleIndex;
 
         *out = mBuffer;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 39d264c..7648d42 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -32,6 +32,8 @@
 const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
 const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
 const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
+const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
 const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d19fbe5..11396ef 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -26,6 +26,7 @@
 #include "include/AMRWBEncoder.h"
 #include "include/AVCDecoder.h"
 #include "include/AVCEncoder.h"
+#include "include/G711Decoder.h"
 #include "include/M4vH263Decoder.h"
 #include "include/M4vH263Encoder.h"
 #include "include/MP3Decoder.h"
@@ -77,6 +78,7 @@
 FACTORY_CREATE(AMRWBDecoder)
 FACTORY_CREATE(AACDecoder)
 FACTORY_CREATE(AVCDecoder)
+FACTORY_CREATE(G711Decoder)
 FACTORY_CREATE(M4vH263Decoder)
 FACTORY_CREATE(VorbisDecoder)
 FACTORY_CREATE(VPXDecoder)
@@ -124,6 +126,7 @@
         FACTORY_REF(AMRWBDecoder)
         FACTORY_REF(AACDecoder)
         FACTORY_REF(AVCDecoder)
+        FACTORY_REF(G711Decoder)
         FACTORY_REF(M4vH263Decoder)
         FACTORY_REF(VorbisDecoder)
         FACTORY_REF(VPXDecoder)
@@ -155,6 +158,8 @@
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
 //    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
+    { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" },
+    { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
@@ -762,6 +767,65 @@
     }
 }
 
+status_t OMXCodec::findTargetColorFormat(
+        const sp<MetaData>& meta, OMX_COLOR_FORMATTYPE *colorFormat) {
+    LOGV("findTargetColorFormat");
+    CHECK(mIsEncoder);
+
+    *colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+    int32_t targetColorFormat;
+    if (meta->findInt32(kKeyColorFormat, &targetColorFormat)) {
+        *colorFormat = (OMX_COLOR_FORMATTYPE) targetColorFormat;
+    } else {
+        if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
+            *colorFormat = OMX_COLOR_FormatYCbYCr;
+        }
+    }
+
+    // Check whether the target color format is supported.
+    return isColorFormatSupported(*colorFormat, kPortIndexInput);
+}
+
+status_t OMXCodec::isColorFormatSupported(
+        OMX_COLOR_FORMATTYPE colorFormat, int portIndex) {
+    LOGV("isColorFormatSupported: %d", static_cast<int>(colorFormat));
+
+    // Enumerate all the color formats supported by
+    // the omx component to see whether the given
+    // color format is supported.
+    OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+    InitOMXParams(&portFormat);
+    portFormat.nPortIndex = portIndex;
+    OMX_U32 index = 0;
+    portFormat.nIndex = index;
+    while (true) {
+        if (OMX_ErrorNone != mOMX->getParameter(
+                mNode, OMX_IndexParamVideoPortFormat,
+                &portFormat, sizeof(portFormat))) {
+
+            return UNKNOWN_ERROR;
+        }
+        // Make sure that omx component does not overwrite
+        // the incremented index (bug 2897413).
+        CHECK_EQ(index, portFormat.nIndex);
+        if ((portFormat.eColorFormat == colorFormat)) {
+            LOGV("Found supported color format: %d", portFormat.eColorFormat);
+            return OK;  // colorFormat is supported!
+        }
+        ++index;
+        portFormat.nIndex = index;
+
+        // OMX Spec defines less than 50 color formats
+        // 1000 is more than enough for us to tell whether the omx
+        // component in question is buggy or not.
+        if (index >= 1000) {
+            LOGE("More than %ld color formats are supported???", index);
+            break;
+        }
+    }
+    return UNKNOWN_ERROR;
+}
+
 void OMXCodec::setVideoInputFormat(
         const char *mime, const sp<MetaData>& meta) {
 
@@ -787,10 +851,8 @@
         CHECK(!"Should not be here. Not a supported video mime type.");
     }
 
-    OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
-    if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
-        colorFormat = OMX_COLOR_FormatYCbYCr;
-    }
+    OMX_COLOR_FORMATTYPE colorFormat;
+    CHECK_EQ(OK, findTargetColorFormat(meta, &colorFormat));
 
     status_t err;
     OMX_PARAM_PORTDEFINITIONTYPE def;
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 641a876..b699d8f 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -181,6 +181,8 @@
     }
 #endif
 
+    packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+
     *out = packet;
 
     return OK;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 2e62f9f..27faf4f 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -55,6 +55,8 @@
       mTimeToSample(NULL),
       mSyncSampleOffset(-1),
       mNumSyncSamples(0),
+      mSyncSamples(NULL),
+      mLastSyncSampleIndex(0),
       mSampleToChunkEntries(NULL) {
     mSampleIterator = new SampleIterator(this);
 }
@@ -63,6 +65,9 @@
     delete[] mSampleToChunkEntries;
     mSampleToChunkEntries = NULL;
 
+    delete[] mSyncSamples;
+    mSyncSamples = NULL;
+
     delete[] mTimeToSample;
     mTimeToSample = NULL;
 
@@ -278,6 +283,18 @@
     if (mNumSyncSamples < 2) {
         LOGW("Table of sync samples is empty or has only a single entry!");
     }
+
+    mSyncSamples = new uint32_t[mNumSyncSamples];
+    size_t size = mNumSyncSamples * sizeof(uint32_t);
+    if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
+            != (ssize_t)size) {
+        return ERROR_IO;
+    }
+
+    for (size_t i = 0; i < mNumSyncSamples; ++i) {
+        mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
+    }
+
     return OK;
 }
 
@@ -394,14 +411,7 @@
 
     uint32_t left = 0;
     while (left < mNumSyncSamples) {
-        uint32_t x;
-        if (mDataSource->readAt(
-                    mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
-            return ERROR_IO;
-        }
-
-        x = ntohl(x);
-        --x;
+        uint32_t x = mSyncSamples[left];
 
         if (x >= start_sample_index) {
             break;
@@ -421,14 +431,7 @@
     --x;
 
     if (left + 1 < mNumSyncSamples) {
-        uint32_t y;
-        if (mDataSource->readAt(
-                    mSyncSampleOffset + 8 + (left + 1) * 4, &y, 4) != 4) {
-            return ERROR_IO;
-        }
-
-        y = ntohl(y);
-        --y;
+        uint32_t y = mSyncSamples[left + 1];
 
         // our sample lies between sync samples x and y.
 
@@ -486,13 +489,7 @@
                     return ERROR_OUT_OF_RANGE;
                 }
 
-                if (mDataSource->readAt(
-                            mSyncSampleOffset + 8 + (left + 1) * 4, &x, 4) != 4) {
-                    return ERROR_IO;
-                }
-
-                x = ntohl(x);
-                --x;
+                x = mSyncSamples[left + 1];
 
                 CHECK(x >= start_sample_index);
             }
@@ -532,13 +529,7 @@
     }
 
     for (size_t i = 0; i < numSamplesToScan; ++i) {
-        uint32_t x;
-        if (mDataSource->readAt(
-                    mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
-            return ERROR_IO;
-        }
-        x = ntohl(x);
-        --x;
+        uint32_t x = mSyncSamples[i];
 
         // Now x is a sample index.
         size_t sampleSize;
@@ -568,7 +559,8 @@
         uint32_t sampleIndex,
         off_t *offset,
         size_t *size,
-        uint32_t *decodingTime) {
+        uint32_t *decodingTime,
+        bool *isSyncSample) {
     Mutex::Autolock autoLock(mLock);
 
     status_t err;
@@ -588,6 +580,28 @@
         *decodingTime = mSampleIterator->getSampleTime();
     }
 
+    if (isSyncSample) {
+        *isSyncSample = false;
+        if (mSyncSampleOffset < 0) {
+            // Every sample is a sync sample.
+            *isSyncSample = true;
+        } else {
+            size_t i = (mLastSyncSampleIndex < mNumSyncSamples)
+                    && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)
+                ? mLastSyncSampleIndex : 0;
+
+            while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {
+                ++i;
+            }
+
+            if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {
+                *isSyncSample = true;
+            }
+
+            mLastSyncSampleIndex = i;
+        }
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 7c2b07e..8d820c0 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -31,7 +31,11 @@
 
 namespace android {
 
-static uint16_t WAVE_FORMAT_PCM = 1;
+enum {
+    WAVE_FORMAT_PCM = 1,
+    WAVE_FORMAT_ALAW = 6,
+    WAVE_FORMAT_MULAW = 7,
+};
 
 static uint32_t U32_LE_AT(const uint8_t *ptr) {
     return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
@@ -45,6 +49,7 @@
     WAVSource(
             const sp<DataSource> &dataSource,
             const sp<MetaData> &meta,
+            uint16_t waveFormat,
             int32_t bitsPerSample,
             off_t offset, size_t size);
 
@@ -63,6 +68,7 @@
 
     sp<DataSource> mDataSource;
     sp<MetaData> mMeta;
+    uint16_t mWaveFormat;
     int32_t mSampleRate;
     int32_t mNumChannels;
     int32_t mBitsPerSample;
@@ -108,7 +114,7 @@
 
     return new WAVSource(
             mDataSource, mTrackMeta,
-            mBitsPerSample, mDataOffset, mDataSize);
+            mWaveFormat, mBitsPerSample, mDataOffset, mDataSize);
 }
 
 sp<MetaData> WAVExtractor::getTrackMetaData(
@@ -160,8 +166,10 @@
                 return NO_INIT;
             }
 
-            uint16_t format = U16_LE_AT(formatSpec);
-            if (format != WAVE_FORMAT_PCM) {
+            mWaveFormat = U16_LE_AT(formatSpec);
+            if (mWaveFormat != WAVE_FORMAT_PCM
+                    && mWaveFormat != WAVE_FORMAT_ALAW
+                    && mWaveFormat != WAVE_FORMAT_MULAW) {
                 return ERROR_UNSUPPORTED;
             }
 
@@ -178,9 +186,17 @@
 
             mBitsPerSample = U16_LE_AT(&formatSpec[14]);
 
-            if (mBitsPerSample != 8 && mBitsPerSample != 16
-                && mBitsPerSample != 24) {
-                return ERROR_UNSUPPORTED;
+            if (mWaveFormat == WAVE_FORMAT_PCM) {
+                if (mBitsPerSample != 8 && mBitsPerSample != 16
+                    && mBitsPerSample != 24) {
+                    return ERROR_UNSUPPORTED;
+                }
+            } else {
+                CHECK(mWaveFormat == WAVE_FORMAT_MULAW
+                        || mWaveFormat == WAVE_FORMAT_ALAW);
+                if (mBitsPerSample != 8) {
+                    return ERROR_UNSUPPORTED;
+                }
             }
 
             mValidFormat = true;
@@ -190,7 +206,23 @@
                 mDataSize = chunkSize;
 
                 mTrackMeta = new MetaData;
-                mTrackMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+
+                switch (mWaveFormat) {
+                    case WAVE_FORMAT_PCM:
+                        mTrackMeta->setCString(
+                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+                        break;
+                    case WAVE_FORMAT_ALAW:
+                        mTrackMeta->setCString(
+                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
+                        break;
+                    default:
+                        CHECK_EQ(mWaveFormat, WAVE_FORMAT_MULAW);
+                        mTrackMeta->setCString(
+                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
+                        break;
+                }
+
                 mTrackMeta->setInt32(kKeyChannelCount, mNumChannels);
                 mTrackMeta->setInt32(kKeySampleRate, mSampleRate);
 
@@ -217,10 +249,12 @@
 WAVSource::WAVSource(
         const sp<DataSource> &dataSource,
         const sp<MetaData> &meta,
+        uint16_t waveFormat,
         int32_t bitsPerSample,
         off_t offset, size_t size)
     : mDataSource(dataSource),
       mMeta(meta),
+      mWaveFormat(waveFormat),
       mSampleRate(0),
       mNumChannels(0),
       mBitsPerSample(bitsPerSample),
@@ -312,43 +346,45 @@
 
     buffer->set_range(0, n);
 
-    if (mBitsPerSample == 8) {
-        // Convert 8-bit unsigned samples to 16-bit signed.
+    if (mWaveFormat == WAVE_FORMAT_PCM) {
+        if (mBitsPerSample == 8) {
+            // Convert 8-bit unsigned samples to 16-bit signed.
 
-        MediaBuffer *tmp;
-        CHECK_EQ(mGroup->acquire_buffer(&tmp), OK);
+            MediaBuffer *tmp;
+            CHECK_EQ(mGroup->acquire_buffer(&tmp), OK);
 
-        // The new buffer holds the sample number of samples, but each
-        // one is 2 bytes wide.
-        tmp->set_range(0, 2 * n);
+            // The new buffer holds the sample number of samples, but each
+            // one is 2 bytes wide.
+            tmp->set_range(0, 2 * n);
 
-        int16_t *dst = (int16_t *)tmp->data();
-        const uint8_t *src = (const uint8_t *)buffer->data();
-        while (n-- > 0) {
-            *dst++ = ((int16_t)(*src) - 128) * 256;
-            ++src;
+            int16_t *dst = (int16_t *)tmp->data();
+            const uint8_t *src = (const uint8_t *)buffer->data();
+            while (n-- > 0) {
+                *dst++ = ((int16_t)(*src) - 128) * 256;
+                ++src;
+            }
+
+            buffer->release();
+            buffer = tmp;
+        } else if (mBitsPerSample == 24) {
+            // Convert 24-bit signed samples to 16-bit signed.
+
+            const uint8_t *src =
+                (const uint8_t *)buffer->data() + buffer->range_offset();
+            int16_t *dst = (int16_t *)src;
+
+            size_t numSamples = buffer->range_length() / 3;
+            for (size_t i = 0; i < numSamples; ++i) {
+                int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16);
+                x = (x << 8) >> 8;  // sign extension
+
+                x = x >> 8;
+                *dst++ = (int16_t)x;
+                src += 3;
+            }
+
+            buffer->set_range(buffer->range_offset(), 2 * numSamples);
         }
-
-        buffer->release();
-        buffer = tmp;
-    } else if (mBitsPerSample == 24) {
-        // Convert 24-bit signed samples to 16-bit signed.
-
-        const uint8_t *src =
-            (const uint8_t *)buffer->data() + buffer->range_offset();
-        int16_t *dst = (int16_t *)src;
-
-        size_t numSamples = buffer->range_length() / 3;
-        for (size_t i = 0; i < numSamples; ++i) {
-            int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16);
-            x = (x << 8) >> 8;  // sign extension
-
-            x = x >> 8;
-            *dst++ = (int16_t)x;
-            src += 3;
-        }
-
-        buffer->set_range(buffer->range_offset(), 2 * numSamples);
     }
 
     size_t bytesPerSample = mBitsPerSample >> 3;
@@ -358,6 +394,7 @@
             1000000LL * (mCurrentPos - mOffset)
                 / (mNumChannels * bytesPerSample) / mSampleRate);
 
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 
     *out = buffer;
 
diff --git a/media/libstagefright/codecs/g711/Android.mk b/media/libstagefright/codecs/g711/Android.mk
new file mode 100644
index 0000000..2e43120
--- /dev/null
+++ b/media/libstagefright/codecs/g711/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
new file mode 100644
index 0000000..cfb9fe4
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    G711Decoder.cpp
+
+LOCAL_C_INCLUDES := \
+        frameworks/base/media/libstagefright/include \
+
+LOCAL_MODULE := libstagefright_g711dec
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp b/media/libstagefright/codecs/g711/dec/G711Decoder.cpp
new file mode 100644
index 0000000..4414e4e
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/G711Decoder.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "G711Decoder"
+#include <utils/Log.h>
+
+#include "G711Decoder.h"
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+static const size_t kMaxNumSamplesPerFrame = 16384;
+
+namespace android {
+
+G711Decoder::G711Decoder(const sp<MediaSource> &source)
+    : mSource(source),
+      mStarted(false),
+      mBufferGroup(NULL) {
+}
+
+G711Decoder::~G711Decoder() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t G711Decoder::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    mIsMLaw = false;
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {
+        mIsMLaw = true;
+    } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    mBufferGroup = new MediaBufferGroup;
+    mBufferGroup->add_buffer(
+            new MediaBuffer(kMaxNumSamplesPerFrame * sizeof(int16_t)));
+
+    mSource->start();
+
+    mStarted = true;
+
+    return OK;
+}
+
+status_t G711Decoder::stop() {
+    CHECK(mStarted);
+
+    delete mBufferGroup;
+    mBufferGroup = NULL;
+
+    mSource->stop();
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> G711Decoder::getFormat() {
+    sp<MetaData> srcFormat = mSource->getFormat();
+
+    int32_t numChannels;
+    int32_t sampleRate;
+
+    CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
+    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+    meta->setInt32(kKeyChannelCount, numChannels);
+    meta->setInt32(kKeySampleRate, sampleRate);
+
+    int64_t durationUs;
+    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+        meta->setInt64(kKeyDuration, durationUs);
+    }
+
+    meta->setCString(kKeyDecoderComponent, "G711Decoder");
+
+    return meta;
+}
+
+status_t G711Decoder::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    status_t err;
+
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        CHECK(seekTimeUs >= 0);
+    } else {
+        seekTimeUs = -1;
+    }
+
+    MediaBuffer *inBuffer;
+    err = mSource->read(&inBuffer, options);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (inBuffer->range_length() > kMaxNumSamplesPerFrame) {
+        LOGE("input buffer too large (%d).", inBuffer->range_length());
+
+        inBuffer->release();
+        inBuffer = NULL;
+
+        return ERROR_UNSUPPORTED;
+    }
+
+    int64_t timeUs;
+    CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
+    const uint8_t *inputPtr =
+        (const uint8_t *)inBuffer->data() + inBuffer->range_offset();
+
+    MediaBuffer *outBuffer;
+    CHECK_EQ(mBufferGroup->acquire_buffer(&outBuffer), OK);
+
+    if (mIsMLaw) {
+        DecodeMLaw(
+                static_cast<int16_t *>(outBuffer->data()),
+                inputPtr, inBuffer->range_length());
+    } else {
+        DecodeALaw(
+                static_cast<int16_t *>(outBuffer->data()),
+                inputPtr, inBuffer->range_length());
+    }
+
+    // Each 8-bit byte is converted into a 16-bit sample.
+    outBuffer->set_range(0, inBuffer->range_length() * 2);
+
+    outBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+    inBuffer->release();
+    inBuffer = NULL;
+
+    *out = outBuffer;
+
+    return OK;
+}
+
+// static
+void G711Decoder::DecodeALaw(
+        int16_t *out, const uint8_t *in, size_t inSize) {
+    while (inSize-- > 0) {
+        int32_t x = *in++;
+
+        int32_t ix = x ^ 0x55;
+        ix &= 0x7f;
+
+        int32_t iexp = ix >> 4;
+        int32_t mant = ix & 0x0f;
+
+        if (iexp > 0) {
+            mant += 16;
+        }
+
+        mant = (mant << 4) + 8;
+
+        if (iexp > 1) {
+            mant = mant << (iexp - 1);
+        }
+
+        *out++ = (x > 127) ? mant : -mant;
+    }
+}
+
+// static
+void G711Decoder::DecodeMLaw(
+        int16_t *out, const uint8_t *in, size_t inSize) {
+    while (inSize-- > 0) {
+        int32_t x = *in++;
+
+        int32_t mantissa = ~x;
+        int32_t exponent = (mantissa >> 4) & 7;
+        int32_t segment = exponent + 1;
+        mantissa &= 0x0f;
+
+        int32_t step = 4 << segment;
+
+        int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+
+        *out++ = (x < 0x80) ? -abs : abs;
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/G711Decoder.h b/media/libstagefright/include/G711Decoder.h
new file mode 100644
index 0000000..8b5143a
--- /dev/null
+++ b/media/libstagefright/include/G711Decoder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef G711_DECODER_H_
+
+#define G711_DECODER_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+struct MediaBufferGroup;
+
+struct G711Decoder : public MediaSource {
+    G711Decoder(const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+    virtual ~G711Decoder();
+
+private:
+    sp<MediaSource> mSource;
+    bool mStarted;
+    bool mIsMLaw;
+
+    MediaBufferGroup *mBufferGroup;
+
+    static void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
+    static void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
+
+    G711Decoder(const G711Decoder &);
+    G711Decoder &operator=(const G711Decoder &);
+};
+
+}  // namespace android
+
+#endif  // G711_DECODER_H_
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index a2b2c99..f830690 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -60,7 +60,8 @@
             uint32_t sampleIndex,
             off_t *offset,
             size_t *size,
-            uint32_t *decodingTime);
+            uint32_t *decodingTime,
+            bool *isSyncSample = NULL);
 
     enum {
         kFlagBefore,
@@ -105,6 +106,8 @@
 
     off_t mSyncSampleOffset;
     uint32_t mNumSyncSamples;
+    uint32_t *mSyncSamples;
+    size_t mLastSyncSampleIndex;
 
     SampleIterator *mSampleIterator;
 
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 9384942..3e847b9 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -43,6 +43,7 @@
     sp<DataSource> mDataSource;
     status_t mInitCheck;
     bool mValidFormat;
+    uint16_t mWaveFormat;
     uint16_t mNumChannels;
     uint32_t mSampleRate;
     uint16_t mBitsPerSample;
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 3739be1..71f6587 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -296,6 +296,7 @@
 
     MediaBuffer *buffer = new MediaBuffer(size + 2);
     buffer->meta_data()->setInt64(kKeyTime, timeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
     long res = block->Read(
             mExtractor->mReader, (unsigned char *)buffer->data() + 2);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 252b42a..1c7faa4 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1696,7 +1696,10 @@
     // Delegate master volume control to effect in output mix effect chain if needed
     sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX);
     if (chain != 0) {
-        uint32_t v = (uint32_t)(masterVolume * (1 << 24));
+        uint32_t v = 0;
+        if (!masterMute) {
+            v = (uint32_t)(masterVolume * (1 << 24));
+        }
         chain->setVolume_l(&v, &v);
         masterVolume = (float)((v + (1 << 23)) >> 24);
         chain.clear();
@@ -1750,7 +1753,7 @@
 
             // compute volume for this track
             int16_t left, right, aux;
-            if (track->isMuted() || masterMute || track->isPausing() ||
+            if (track->isMuted() || track->isPausing() ||
                 mStreamTypes[track->type()].mute) {
                 left = right = aux = 0;
                 if (track->isPausing()) {
@@ -5351,7 +5354,7 @@
         return;
     }
 
-    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) {
+    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED || mState == RESTART) {
         // do 32 bit to 16 bit conversion for auxiliary effect input buffer
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -6032,8 +6035,8 @@
 AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
                                         int sessionId)
     : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mOwnInBuffer(false),
-            mVolumeCtrlIdx(-1), mLeftVolume(0), mRightVolume(0),
-            mNewLeftVolume(0), mNewRightVolume(0)
+            mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+            mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
 }