diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libmedia/AudioEffect.cpp | 25 | ||||
-rw-r--r-- | media/libstagefright/AMRExtractor.cpp | 1 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/MP3Extractor.cpp | 1 | ||||
-rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 12 | ||||
-rw-r--r-- | media/libstagefright/MediaDefs.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/OMXCodec.cpp | 70 | ||||
-rw-r--r-- | media/libstagefright/OggExtractor.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/SampleTable.cpp | 76 | ||||
-rw-r--r-- | media/libstagefright/WAVExtractor.cpp | 117 | ||||
-rw-r--r-- | media/libstagefright/codecs/g711/Android.mk | 4 | ||||
-rw-r--r-- | media/libstagefright/codecs/g711/dec/Android.mk | 12 | ||||
-rw-r--r-- | media/libstagefright/codecs/g711/dec/G711Decoder.cpp | 213 | ||||
-rw-r--r-- | media/libstagefright/include/G711Decoder.h | 57 | ||||
-rw-r--r-- | media/libstagefright/include/SampleTable.h | 5 | ||||
-rw-r--r-- | media/libstagefright/include/WAVExtractor.h | 1 | ||||
-rw-r--r-- | media/libstagefright/matroska/MatroskaExtractor.cpp | 1 |
17 files changed, 519 insertions, 81 deletions
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 @@ status_t AudioEffect::setEnabled(bool enabled) return mIEffect->disable(); } } - return INVALID_OPERATION; + return NO_ERROR; } status_t AudioEffect::command(uint32_t cmdCode, @@ -231,7 +231,22 @@ status_t AudioEffect::command(uint32_t cmdCode, 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 @@ void AudioEffect::enableStatusChanged(bool enabled) { 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 @@ status_t AMRSource::read( 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 @@ LOCAL_STATIC_LIBRARIES := \ 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 @@ status_t MP3Source::read( 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 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) { 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 @@ status_t MPEG4Source::read( 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 @@ status_t MPEG4Source::read( kKeyTargetTime, targetSampleTimeUs); } + if (isSyncSample) { + mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); + } + ++mCurrentSampleIndex; } @@ -1697,6 +1701,10 @@ status_t MPEG4Source::read( 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_MPEG = "audio/mpeg"; 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(AMRNBDecoder) 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 @@ static sp<MediaSource> InstantiateSoftwareCodec( 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 @@ static const CodecInfo kDecoderInfo[] = { { 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 @@ static size_t getFrameSize( } } +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 @@ void OMXCodec::setVideoInputFormat( 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 @@ status_t OggSource::read( } #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 @@ SampleTable::SampleTable(const sp<DataSource> &source) mTimeToSample(NULL), mSyncSampleOffset(-1), mNumSyncSamples(0), + mSyncSamples(NULL), + mLastSyncSampleIndex(0), mSampleToChunkEntries(NULL) { mSampleIterator = new SampleIterator(this); } @@ -63,6 +65,9 @@ SampleTable::~SampleTable() { delete[] mSampleToChunkEntries; mSampleToChunkEntries = NULL; + delete[] mSyncSamples; + mSyncSamples = NULL; + delete[] mTimeToSample; mTimeToSample = NULL; @@ -278,6 +283,18 @@ status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) { 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 @@ status_t SampleTable::findSyncSampleNear( 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 @@ status_t SampleTable::findSyncSampleNear( --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 @@ status_t SampleTable::findSyncSampleNear( 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 @@ status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { } 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 @@ status_t SampleTable::getMetaDataForSample( 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 @@ status_t SampleTable::getMetaDataForSample( *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 @@ struct WAVSource : public MediaSource { 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 @@ private: sp<DataSource> mDataSource; sp<MetaData> mMeta; + uint16_t mWaveFormat; int32_t mSampleRate; int32_t mNumChannels; int32_t mBitsPerSample; @@ -108,7 +114,7 @@ sp<MediaSource> WAVExtractor::getTrack(size_t index) { return new WAVSource( mDataSource, mTrackMeta, - mBitsPerSample, mDataOffset, mDataSize); + mWaveFormat, mBitsPerSample, mDataOffset, mDataSize); } sp<MetaData> WAVExtractor::getTrackMetaData( @@ -160,8 +166,10 @@ status_t WAVExtractor::init() { 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 @@ status_t WAVExtractor::init() { 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 @@ status_t WAVExtractor::init() { 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 @@ const size_t WAVSource::kMaxFrameSize = 32768; 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 @@ status_t WAVSource::read( 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->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 - buffer->set_range(buffer->range_offset(), 2 * numSamples); + 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 @@ status_t WAVSource::read( 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 @@ public: uint32_t sampleIndex, off_t *offset, size_t *size, - uint32_t *decodingTime); + uint32_t *decodingTime, + bool *isSyncSample = NULL); enum { kFlagBefore, @@ -105,6 +106,8 @@ private: 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 @@ private: 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 @@ status_t MatroskaSource::read( 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); |