diff options
21 files changed, 988 insertions, 80 deletions
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h index 99f3c3b..4489254 100644 --- a/include/media/stagefright/AudioSource.h +++ b/include/media/stagefright/AudioSource.h @@ -85,6 +85,7 @@ private: int64_t mInitialReadTimeUs; int64_t mNumFramesReceived; int64_t mNumClientOwnedBuffers; + int64_t mAutoRampStartUs; List<MediaBuffer * > mBuffersReceived; diff --git a/include/media/stagefright/LPAPlayer.h b/include/media/stagefright/LPAPlayer.h index b0e1d31..c3c5cac 100755 --- a/include/media/stagefright/LPAPlayer.h +++ b/include/media/stagefright/LPAPlayer.h @@ -92,7 +92,8 @@ private: bool mPaused; bool mA2DPEnabled; int32_t mChannelMask; - int32_t numChannels; + int32_t mNumOutputChannels; + int32_t mNumInputChannels; int32_t mSampleRate; int64_t mLatencyUs; size_t mFrameSize; @@ -259,6 +260,8 @@ private: void *buffer, size_t size, void *cookie); size_t AudioCallback(void *cookie, void *data, size_t size); + void convertMonoToStereo(int16_t *data, size_t size); + LPAPlayer(const LPAPlayer &); LPAPlayer &operator=(const LPAPlayer &); }; diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h new file mode 100644 index 0000000..bcaeeba --- /dev/null +++ b/include/media/stagefright/MediaDebug.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * Not a Contribution, Apache license notifications and license are retained + * for attribution purposes only + * + * 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 MEDIA_DEBUG_H_ + +#define MEDIA_DEBUG_H_ + +#include <cutils/log.h> + +#define LITERAL_TO_STRING_INTERNAL(x) #x +#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x) + +#define CHECK_EQ(x,y) \ + LOG_ALWAYS_FATAL_IF( \ + (x) != (y), \ + __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y) + +#define CHECK(x) \ + LOG_ALWAYS_FATAL_IF( \ + !(x), \ + __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x) + +#endif // MEDIA_DEBUG_H_ diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index ce03754..2725b5b 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -63,7 +63,12 @@ status_t AudioRecord::getMinFrameCount( // We double the size of input buffer for ping pong use of record buffer. size <<= 1; - if (audio_is_linear_pcm(format)) { +#ifdef QCOM_ENHANCED_AUDIO + if (audio_is_linear_pcm(format) || format == AUDIO_FORMAT_AMR_WB) +#else + if (audio_is_linear_pcm(format)) +#endif + { int channelCount = popcount(channelMask); size /= channelCount * audio_bytes_per_sample(format); } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a2172c9..36b1469 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -96,7 +96,8 @@ status_t AudioTrack::getMinFrameCount( // --------------------------------------------------------------------------- AudioTrack::AudioTrack() - : mStatus(NO_INIT), + : mCblk(NULL), + mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) @@ -118,7 +119,8 @@ AudioTrack::AudioTrack( void* user, int notificationFrames, int sessionId) - : mStatus(NO_INIT), + : mCblk(NULL), + mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) @@ -144,7 +146,8 @@ AudioTrack::AudioTrack( void* user, int notificationFrames, int sessionId) - : mStatus(NO_INIT), + : mCblk(NULL), + mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) #ifdef QCOM_HARDWARE @@ -169,7 +172,8 @@ AudioTrack::AudioTrack( void* user, int notificationFrames, int sessionId) - : mStatus(NO_INIT), + : mCblk(NULL), + mStatus(NO_INIT), mIsTimed(false), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT) @@ -1599,7 +1603,8 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const result.append(" AudioTrack::dump\n"); snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]); result.append(buffer); - snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mCblk->frameCount); + snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, + (mCblk == 0) ? 0 : mCblk->frameCount); result.append(buffer); snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted); result.append(buffer); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 1f4038c..e86bf63 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -820,6 +820,10 @@ status_t ACodec::setComponentRole( "audio_decoder.amrnb", "audio_encoder.amrnb" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "audio_decoder.amrwb", "audio_encoder.amrwb" }, +#ifdef QCOM_ENHANCED_AUDIO + { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS, + "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" }, +#endif { MEDIA_MIMETYPE_AUDIO_AAC, "audio_decoder.aac", "audio_encoder.aac" }, { MEDIA_MIMETYPE_AUDIO_VORBIS, diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index eb89cfe..ea64cc8 100755 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) ifeq ($(BOARD_USES_ALSA_AUDIO),true) ifeq ($(call is-chipset-in-board-platform,msm8960),true) LOCAL_CFLAGS += -DUSE_TUNNEL_MODE + LOCAL_CFLAGS += -DTUNNEL_MODE_SUPPORTS_AMRWB endif endif @@ -132,6 +133,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := \ libstagefright_color_conversion \ + libstagefright_mp3dec \ libstagefright_aacenc \ libstagefright_matroska \ libstagefright_timedtext \ diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index 8e3811b..bb2d415 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -83,6 +83,17 @@ AudioSource::AudioSource( this, frameCount); mInitCheck = mRecord->initCheck(); + + //configure the auto ramp start duration + mAutoRampStartUs = kAutoRampStartUs; + uint32_t playbackLatencyMs = 0; + if (AudioSystem::getOutputLatency(&playbackLatencyMs, + AUDIO_STREAM_DEFAULT) == OK) { + if (2*playbackLatencyMs*1000LL > kAutoRampStartUs) { + mAutoRampStartUs = 2*playbackLatencyMs*1000LL; + } + } + ALOGD("Start autoramp from %lld", mAutoRampStartUs); } else { mInitCheck = status; } @@ -238,14 +249,14 @@ status_t AudioSource::read( int64_t timeUs; CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); int64_t elapsedTimeUs = timeUs - mStartTimeUs; - if (elapsedTimeUs < kAutoRampStartUs) { + if (elapsedTimeUs < mAutoRampStartUs) { memset((uint8_t *) buffer->data(), 0, buffer->range_length()); - } else if (elapsedTimeUs < kAutoRampStartUs + kAutoRampDurationUs) { + } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) { int32_t autoRampDurationFrames = (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; int32_t autoRampStartFrames = - (kAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; + (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; int32_t nFrames = mNumFramesReceived - autoRampStartFrames; rampVolume(nFrames, autoRampDurationFrames, diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 97ee08a..4b14baa 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -1544,26 +1544,26 @@ status_t AwesomePlayer::initAudioDecoder() { nchannels); #ifdef USE_TUNNEL_MODE - char value[PROPERTY_VALUE_MAX]; - char tunnelDecode[128]; + char tunnelDecode[PROPERTY_VALUE_MAX]; property_get("tunnel.decode",tunnelDecode,"0"); // Enable tunnel mode for mp3 and aac and if the clip is not aac adif // and if no other tunnel mode instances aare running. ALOGD("Tunnel Mime Type: %s, object alive = %d, mTunnelAliveAP = %d",\ mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP); - if(((strcmp("true",tunnelDecode) == 0)||(atoi(tunnelDecode))) && - (TunnelPlayer::mTunnelObjectsAlive == 0) && - //widevine will fallback to software decoder - mTunnelAliveAP == 0 && (isADTS == 0) && mAudioSink->realtime() && - ((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) || - (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) || - (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) || - (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)))) { - - if(mVideoSource != NULL) { - char tunnelAVDecode[128]; + + bool sys_prop_enabled = !strcmp("true",tunnelDecode) || atoi(tunnelDecode); + + //widevine will fallback to software decoder + if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) && + mTunnelAliveAP == 0 && (isADTS == 0) && + mAudioSink->realtime() && + inSupportedTunnelFormats(mime)) { + + if (mVideoSource != NULL) { + char tunnelAVDecode[PROPERTY_VALUE_MAX]; property_get("tunnel.audiovideo.decode",tunnelAVDecode,"0"); - if(((strncmp("true", tunnelAVDecode, 4) == 0)||(atoi(tunnelAVDecode)))) { + sys_prop_enabled = !strncmp("true", tunnelAVDecode, 4) || atoi(tunnelAVDecode); + if (sys_prop_enabled) { ALOGD("Enable Tunnel Mode for A-V playback"); mIsTunnelAudio = true; } @@ -3027,4 +3027,36 @@ inline int64_t AwesomePlayer::getTimeOfDayUs() { return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; } + +#ifdef USE_TUNNEL_MODE +bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) { + const char * tunnelFormats [ ] = { + MEDIA_MIMETYPE_AUDIO_MPEG, + MEDIA_MIMETYPE_AUDIO_AAC, +#ifdef TUNNEL_MODE_SUPPORTS_AMRWB + MEDIA_MIMETYPE_AUDIO_AMR_WB, + MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS +#endif + }; + + if (!mime) { + return false; + } + + size_t len = sizeof(tunnelFormats)/sizeof(const char *); + for (size_t i = 0; i < len; i++) { + const char * tf = tunnelFormats[i]; + if (!strncasecmp(mime, tf, strlen(tf))) { + if (strlen(mime) == strlen(tf)) { //to prevent a substring match + ALOGD("Tunnel playback supported for %s", tf); + return true; + } + } + } + + ALOGW("Tunnel playback unsupported for %s", mime); + return false; +} +#endif + } // namespace android diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp index 38d6bac..18aae8f 100644 --- a/media/libstagefright/LPAPlayerALSA.cpp +++ b/media/libstagefright/LPAPlayerALSA.cpp @@ -87,7 +87,8 @@ mAudioSink(audioSink), mObserver(observer) { ALOGV("LPAPlayer::LPAPlayer() ctor"); objectsAlive++; - numChannels =0; + mNumOutputChannels =0; + mNumInputChannels = 0; mPaused = false; mIsA2DPEnabled = false; mAudioFlinger = NULL; @@ -256,20 +257,24 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) { success = format->findInt32(kKeySampleRate, &mSampleRate); CHECK(success); - success = format->findInt32(kKeyChannelCount, &numChannels); + success = format->findInt32(kKeyChannelCount, &mNumInputChannels); CHECK(success); + // Always produce stereo output + mNumOutputChannels = 2; + if(!format->findInt32(kKeyChannelMask, &mChannelMask)) { // log only when there's a risk of ambiguity of channel mask selection - ALOGI_IF(numChannels > 2, - "source format didn't specify channel mask, using (%d) channel order", numChannels); + ALOGI_IF(mNumInputChannels > 2, + "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels); mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT); - ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags); + ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate, + mNumOutputChannels, mChannelMask, flags); err = mAudioSink->open( - mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, + mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &LPAPlayer::AudioSinkCallback, this, @@ -372,7 +377,7 @@ void LPAPlayer::resume() { audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT); status_t err = mAudioSink->open( - mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, + mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &LPAPlayer::AudioSinkCallback, this, @@ -491,6 +496,12 @@ void LPAPlayer::decoderThreadEntry() { } void* local_buf = malloc(MEM_BUFFER_SIZE); int bytesWritten = 0; + + if (!local_buf) { + ALOGE("Failed to allocate temporary buffer for decoderThread"); + return; + } + while (!killDecoderThread) { if (mReachedEOS || mPaused || !mIsAudioRouted) { @@ -500,16 +511,27 @@ void LPAPlayer::decoderThreadEntry() { continue; } - if (!mIsA2DPEnabled) { - ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE); - ALOGV("Fillbuffer started"); - //TODO: Add memset + if (mIsA2DPEnabled) { + //nothing to do + continue; + } + + ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE); + ALOGV("Fillbuffer started"); + if (mNumInputChannels == 1) { + bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2); + CHECK(bytesWritten <= MEM_BUFFER_SIZE/2); + + convertMonoToStereo((int16_t*)local_buf, bytesWritten); + bytesWritten *= 2; + } else { bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE); - ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten); + CHECK(bytesWritten <= MEM_BUFFER_SIZE); + } - if(!killDecoderThread) { - mAudioSink->write(local_buf, bytesWritten); - } + ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten); + if(!killDecoderThread) { + mAudioSink->write(local_buf, bytesWritten); } } @@ -662,7 +684,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) { size_t copy = size_remaining; if (copy > mInputBuffer->range_length()) { copy = mInputBuffer->range_length(); - } + } //is size_remaining < range_length impossible? memcpy((char *)data + size_done, (const char *)mInputBuffer->data() + mInputBuffer->range_offset(), @@ -790,4 +812,18 @@ void LPAPlayer::onPauseTimeOut() { } +//dup each mono frame +void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size) +{ + int i =0; + int16_t *start_pointer = data; + int monoFrameCount = (size) / (sizeof(int16_t)); + + for (i = monoFrameCount; i > 0 ; i--) { + int16_t temp_sample = *(start_pointer + i - 1); + *(start_pointer + (i*2) - 1) = temp_sample; + *(start_pointer + (i*2) - 2) = temp_sample; + } +} + } //namespace android diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 62ba826..488c2a3 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -243,6 +243,9 @@ static const char *FourCC2MIME(uint32_t fourcc) { case FOURCC('m', 'p', '4', 'a'): return MEDIA_MIMETYPE_AUDIO_AAC; + case FOURCC('.', 'm', 'p', '3'): + return MEDIA_MIMETYPE_AUDIO_MPEG; + case FOURCC('s', 'a', 'm', 'r'): return MEDIA_MIMETYPE_AUDIO_AMR_NB; @@ -1870,12 +1873,12 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( return OK; } - if (objectTypeIndication == 0x6b) { - // The media subtype is MP3 audio - // Our software MP3 audio decoder may not be able to handle - // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED - ALOGE("MP3 track in MP4/3GPP file is not supported"); - return ERROR_UNSUPPORTED; + if (objectTypeIndication == 0x6b + || objectTypeIndication == 0x69) { + // This is mpeg1/2 audio content, set mimetype to mpeg + mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); + ALOGD("objectTypeIndication:0x%x, set mimetype to mpeg ",objectTypeIndication); + return OK; } const uint8_t *csd; diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 218448b..1eb5c19 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -107,13 +108,7 @@ sp<MediaExtractor> MediaExtractor::Create( ret = new MPEG4Extractor(source); } #ifdef QCOM_ENHANCED_AUDIO - char tunnelDecode[PROPERTY_VALUE_MAX]; - ALOGV("MediaExtractor::Create checking tunnel.decode"); - property_get("tunnel.decode",tunnelDecode,"0"); - if( (strncmp("true",tunnelDecode,4) == 0) || (atoi(tunnelDecode)) ) { - bCheckExtendedExtractor = true; - ALOGV("MediaExtractor::Create detected tunnel.decode as true..."); - } + bCheckExtendedExtractor = true; #endif } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { ret = new MP3Extractor(source, meta); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index e7ba1cc..5988061 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -23,6 +23,7 @@ #include <utils/Log.h> #include "include/AACEncoder.h" +#include "include/MP3Decoder.h" #include "include/ESDS.h" @@ -97,6 +98,11 @@ const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL; // component in question is buggy or not. const static uint32_t kMaxColorFormatSupported = 1000; + +#define FACTORY_CREATE(name) \ +static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \ + return new name(source); \ +} #define FACTORY_CREATE_ENCODER(name) \ static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \ return new name(source, meta); \ @@ -104,6 +110,7 @@ static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaDa #define FACTORY_REF(name) { #name, Make##name }, +FACTORY_CREATE(MP3Decoder) FACTORY_CREATE_ENCODER(AACEncoder) static sp<MediaSource> InstantiateSoftwareEncoder( @@ -127,8 +134,29 @@ static sp<MediaSource> InstantiateSoftwareEncoder( return NULL; } +static sp<MediaSource> InstantiateSoftwareDecoder( + const char *name, const sp<MediaSource> &source) { + struct FactoryInfo { + const char *name; + sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &); + }; + + static const FactoryInfo kFactoryInfo[] = { + FACTORY_REF(MP3Decoder) + }; + for (size_t i = 0; + i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) { + if (!strcmp(name, kFactoryInfo[i].name)) { + return (*kFactoryInfo[i].CreateFunc)(source); + } + } + + return NULL; +} + #undef FACTORY_CREATE_ENCODER #undef FACTORY_REF +#undef FACTORY_CREATE #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__) @@ -173,7 +201,8 @@ static void InitOMXParams(T *params) { } static bool IsSoftwareCodec(const char *componentName) { - if (!strncmp("OMX.google.", componentName, 11)) { + if (!strncmp("OMX.google.", componentName, 11) + || !strncmp("OMX.PV.", componentName, 7)) { return true; } @@ -245,6 +274,7 @@ void OMXCodec::findMatchingCodecs( const char *componentName = list->getCodecName(matchIndex); // If a specific codec is requested, skip the non-matching ones. + ALOGV("matchComponentName %s ",matchComponentName); if (matchComponentName && strcmp(componentName, matchComponentName)) { continue; } @@ -389,15 +419,15 @@ sp<MediaSource> OMXCodec::Create( componentName = tmp.c_str(); } + sp<MediaSource> softwareCodec; if (createEncoder) { - sp<MediaSource> softwareCodec = - InstantiateSoftwareEncoder(componentName, source, meta); - - if (softwareCodec != NULL) { - ALOGV("Successfully allocated software codec '%s'", componentName); - - return softwareCodec; - } + softwareCodec = InstantiateSoftwareEncoder(componentName, source, meta); + } else { + softwareCodec = InstantiateSoftwareDecoder(componentName, source); + } + if (softwareCodec != NULL) { + ALOGE("Successfully allocated software codec '%s'", componentName); + return softwareCodec; } #ifdef QCOM_HARDWARE //quirks = getComponentQuirks(componentNameBase, createEncoder); @@ -562,8 +592,14 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { esds.getCodecSpecificInfo( &codec_specific_data, &codec_specific_data_size); - addCodecSpecificData( + const char * mime_type; + meta->findCString(kKeyMIMEType, &mime_type); + if (strncmp(mime_type, + MEDIA_MIMETYPE_AUDIO_MPEG, + strlen(MEDIA_MIMETYPE_AUDIO_MPEG))) { + addCodecSpecificData( codec_specific_data, codec_specific_data_size); + } } else if (meta->findData(kKeyAVCC, &type, &data, &size)) { // Parse the AVCDecoderConfigurationRecord diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp index 475cf56..564f916 100644 --- a/media/libstagefright/TunnelPlayer.cpp +++ b/media/libstagefright/TunnelPlayer.cpp @@ -376,7 +376,13 @@ status_t TunnelPlayer::seekTo(int64_t time_us) { ALOGV("seekTo: time_us %lld", time_us); - if (mPositionTimeRealUs != 0) { + //This can happen if the client calls seek + //without ever calling getPosition + if (mPositionTimeRealUs == -1) { + getOffsetRealTime_l(&mPositionTimeRealUs); + } + + if (mPositionTimeRealUs > 0) { //check for return conditions only if seektime // is set if (time_us > mPositionTimeRealUs){ @@ -522,17 +528,10 @@ void TunnelPlayer::reset() { mInputBuffer = NULL; } - if(mStarted) + if (mStarted) mSource->stop(); - // The following hack is necessary to ensure that the OMX - // component is completely released by the time we may try - // to instantiate it again. - wp<MediaSource> tmp = mSource; mSource.clear(); - while (tmp.promote() != NULL) { - usleep(1000); - } mPositionTimeMediaUs = -1; mPositionTimeRealUs = -1; diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk index ec8d7ec..4837664 100644 --- a/media/libstagefright/codecs/mp3dec/Android.mk +++ b/media/libstagefright/codecs/mp3dec/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ + MP3Decoder.cpp \ src/pvmp3_normalize.cpp \ src/pvmp3_alias_reduction.cpp \ src/pvmp3_crc.cpp \ @@ -52,6 +53,64 @@ LOCAL_CFLAGS := \ LOCAL_MODULE := libstagefright_mp3dec +include $(BUILD_STATIC_LIBRARY) + + + +#LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + src/pvmp3_normalize.cpp \ + src/pvmp3_alias_reduction.cpp \ + src/pvmp3_crc.cpp \ + src/pvmp3_decode_header.cpp \ + src/pvmp3_decode_huff_cw.cpp \ + src/pvmp3_getbits.cpp \ + src/pvmp3_dequantize_sample.cpp \ + src/pvmp3_framedecoder.cpp \ + src/pvmp3_get_main_data_size.cpp \ + src/pvmp3_get_side_info.cpp \ + src/pvmp3_get_scale_factors.cpp \ + src/pvmp3_mpeg2_get_scale_data.cpp \ + src/pvmp3_mpeg2_get_scale_factors.cpp \ + src/pvmp3_mpeg2_stereo_proc.cpp \ + src/pvmp3_huffman_decoding.cpp \ + src/pvmp3_huffman_parsing.cpp \ + src/pvmp3_tables.cpp \ + src/pvmp3_imdct_synth.cpp \ + src/pvmp3_mdct_6.cpp \ + src/pvmp3_dct_6.cpp \ + src/pvmp3_poly_phase_synthesis.cpp \ + src/pvmp3_equalizer.cpp \ + src/pvmp3_seek_synch.cpp \ + src/pvmp3_stereo_proc.cpp \ + src/pvmp3_reorder.cpp \ + +ifeq ($(TARGET_ARCH),arm) +LOCAL_SRC_FILES += \ + src/asm/pvmp3_polyphase_filter_window_gcc.s \ + src/asm/pvmp3_mdct_18_gcc.s \ + src/asm/pvmp3_dct_9_gcc.s \ + src/asm/pvmp3_dct_16_gcc.s +else +LOCAL_SRC_FILES += \ + src/pvmp3_polyphase_filter_window.cpp \ + src/pvmp3_mdct_18.cpp \ + src/pvmp3_dct_9.cpp \ + src/pvmp3_dct_16.cpp +endif + +LOCAL_C_INCLUDES := \ + frameworks/av/media/libstagefright/include \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/include + +LOCAL_CFLAGS := \ + -DOSCL_UNUSED_ARG= + +LOCAL_MODULE := libstagefright_mp3dec_omx + LOCAL_ARM_MODE := arm include $(BUILD_STATIC_LIBRARY) @@ -73,7 +132,7 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils LOCAL_STATIC_LIBRARIES := \ - libstagefright_mp3dec + libstagefright_mp3dec_omx LOCAL_MODULE := libstagefright_soft_mp3dec LOCAL_MODULE_TAGS := optional diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp new file mode 100644 index 0000000..c24aca0 --- /dev/null +++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp @@ -0,0 +1,586 @@ +/* + * Copyright (C) 2009 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. + */ + +#include "MP3Decoder.h" + +#include "include/pvmp3decoder_api.h" + +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/Utils.h> + +namespace android { + +// Everything must match except for +// protection, bitrate, padding, private bits, mode extension, +// copyright bit, original bit and emphasis. +// Yes ... there are things that must indeed match... +static const uint32_t kMask = 0xfffe0cc0; + +static bool get_mp3_frame_size( + uint32_t header, size_t *frame_size, + int *out_sampling_rate = NULL, int *out_channels = NULL, + int *out_bitrate = NULL) { + *frame_size = 0; + + if (out_sampling_rate) { + *out_sampling_rate = 0; + } + + if (out_channels) { + *out_channels = 0; + } + + if (out_bitrate) { + *out_bitrate = 0; + } + + if ((header & 0xffe00000) != 0xffe00000) { + return false; + } + + unsigned version = (header >> 19) & 3; + + if (version == 0x01) { + return false; + } + + unsigned layer = (header >> 17) & 3; + + if (layer == 0x00) { + return false; + } + + unsigned protection = (header >> 16) & 1; + + unsigned bitrate_index = (header >> 12) & 0x0f; + + if (bitrate_index == 0 || bitrate_index == 0x0f) { + // Disallow "free" bitrate. + return false; + } + + unsigned sampling_rate_index = (header >> 10) & 3; + + if (sampling_rate_index == 3) { + return false; + } + + static const int kSamplingRateV1[] = { 44100, 48000, 32000 }; + int sampling_rate = kSamplingRateV1[sampling_rate_index]; + if (version == 2 /* V2 */) { + sampling_rate /= 2; + } else if (version == 0 /* V2.5 */) { + sampling_rate /= 4; + } + + unsigned padding = (header >> 9) & 1; + + if (layer == 3) { + // layer I + + static const int kBitrateV1[] = { + 32, 64, 96, 128, 160, 192, 224, 256, + 288, 320, 352, 384, 416, 448 + }; + + static const int kBitrateV2[] = { + 32, 48, 56, 64, 80, 96, 112, 128, + 144, 160, 176, 192, 224, 256 + }; + + int bitrate = + (version == 3 /* V1 */) + ? kBitrateV1[bitrate_index - 1] + : kBitrateV2[bitrate_index - 1]; + + if (out_bitrate) { + *out_bitrate = bitrate; + } + + *frame_size = (12000 * bitrate / sampling_rate + padding) * 4; + } else { + // layer II or III + + static const int kBitrateV1L2[] = { + 32, 48, 56, 64, 80, 96, 112, 128, + 160, 192, 224, 256, 320, 384 + }; + + static const int kBitrateV1L3[] = { + 32, 40, 48, 56, 64, 80, 96, 112, + 128, 160, 192, 224, 256, 320 + }; + + static const int kBitrateV2[] = { + 8, 16, 24, 32, 40, 48, 56, 64, + 80, 96, 112, 128, 144, 160 + }; + + int bitrate; + if (version == 3 /* V1 */) { + bitrate = (layer == 2 /* L2 */) + ? kBitrateV1L2[bitrate_index - 1] + : kBitrateV1L3[bitrate_index - 1]; + } else { + // V2 (or 2.5) + + bitrate = kBitrateV2[bitrate_index - 1]; + } + + if (out_bitrate) { + *out_bitrate = bitrate; + } + + if (version == 3 /* V1 */) { + *frame_size = 144000 * bitrate / sampling_rate + padding; + } else { + // V2 or V2.5 + *frame_size = 72000 * bitrate / sampling_rate + padding; + } + } + + if (out_sampling_rate) { + *out_sampling_rate = sampling_rate; + } + + if (out_channels) { + int channel_mode = (header >> 6) & 3; + + *out_channels = (channel_mode == 3) ? 1 : 2; + } + + return true; +} + +static bool resync( + uint8_t *data, uint32_t size, uint32_t match_header, off_t *out_pos) { + + bool valid = false; + off_t pos = 0; + *out_pos = 0; + do { + if (pos + 4 > size) { + // Don't scan forever. + ALOGV("no dice, no valid sequence of frames found."); + break; + } + + uint32_t header = U32_AT(data + pos); + + if (match_header != 0 && (header & kMask) != (match_header & kMask)) { + ++pos; + continue; + } + + ALOGV("found possible frame at %ld (header = 0x%08x)", pos, header); + + // We found what looks like a valid frame, + valid = true; + *out_pos = pos; + } while (!valid); + + return valid; +} + + +MP3Decoder::MP3Decoder(const sp<MediaSource> &source) + : mSource(source), + mNumChannels(0), + mStarted(false), + mBufferGroup(NULL), + mConfig(new tPVMP3DecoderExternal), + mDecoderBuf(NULL), + mAnchorTimeUs(0), + mNumFramesOutput(0), + mInputBuffer(NULL), + mPartialBuffer(NULL), + mFixedHeader(0) { + init(); +} + +void MP3Decoder::init() { + sp<MetaData> srcFormat = mSource->getFormat(); + + int32_t sampleRate; + CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels)); + CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); + + mMeta = new MetaData; + mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + mMeta->setInt32(kKeyChannelCount, mNumChannels); + mMeta->setInt32(kKeySampleRate, sampleRate); + + int64_t durationUs; + if (srcFormat->findInt64(kKeyDuration, &durationUs)) { + mMeta->setInt64(kKeyDuration, durationUs); + } + + mMeta->setCString(kKeyDecoderComponent, "MP3Decoder"); +} + +MP3Decoder::~MP3Decoder() { + if (mStarted) { + stop(); + } + + delete mConfig; + mConfig = NULL; +} + +status_t MP3Decoder::start(MetaData *params) { + CHECK(!mStarted); + + mBufferGroup = new MediaBufferGroup; + mBufferGroup->add_buffer(new MediaBuffer(4608 * 2)); + + mConfig->equalizerType = flat; + mConfig->crcEnabled = false; + + uint32_t memRequirements = pvmp3_decoderMemRequirements(); + mDecoderBuf = malloc(memRequirements); + + pvmp3_InitDecoder(mConfig, mDecoderBuf); + + mSource->start(); + + mAnchorTimeUs = 0; + mNumFramesOutput = 0; + mStarted = true; + + return OK; +} + +status_t MP3Decoder::stop() { + CHECK(mStarted); + + if (mInputBuffer) { + mInputBuffer->release(); + mInputBuffer = NULL; + } + + free(mDecoderBuf); + mDecoderBuf = NULL; + + delete mBufferGroup; + mBufferGroup = NULL; + + mSource->stop(); + + mStarted = false; + + return OK; +} + +sp<MetaData> MP3Decoder::getFormat() { + return mMeta; +} + +status_t MP3Decoder::updatePartialFrame() { + status_t err = OK; + if (mPartialBuffer == NULL) { + return err; + } + + size_t frameSize = 0; + uint32_t partialBufLen = mPartialBuffer->range_length(); + uint32_t inputBufLen = mInputBuffer->range_length(); + uint8_t frameHeader[4]; + uint8_t *frmHdr; + uint32_t header; + + + // Look at the frame size and complete the partial frame + // Also check if a vaild header is found after the partial frame + if (partialBufLen < 4) { // check if partial frame has the 4 bytes header + if (inputBufLen < (4 - partialBufLen)) { + // input buffer does not have the frame header bytes + // bail out TODO + ALOGE("MP3Decoder::updatePartialFrame buffer to small header not found" + " partial buffer len %d, input buffer len %d", + partialBufLen, inputBufLen); + //mPartialBuffer->release(); + //mPartialBuffer = NULL; + return UNKNOWN_ERROR; + } + + // copy the header bytes to frameHeader + memcpy (frameHeader, mPartialBuffer->data(), partialBufLen); + memcpy (frameHeader + partialBufLen, mInputBuffer->data(), (4 - partialBufLen)); + // get the first 4 bytes of the buffer + header = U32_AT((uint8_t *)frameHeader); + frmHdr = frameHeader; + } else { + frmHdr = (uint8_t *)mPartialBuffer->data(); + } + + // check if its a good frame, and the frame size + // get the first 4 bytes of the buffer + header = U32_AT(frmHdr); + bool curFrame = get_mp3_frame_size(header,&frameSize); + if (!curFrame) { + ALOGE("MP3Decoder::read - partial frame does not have a vaild header 0x%x", + header); + return UNKNOWN_ERROR; + } + + // check if the following frame is good + uint32_t nextFrameOffset = frameSize - partialBufLen; + if ((nextFrameOffset + 4) <= inputBufLen) { + header = U32_AT((uint8_t *)mInputBuffer->data() + nextFrameOffset); + if ((header & 0xffe00000) != 0xffe00000) { + // next frame does not have a valid header, + // this may not be the next buffer, bail out. + ALOGE("MP3Decoder::read - next frame does not have a vaild header 0x%x", + header); + return UNKNOWN_ERROR; + } + } else { + // next frame header is out of range + // assume good header for now + ALOGE("MP3Decoder::read - assuming next frame is good"); + } + + // check if the input buffer has the remaining partial frame + if (frameSize > (partialBufLen + inputBufLen)) { + // input buffer does not have the remaining partial frame, + // discard data here as frame split in 3 buffers not supported + ALOGE("MP3Decoder::updatePartialFrame - input buffer does not have the complete frame." + " frame size %d, saved partial buffer len %d," + " input buffer len %d", frameSize, partialBufLen, inputBufLen); + return UNKNOWN_ERROR; + } + + // check if the mPartialBuffer can fit the remaining frame + if ((mPartialBuffer->size() - partialBufLen) < (frameSize - partialBufLen)) { + // mPartialBuffer is small to hold the reaming frame + //TODO + ALOGE("MP3Decoder::updatePartialFrame - mPartialBuffer is small, size %d, required &d", + (mPartialBuffer->size() - partialBufLen), (frameSize - partialBufLen)); + return UNKNOWN_ERROR; + } + + // done with error checks + // copy the partial frames to from a complete frame + // Copy the remaining frame from input buffer + uint32_t bytesRemaining = frameSize - mPartialBuffer->range_length(); + memcpy ((uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_length(), + (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(), + bytesRemaining); + + // mark the bytes as consumed from input buffer + mInputBuffer->set_range( + mInputBuffer->range_offset() + bytesRemaining, + mInputBuffer->range_length() - bytesRemaining); + + // set the range and length of mPartialBuffer + mPartialBuffer->set_range(0, + mPartialBuffer->range_length() + bytesRemaining); + + ALOGE("MP3Decoder::updatePartialFrame - copied the partial frame %d, input buffer length %d", + bytesRemaining, mInputBuffer->range_length()); + + return err; +} + +status_t MP3Decoder::read( + MediaBuffer **out, const ReadOptions *options) { + status_t err; + + *out = NULL; + bool usedPartialFrame = false; + bool seekSource = false; + + int64_t seekTimeUs; + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { + CHECK(seekTimeUs >= 0); + + mNumFramesOutput = 0; + seekSource = true; + + if (mInputBuffer) { + mInputBuffer->release(); + mInputBuffer = NULL; + } + + if (mPartialBuffer) { + mPartialBuffer->release(); + mPartialBuffer = NULL; + } + + // Make sure that the next buffer output does not still + // depend on fragments from the last one decoded. + pvmp3_InitDecoder(mConfig, mDecoderBuf); + } else { + seekTimeUs = -1; + } + + if (mInputBuffer == NULL) { + err = mSource->read(&mInputBuffer, options); + + if (err != OK) { + return err; + } + + if ((mFixedHeader == 0) && (mInputBuffer->range_length() > 4)) { + //save the first 4 bytes as fixed header for the reset of the file + mFixedHeader = U32_AT((uint8_t *)mInputBuffer->data()); + } + + if (seekSource == true) { + off_t syncOffset = 0; + bool valid = resync((uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset() + ,mInputBuffer->range_length(), mFixedHeader, &syncOffset); + if (valid) { + // consume these bytes, we might find a frame header in next buffer + mInputBuffer->set_range( + mInputBuffer->range_offset() + syncOffset, + mInputBuffer->range_length() - syncOffset); + ALOGV("mp3 decoder found a sync point after seek syncOffset %d", syncOffset); + } else { + ALOGV("NO SYNC POINT found, buffer length %d",mInputBuffer->range_length()); + } + } + + int64_t timeUs; + if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { + mAnchorTimeUs = timeUs; + mNumFramesOutput = 0; + } else { + // We must have a new timestamp after seeking. + CHECK(seekTimeUs < 0); + } + // check for partial frame + if (mPartialBuffer != NULL) { + err = updatePartialFrame(); + if (err != OK) { + // updating partial frame failed, discard the previously + // saved partial frame and continue + mPartialBuffer->release(); + mPartialBuffer = NULL; + err = OK; + } + } + } + + MediaBuffer *buffer; + CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK); + + if (mPartialBuffer != NULL) { + mConfig->pInputBuffer = + (uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_offset(); + mConfig->inputBufferCurrentLength = mPartialBuffer->range_length(); + usedPartialFrame = true; + } else { + mConfig->pInputBuffer = + (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); + mConfig->inputBufferCurrentLength = mInputBuffer->range_length(); + } + + mConfig->inputBufferMaxLength = 0; + mConfig->inputBufferUsedLength = 0; + + mConfig->outputFrameSize = buffer->size() / sizeof(int16_t); + mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data()); + + ERROR_CODE decoderErr; + if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) + != NO_DECODING_ERROR) { + ALOGV("mp3 decoder returned error %d", decoderErr); + + if ((decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) && + (decoderErr != SYNCH_LOST_ERROR)) { + buffer->release(); + buffer = NULL; + + mInputBuffer->release(); + mInputBuffer = NULL; + if (mPartialBuffer) { + mPartialBuffer->release(); + mPartialBuffer = NULL; + } + ALOGE("mp3 decoder returned UNKNOWN_ERROR"); + + return UNKNOWN_ERROR; + } + + if ((mPartialBuffer == NULL) && (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR)) { + // Might be a partial frame, save it + mPartialBuffer = new MediaBuffer(mInputBuffer->size()); + memcpy ((uint8_t *)mPartialBuffer->data(), + mConfig->pInputBuffer, mConfig->inputBufferCurrentLength); + mPartialBuffer->set_range(0, mConfig->inputBufferCurrentLength); + // set output buffer to 0 + mConfig->outputFrameSize = 0; + // consume the copied bytes from input + mConfig->inputBufferUsedLength = mConfig->inputBufferCurrentLength; + } else if(decoderErr == SYNCH_LOST_ERROR) { + // Try to find the mp3 frame header in the current buffer + off_t syncOffset = 0; + bool valid = resync(mConfig->pInputBuffer, mConfig->inputBufferCurrentLength, + mFixedHeader, &syncOffset); + if (!valid || !syncOffset) { + // consume these bytes, we might find a frame header in next buffer + syncOffset = mConfig->inputBufferCurrentLength; + } + // set output buffer to 0 + mConfig->outputFrameSize = 0; + // consume the junk bytes from input buffer + mConfig->inputBufferUsedLength = syncOffset; + } else { + // This is recoverable, just ignore the current frame and + // play silence instead. + memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t)); + mConfig->inputBufferUsedLength = mInputBuffer->range_length(); + } + } + + buffer->set_range( + 0, mConfig->outputFrameSize * sizeof(int16_t)); + + if ((mPartialBuffer != NULL) && usedPartialFrame) { + mPartialBuffer->set_range( + mPartialBuffer->range_offset() + mConfig->inputBufferUsedLength, + mPartialBuffer->range_length() - mConfig->inputBufferUsedLength); + mPartialBuffer->release(); + mPartialBuffer = NULL; + } else { + mInputBuffer->set_range( + mInputBuffer->range_offset() + mConfig->inputBufferUsedLength, + mInputBuffer->range_length() - mConfig->inputBufferUsedLength); + } + + if (mInputBuffer->range_length() == 0) { + mInputBuffer->release(); + mInputBuffer = NULL; + } + + buffer->meta_data()->setInt64( + kKeyTime, + mAnchorTimeUs + + (mNumFramesOutput * 1000000) / mConfig->samplingRate); + + mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; + + *out = buffer; + + return OK; +} + +} // namespace android diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index a5586dd..348f485 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -365,6 +365,8 @@ private: size_t countTracks() const; #ifdef QCOM_ENHANCED_AUDIO + bool inSupportedTunnelFormats(const char * mime); + //Flag to check if tunnel mode audio is enabled bool mIsTunnelAudio; #endif diff --git a/media/libstagefright/include/MP3Decoder.h b/media/libstagefright/include/MP3Decoder.h new file mode 100644 index 0000000..8ff570a --- /dev/null +++ b/media/libstagefright/include/MP3Decoder.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 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 MP3_DECODER_H_ + +#define MP3_DECODER_H_ + +#include <media/stagefright/MediaSource.h> + +struct tPVMP3DecoderExternal; + +namespace android { + +struct MediaBufferGroup; + +struct MP3Decoder : public MediaSource { + MP3Decoder(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 ~MP3Decoder(); + +private: + sp<MediaSource> mSource; + sp<MetaData> mMeta; + int32_t mNumChannels; + + bool mStarted; + + MediaBufferGroup *mBufferGroup; + + tPVMP3DecoderExternal *mConfig; + void *mDecoderBuf; + int64_t mAnchorTimeUs; + int64_t mNumFramesOutput; + uint32_t mFixedHeader; + + MediaBuffer *mInputBuffer; + MediaBuffer *mPartialBuffer; + + void init(); + + MP3Decoder(const MP3Decoder &); + MP3Decoder &operator=(const MP3Decoder &); + status_t updatePartialFrame(); +}; + +} // namespace android + +#endif // MP3_DECODER_H_ diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index bd9421c..c2b97d8 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -13,6 +13,10 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) +ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf) +LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO +endif + LOCAL_SRC_FILES:= \ AudioFlinger.cpp \ AudioMixer.cpp.arm \ diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 12cfe9d..d260074 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1204,7 +1204,15 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& if (desc != NULL) { ALOGV("setParameters for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc); desc->stream->common.set_parameters(&desc->stream->common, keyValuePairs.string()); - return NO_ERROR; + AudioParameter param = AudioParameter(keyValuePairs); + String8 key = String8(AudioParameter::keyRouting); + int device; + if (param.getInt(key, device) == NO_ERROR) { + if(mLPAEffectChain != NULL){ + mLPAEffectChain->setDevice_l(device); + audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL); + } + } } } #endif @@ -6169,9 +6177,12 @@ AudioFlinger::DirectAudioTrack::~DirectAudioTrack() { AudioSystem::releaseOutput(mOutput); releaseWakeLock(); - if (mPowerManager != 0) { - sp<IBinder> binder = mPowerManager->asBinder(); - binder->unlinkToDeath(mDeathRecipient); + { + Mutex::Autolock _l(pmLock); + if (mPowerManager != 0) { + sp<IBinder> binder = mPowerManager->asBinder(); + binder->unlinkToDeath(mDeathRecipient); + } } } @@ -6234,8 +6245,8 @@ void AudioFlinger::DirectAudioTrack::mute(bool muted) { } void AudioFlinger::DirectAudioTrack::setVolume(float left, float right) { - mOutputDesc->mVolumeLeft = 1.0; - mOutputDesc->mVolumeRight = 1.0; + mOutputDesc->mVolumeLeft = left; + mOutputDesc->mVolumeRight = right; } int64_t AudioFlinger::DirectAudioTrack::getTimeStamp() { @@ -6428,8 +6439,8 @@ void AudioFlinger::DirectAudioTrack::releaseWakeLock() void AudioFlinger::DirectAudioTrack::clearPowerManager() { - Mutex::Autolock _l(pmLock); releaseWakeLock(); + Mutex::Autolock _l(pmLock); mPowerManager.clear(); } diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index af169d5..ced0453 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -549,7 +549,11 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) (value == 48000 && devSampleRate == 44100))) { quality = AudioResampler::LOW_QUALITY; } else { +#ifdef QCOM_ENHANCED_AUDIO + quality = AudioResampler::VERY_HIGH_QUALITY; +#else quality = AudioResampler::DEFAULT_QUALITY; +#endif } resampler = AudioResampler::create( format, |