summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/g711
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-08-09 09:54:59 -0700
committerAndreas Huber <andih@google.com>2010-08-09 10:01:26 -0700
commit42d66f25af9cb8089a93c6796876a6bc16e36cea (patch)
tree5db576e682def943eaf39ada08c3c10235fd4d31 /media/libstagefright/codecs/g711
parent8bf59e735760af0b6a85747fd90bf8cf1e5388d7 (diff)
downloadframeworks_av-42d66f25af9cb8089a93c6796876a6bc16e36cea.zip
frameworks_av-42d66f25af9cb8089a93c6796876a6bc16e36cea.tar.gz
frameworks_av-42d66f25af9cb8089a93c6796876a6bc16e36cea.tar.bz2
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
Diffstat (limited to 'media/libstagefright/codecs/g711')
-rw-r--r--media/libstagefright/codecs/g711/Android.mk4
-rw-r--r--media/libstagefright/codecs/g711/dec/Android.mk12
-rw-r--r--media/libstagefright/codecs/g711/dec/G711Decoder.cpp213
3 files changed, 229 insertions, 0 deletions
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