Support for extracting G.711 a-law and mu-law audio from WAV files and a corresponding software decoder.

Change-Id: I92685d09456c220b8c09842defb721bd55b0b9f6
related-to-bug: 2900021
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/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/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 4f3bffd..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" },
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 39b1b96..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;
diff --git a/media/libstagefright/codecs/g711/Android.mk b/media/libstagefright/codecs/g711/Android.mk
new file mode 100644
index 0000000..2e431205
--- /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/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;