summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/stagefright/AudioSource.h1
-rwxr-xr-xinclude/media/stagefright/LPAPlayer.h5
-rw-r--r--include/media/stagefright/MediaDebug.h40
-rw-r--r--media/libmedia/AudioRecord.cpp7
-rw-r--r--media/libmedia/AudioTrack.cpp15
-rw-r--r--media/libstagefright/ACodec.cpp4
-rwxr-xr-xmedia/libstagefright/Android.mk2
-rw-r--r--media/libstagefright/AudioSource.cpp17
-rw-r--r--media/libstagefright/AwesomePlayer.cpp60
-rw-r--r--media/libstagefright/LPAPlayerALSA.cpp68
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp15
-rw-r--r--media/libstagefright/MediaExtractor.cpp9
-rw-r--r--media/libstagefright/OMXCodec.cpp56
-rw-r--r--media/libstagefright/TunnelPlayer.cpp17
-rw-r--r--media/libstagefright/codecs/mp3dec/Android.mk61
-rw-r--r--media/libstagefright/codecs/mp3dec/MP3Decoder.cpp586
-rw-r--r--media/libstagefright/include/AwesomePlayer.h2
-rw-r--r--media/libstagefright/include/MP3Decoder.h70
-rw-r--r--services/audioflinger/Android.mk4
-rw-r--r--services/audioflinger/AudioFlinger.cpp25
-rw-r--r--services/audioflinger/AudioMixer.cpp4
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,