From 520b2a7039792f03da11a8d54344f10175cebfbc Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 9 Aug 2010 09:54:59 -0700 Subject: 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 --- media/libstagefright/codecs/g711/Android.mk | 4 + media/libstagefright/codecs/g711/dec/Android.mk | 12 ++ .../libstagefright/codecs/g711/dec/G711Decoder.cpp | 213 +++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 media/libstagefright/codecs/g711/Android.mk create mode 100644 media/libstagefright/codecs/g711/dec/Android.mk create mode 100644 media/libstagefright/codecs/g711/dec/G711Decoder.cpp (limited to 'media/libstagefright/codecs/g711') 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 + +#include "G711Decoder.h" + +#include +#include +#include +#include +#include + +static const size_t kMaxNumSamplesPerFrame = 16384; + +namespace android { + +G711Decoder::G711Decoder(const sp &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 G711Decoder::getFormat() { + sp srcFormat = mSource->getFormat(); + + int32_t numChannels; + int32_t sampleRate; + + CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels)); + CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); + + sp 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(outBuffer->data()), + inputPtr, inBuffer->range_length()); + } else { + DecodeALaw( + static_cast(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 -- cgit v1.1