summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/AudioTrack.cpp3
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp1
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp101
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h13
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp19
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h1
-rw-r--r--media/libstagefright/ACodec.cpp57
-rw-r--r--media/libstagefright/MediaCodec.cpp24
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC2.cpp19
-rw-r--r--media/libstagefright/codecs/g711/dec/SoftG711.cpp9
11 files changed, 180 insertions, 69 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e3beba5..8e0704f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2244,6 +2244,9 @@ bool AudioTrack::AudioTrackThread::threadLoop()
return true;
}
}
+ if (exitPending()) {
+ return false;
+ }
nsecs_t ns = mReceiver.processAudioBuffer();
switch (ns) {
case 0:
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 17190fb..cadd691 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1172,6 +1172,7 @@ status_t StagefrightRecorder::checkVideoEncoderCapabilities(
client.interface(),
(mVideoEncoder == VIDEO_ENCODER_H263 ? MEDIA_MIMETYPE_VIDEO_H263 :
mVideoEncoder == VIDEO_ENCODER_MPEG_4_SP ? MEDIA_MIMETYPE_VIDEO_MPEG4 :
+ mVideoEncoder == VIDEO_ENCODER_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 :
mVideoEncoder == VIDEO_ENCODER_H264 ? MEDIA_MIMETYPE_VIDEO_AVC : ""),
false /* decoder */, true /* hwCodec */, &codecs);
*supportsCameraSourceMetaDataMode = codecs.size() > 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 53eec91..1c73995 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -174,6 +174,7 @@ NuPlayer::NuPlayer()
mNumFramesDropped(0ll),
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
mStarted(false) {
+ clearFlushComplete();
}
NuPlayer::~NuPlayer() {
@@ -333,25 +334,6 @@ void NuPlayer::seekToAsync(int64_t seekTimeUs, bool needNotify) {
msg->post();
}
-// static
-bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) {
- switch (state) {
- case FLUSHING_DECODER:
- if (needShutdown != NULL) {
- *needShutdown = false;
- }
- return true;
-
- case FLUSHING_DECODER_SHUTDOWN:
- if (needShutdown != NULL) {
- *needShutdown = true;
- }
- return true;
-
- default:
- return false;
- }
-}
void NuPlayer::writeTrackInfo(
Parcel* reply, const sp<AMessage> format) const {
@@ -773,38 +755,9 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
mRenderer->queueEOS(audio, err);
} else if (what == Decoder::kWhatFlushCompleted) {
- bool needShutdown;
-
- if (audio) {
- CHECK(IsFlushingState(mFlushingAudio, &needShutdown));
- mFlushingAudio = FLUSHED;
- } else {
- CHECK(IsFlushingState(mFlushingVideo, &needShutdown));
- mFlushingVideo = FLUSHED;
-
- mVideoLateByUs = 0;
- }
-
ALOGV("decoder %s flush completed", audio ? "audio" : "video");
- if (needShutdown) {
- ALOGV("initiating %s decoder shutdown",
- audio ? "audio" : "video");
-
- // Widevine source reads must stop before releasing the video decoder.
- if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
- mSource->stop();
- }
-
- getDecoder(audio)->initiateShutdown();
-
- if (audio) {
- mFlushingAudio = SHUTTING_DOWN_DECODER;
- } else {
- mFlushingVideo = SHUTTING_DOWN_DECODER;
- }
- }
-
+ handleFlushComplete(audio, true /* isDecoder */);
finishFlushIfPossible();
} else if (what == Decoder::kWhatOutputFormatChanged) {
sp<AMessage> format;
@@ -957,6 +910,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
CHECK(msg->findInt32("audio", &audio));
ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
+ handleFlushComplete(audio, false /* isDecoder */);
+ finishFlushIfPossible();
} else if (what == Renderer::kWhatVideoRenderingStart) {
notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
} else if (what == Renderer::kWhatMediaRenderingStart) {
@@ -1084,6 +1039,50 @@ bool NuPlayer::audioDecoderStillNeeded() {
return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER));
}
+void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) {
+ // We wait for both the decoder flush and the renderer flush to complete
+ // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state.
+
+ mFlushComplete[audio][isDecoder] = true;
+ if (!mFlushComplete[audio][!isDecoder]) {
+ return;
+ }
+
+ FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo;
+ switch (*state) {
+ case FLUSHING_DECODER:
+ {
+ *state = FLUSHED;
+
+ if (!audio) {
+ mVideoLateByUs = 0;
+ }
+ break;
+ }
+
+ case FLUSHING_DECODER_SHUTDOWN:
+ {
+ *state = SHUTTING_DOWN_DECODER;
+
+ ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
+ if (!audio) {
+ mVideoLateByUs = 0;
+ // Widevine source reads must stop before releasing the video decoder.
+ if (mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
+ mSource->stop();
+ }
+ }
+ getDecoder(audio)->initiateShutdown();
+ break;
+ }
+
+ default:
+ // decoder flush completes only occur in a flushing state.
+ LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state);
+ break;
+ }
+}
+
void NuPlayer::finishFlushIfPossible() {
if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
&& mFlushingAudio != SHUT_DOWN) {
@@ -1116,6 +1115,8 @@ void NuPlayer::finishFlushIfPossible() {
mFlushingAudio = NONE;
mFlushingVideo = NONE;
+ clearFlushComplete();
+
processDeferredActions();
}
@@ -1720,6 +1721,8 @@ void NuPlayer::flushDecoder(
FlushStatus newStatus =
needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
+ mFlushComplete[audio][false /* isDecoder */] = false;
+ mFlushComplete[audio][true /* isDecoder */] = false;
if (audio) {
ALOGE_IF(mFlushingAudio != NONE,
"audio flushDecoder() is called in state %d", mFlushingAudio);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 8157733..1b9a756 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -164,6 +164,9 @@ private:
// notion of time has changed.
bool mTimeDiscontinuityPending;
+ // Status of flush responses from the decoder and renderer.
+ bool mFlushComplete[2][2];
+
// Used by feedDecoderInputData to aggregate small buffers into
// one large buffer.
sp<ABuffer> mPendingAudioAccessUnit;
@@ -187,6 +190,13 @@ private:
return audio ? mAudioDecoder : mVideoDecoder;
}
+ inline void clearFlushComplete() {
+ mFlushComplete[0][0] = false;
+ mFlushComplete[0][1] = false;
+ mFlushComplete[1][0] = false;
+ mFlushComplete[1][1] = false;
+ }
+
void openAudioSink(const sp<AMessage> &format, bool offloadOnly);
void closeAudioSink();
@@ -201,6 +211,7 @@ private:
void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
+ void handleFlushComplete(bool audio, bool isDecoder);
void finishFlushIfPossible();
bool audioDecoderStillNeeded();
@@ -209,8 +220,6 @@ private:
bool audio, bool needShutdown, const sp<AMessage> &newFormat = NULL);
void updateDecoderFormatWithoutFlush(bool audio, const sp<AMessage> &format);
- static bool IsFlushingState(FlushStatus state, bool *needShutdown = NULL);
-
void postScanSources();
void schedulePollDuration();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 776fd92..63c4fce 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -582,7 +582,7 @@ status_t NuPlayerDriver::getMetadata(
}
void NuPlayerDriver::notifyResetComplete() {
- ALOGI("notifyResetComplete(%p)", this);
+ ALOGD("notifyResetComplete(%p)", this);
Mutex::Autolock autoLock(mLock);
CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index d6bf1de..e5c64f6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -72,6 +72,7 @@ NuPlayer::Renderer::Renderer(
mHasVideo(false),
mSyncQueues(false),
mPaused(false),
+ mPauseStartedTimeRealUs(-1),
mVideoSampleReceived(false),
mVideoRenderingStarted(false),
mVideoRenderingStartGeneration(0),
@@ -574,7 +575,9 @@ void NuPlayer::Renderer::postDrainVideoQueue() {
if (!mHasAudio) {
mAnchorTimeMediaUs = mediaTimeUs;
mAnchorTimeRealUs = nowUs;
- notifyPosition();
+ if (!mPaused || mVideoSampleReceived) {
+ notifyPosition();
+ }
}
realTimeUs = nowUs;
} else {
@@ -645,6 +648,10 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
}
} else {
mVideoLateByUs = 0ll;
+ if (!mHasAudio && !mVideoSampleReceived) {
+ mAnchorTimeMediaUs = -1;
+ mAnchorTimeRealUs = -1;
+ }
}
entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll);
@@ -830,6 +837,9 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
{
Mutex::Autolock autoLock(mLock);
syncQueuesDone_l();
+ if (!mHasAudio) {
+ mPauseStartedTimeRealUs = -1;
+ }
}
ALOGV("flushing %s", audio ? "audio" : "video");
@@ -980,6 +990,9 @@ void NuPlayer::Renderer::onPause() {
++mVideoQueueGeneration;
prepareForMediaRenderingStart();
mPaused = true;
+ if (!mHasAudio) {
+ mPauseStartedTimeRealUs = ALooper::GetNowUs();
+ }
}
mDrainAudioQueuePending = false;
@@ -1008,6 +1021,10 @@ void NuPlayer::Renderer::onResume() {
Mutex::Autolock autoLock(mLock);
mPaused = false;
+ if (!mHasAudio && mPauseStartedTimeRealUs != -1) {
+ mAnchorTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeRealUs;
+ mPauseStartedTimeRealUs = -1;
+ }
if (!mAudioQueue.empty()) {
postDrainAudioQueue_l();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 4237902..d27c238 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -130,6 +130,7 @@ private:
bool mSyncQueues;
bool mPaused;
+ int64_t mPauseStartedTimeRealUs;
bool mVideoSampleReceived;
bool mVideoRenderingStarted;
int32_t mVideoRenderingStartGeneration;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b6ac2a0..9b11ded 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -421,7 +421,8 @@ ACodec::ACodec()
mMaxPtsGapUs(-1ll),
mTimePerFrameUs(-1ll),
mTimePerCaptureUs(-1ll),
- mCreateInputBuffersSuspended(false) {
+ mCreateInputBuffersSuspended(false),
+ mTunneled(false) {
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
@@ -697,6 +698,21 @@ status_t ACodec::configureOutputBuffersFromNativeWindow(
return err;
}
+ // Exits here for tunneled video playback codecs -- i.e. skips native window
+ // buffer allocation step as this is managed by the tunneled OMX omponent
+ // itself and explicitly sets def.nBufferCountActual to 0.
+ if (mTunneled) {
+ ALOGV("Tunneled Playback: skipping native window buffer allocation.");
+ def.nBufferCountActual = 0;
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ *minUndequeuedBuffers = 0;
+ *bufferCount = 0;
+ *bufferSize = 0;
+ return err;
+ }
+
*minUndequeuedBuffers = 0;
err = mNativeWindow->query(
mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -904,6 +920,13 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
ANativeWindowBuffer *buf;
int fenceFd = -1;
CHECK(mNativeWindow.get() != NULL);
+
+ if (mTunneled) {
+ ALOGW("dequeueBufferFromNativeWindow() should not be called in tunnel"
+ " video playback mode mode!");
+ return NULL;
+ }
+
if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) {
ALOGE("dequeueBuffer failed.");
return NULL;
@@ -1245,6 +1268,7 @@ status_t ACodec::configureCodec(
if (msg->findInt32("feature-tunneled-playback", &tunneled) &&
tunneled != 0) {
ALOGI("Configuring TUNNELED video playback.");
+ mTunneled = true;
int32_t audioHwSync = 0;
if (!msg->findInt32("audio-hw-sync", &audioHwSync)) {
@@ -1259,6 +1283,9 @@ status_t ACodec::configureCodec(
inputFormat->setInt32("adaptive-playback", true);
} else {
+ ALOGV("Configuring CPU controlled video playback.");
+ mTunneled = false;
+
// Always try to enable dynamic output buffers on native surface
err = mOMX->storeMetaDataInBuffers(
mNode, kPortIndexOutput, OMX_TRUE);
@@ -3431,6 +3458,32 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
break;
}
+ case OMX_AUDIO_CodingG711:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE params;
+ InitOMXParams(&params);
+ params.nPortIndex = portIndex;
+
+ CHECK_EQ((status_t)OK, mOMX->getParameter(
+ mNode,
+ (OMX_INDEXTYPE)OMX_IndexParamAudioPcm,
+ &params,
+ sizeof(params)));
+
+ const char *mime = NULL;
+ if (params.ePCMMode == OMX_AUDIO_PCMModeMULaw) {
+ mime = MEDIA_MIMETYPE_AUDIO_G711_MLAW;
+ } else if (params.ePCMMode == OMX_AUDIO_PCMModeALaw) {
+ mime = MEDIA_MIMETYPE_AUDIO_G711_ALAW;
+ } else { // params.ePCMMode == OMX_AUDIO_PCMModeLinear
+ mime = MEDIA_MIMETYPE_AUDIO_RAW;
+ }
+ notify->setString("mime", mime);
+ notify->setInt32("channel-count", params.nChannels);
+ notify->setInt32("sample-rate", params.nSamplingRate);
+ break;
+ }
+
default:
ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding);
TRESPASS();
@@ -4551,6 +4604,8 @@ void ACodec::LoadedState::stateEntered() {
onShutdown(keepComponentAllocated);
}
mCodec->mExplicitShutdown = false;
+
+ mCodec->processDeferredMessages();
}
void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b568063..5f55484 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -780,7 +780,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
// STOPPING->UNINITIALIZED, instead of the
// usual STOPPING->INITIALIZED state.
setState(UNINITIALIZED);
-
+ if (mState == RELEASING) {
+ mComponentName.clear();
+ }
(new AMessage)->postReply(mReplyID);
}
break;
@@ -1046,7 +1048,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
}
if (mFlags & kFlagIsAsync) {
- onInputBufferAvailable();
+ if (!mHaveInputSurface) {
+ onInputBufferAvailable();
+ }
} else if (mFlags & kFlagDequeueInputPending) {
CHECK(handleDequeueInputBuffer(mDequeueInputReplyID));
@@ -1130,6 +1134,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
} else {
CHECK_EQ(mState, RELEASING);
setState(UNINITIALIZED);
+ mComponentName.clear();
}
(new AMessage)->postReply(mReplyID);
@@ -1339,12 +1344,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
// after stop() returned, it would be safe to call release()
// and it should be in this case, no harm to allow a release()
// if we're already uninitialized.
- // Similarly stopping a stopped MediaCodec should be benign.
sp<AMessage> response = new AMessage;
- response->setInt32(
- "err",
- mState == targetState ? OK : INVALID_OPERATION);
-
+ status_t err = mState == targetState ? OK : INVALID_OPERATION;
+ response->setInt32("err", err);
+ if (err == OK && targetState == UNINITIALIZED) {
+ mComponentName.clear();
+ }
response->postReply(replyID);
break;
}
@@ -1353,6 +1358,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
// It's dead, Jim. Don't expect initiateShutdown to yield
// any useful results now...
setState(UNINITIALIZED);
+ if (targetState == UNINITIALIZED) {
+ mComponentName.clear();
+ }
(new AMessage)->postReply(replyID);
break;
}
@@ -1745,8 +1753,6 @@ void MediaCodec::setState(State newState) {
// return any straggling buffers, e.g. if we got here on an error
returnBuffersToCodec();
- mComponentName.clear();
-
// The component is gone, mediaserver's probably back up already
// but should definitely be back up should we try to instantiate
// another component.. and the cycle continues.
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 1b6eac4..40925fd 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -654,6 +654,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
inHeader->nOffset += inBufferUsedLength;
AAC_DECODER_ERROR decoderErr;
+ int numLoops = 0;
do {
if (outputDelayRingBufferSpaceLeft() <
(mStreamInfo->frameSize * mStreamInfo->numChannels)) {
@@ -661,20 +662,19 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
break;
}
- int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes;
+ int numConsumed = mStreamInfo->numTotalBytes;
decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
tmpOutBuffer,
2048 * MAX_CHANNEL_COUNT,
0 /* flags */);
- numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed;
- if (numconsumed != 0) {
- mDecodedSizes.add(numconsumed);
- }
+ numConsumed = mStreamInfo->numTotalBytes - numConsumed;
+ numLoops++;
if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
break;
}
+ mDecodedSizes.add(numConsumed);
if (decoderErr != AAC_DEC_OK) {
ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
@@ -716,6 +716,15 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+ // After an error, replace the last entry in mBufferSizes with the sum of the
+ // last <numLoops> entries from mDecodedSizes to resynchronize the in/out lists.
+ mBufferSizes.pop();
+ int n = 0;
+ for (int i = 0; i < numLoops; i++) {
+ n += mDecodedSizes.itemAt(mDecodedSizes.size() - numLoops + i);
+ }
+ mBufferSizes.add(n);
+
// fall through
}
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index 240c0c1..3a69095 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -117,7 +117,14 @@ OMX_ERRORTYPE SoftG711::internalGetParameter(
pcmParams->eEndian = OMX_EndianBig;
pcmParams->bInterleaved = OMX_TRUE;
pcmParams->nBitPerSample = 16;
- pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ if (pcmParams->nPortIndex == 0) {
+ // input port
+ pcmParams->ePCMMode = mIsMLaw ? OMX_AUDIO_PCMModeMULaw
+ : OMX_AUDIO_PCMModeALaw;
+ } else {
+ // output port
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ }
pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;