Adds support for 8-bit (unsigned) PCM wave files.

related-to-bug: 2382428
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 959a767..da8fe79 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -44,7 +44,8 @@
 struct WAVSource : public MediaSource {
     WAVSource(
             const sp<DataSource> &dataSource,
-            int32_t sampleRate, int32_t numChannels,
+            const sp<MetaData> &meta,
+            int32_t bitsPerSample,
             off_t offset, size_t size);
 
     virtual status_t start(MetaData *params = NULL);
@@ -61,8 +62,10 @@
     static const size_t kMaxFrameSize;
 
     sp<DataSource> mDataSource;
+    sp<MetaData> mMeta;
     int32_t mSampleRate;
     int32_t mNumChannels;
+    int32_t mBitsPerSample;
     off_t mOffset;
     size_t mSize;
     bool mStarted;
@@ -104,7 +107,8 @@
     }
 
     return new WAVSource(
-            mDataSource, mSampleRate, mNumChannels, mDataOffset, mDataSize);
+            mDataSource, mTrackMeta,
+            mBitsPerSample, mDataOffset, mDataSize);
 }
 
 sp<MetaData> WAVExtractor::getTrackMetaData(
@@ -113,17 +117,7 @@
         return NULL;
     }
 
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-    meta->setInt32(kKeyChannelCount, mNumChannels);
-    meta->setInt32(kKeySampleRate, mSampleRate);
-
-    int64_t durationUs =
-        1000000LL * (mDataSize / (mNumChannels * 2)) / mSampleRate;
-
-    meta->setInt64(kKeyDuration, durationUs);
-
-    return meta;
+    return mTrackMeta;
 }
 
 status_t WAVExtractor::init() {
@@ -149,7 +143,7 @@
 
         remainingSize -= 8;
         offset += 8;
-        
+
         uint32_t chunkSize = U32_LE_AT(&chunkHeader[4]);
 
         if (chunkSize > remainingSize) {
@@ -178,7 +172,13 @@
 
             mSampleRate = U32_LE_AT(&formatSpec[4]);
 
-            if (U16_LE_AT(&formatSpec[14]) != 16) {
+            if (mSampleRate == 0) {
+                return ERROR_MALFORMED;
+            }
+
+            mBitsPerSample = U16_LE_AT(&formatSpec[14]);
+
+            if (mBitsPerSample != 8 && mBitsPerSample != 16) {
                 return ERROR_UNSUPPORTED;
             }
 
@@ -188,6 +188,19 @@
                 mDataOffset = offset;
                 mDataSize = chunkSize;
 
+                mTrackMeta = new MetaData;
+                mTrackMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+                mTrackMeta->setInt32(kKeyChannelCount, mNumChannels);
+                mTrackMeta->setInt32(kKeySampleRate, mSampleRate);
+
+                size_t bytesPerSample = mBitsPerSample >> 3;
+
+                int64_t durationUs =
+                    1000000LL * (mDataSize / (mNumChannels * bytesPerSample))
+                        / mSampleRate;
+
+                mTrackMeta->setInt64(kKeyDuration, durationUs);
+
                 return OK;
             }
         }
@@ -202,15 +215,20 @@
 
 WAVSource::WAVSource(
         const sp<DataSource> &dataSource,
-        int32_t sampleRate, int32_t numChannels,
+        const sp<MetaData> &meta,
+        int32_t bitsPerSample,
         off_t offset, size_t size)
     : mDataSource(dataSource),
-      mSampleRate(sampleRate),
-      mNumChannels(numChannels),
+      mMeta(meta),
+      mSampleRate(0),
+      mNumChannels(0),
+      mBitsPerSample(bitsPerSample),
       mOffset(offset),
       mSize(size),
       mStarted(false),
       mGroup(NULL) {
+    CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate));
+    CHECK(mMeta->findInt32(kKeyChannelCount, &mNumChannels));
 }
 
 WAVSource::~WAVSource() {
@@ -227,6 +245,11 @@
     mGroup = new MediaBufferGroup;
     mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
 
+    if (mBitsPerSample == 8) {
+        // As a temporary buffer for 8->16 bit conversion.
+        mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+    }
+
     mCurrentPos = mOffset;
 
     mStarted = true;
@@ -250,17 +273,7 @@
 sp<MetaData> WAVSource::getFormat() {
     LOGV("WAVSource::getFormat");
 
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-    meta->setInt32(kKeyChannelCount, mNumChannels);
-    meta->setInt32(kKeySampleRate, mSampleRate);
-
-    int64_t durationUs =
-        1000000LL * (mSize / (mNumChannels * 2)) / mSampleRate;
-
-    meta->setInt64(kKeyDuration, durationUs);
-
-    return meta;
+    return mMeta;
 }
 
 status_t WAVSource::read(
@@ -283,7 +296,8 @@
     }
 
     ssize_t n = mDataSource->readAt(
-            mCurrentPos, buffer->data(), kMaxFrameSize);
+            mCurrentPos, buffer->data(),
+            mBitsPerSample == 8 ? kMaxFrameSize / 2 : kMaxFrameSize);
 
     if (n <= 0) {
         buffer->release();
@@ -295,10 +309,34 @@
     mCurrentPos += n;
 
     buffer->set_range(0, n);
+
+    if (mBitsPerSample == 8) {
+        // Convert 8-bit unsigned samples to 16-bit signed.
+
+        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);
+
+        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;
+    }
+
+    size_t bytesPerSample = mBitsPerSample >> 3;
+
     buffer->meta_data()->setInt64(
             kKeyTime,
             1000000LL * (mCurrentPos - mOffset)
-                / (mNumChannels * 2) / mSampleRate);
+                / (mNumChannels * bytesPerSample) / mSampleRate);
 
 
     *out = buffer;
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 8545efc..9384942 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -45,8 +45,10 @@
     bool mValidFormat;
     uint16_t mNumChannels;
     uint32_t mSampleRate;
+    uint16_t mBitsPerSample;
     off_t mDataOffset;
     size_t mDataSize;
+    sp<MetaData> mTrackMeta;
 
     status_t init();